1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 27ccf4f90SNamhyung Kim #include <stdio.h> 38e99b6d4SArnaldo Carvalho de Melo #include <linux/string.h> 47ccf4f90SNamhyung Kim 5*b10ba7f1SArnaldo Carvalho de Melo #include "../../util/callchain.h" 67ccf4f90SNamhyung Kim #include "../../util/util.h" 77ccf4f90SNamhyung Kim #include "../../util/hist.h" 87b644f9aSArnaldo Carvalho de Melo #include "../../util/map.h" 941f30914SArnaldo Carvalho de Melo #include "../../util/map_groups.h" 10daecf9e0SArnaldo Carvalho de Melo #include "../../util/symbol.h" 117ccf4f90SNamhyung Kim #include "../../util/sort.h" 125b9e2146SNamhyung Kim #include "../../util/evsel.h" 13632a5cabSArnaldo Carvalho de Melo #include "../../util/srcline.h" 14a067558eSArnaldo Carvalho de Melo #include "../../util/string2.h" 15e7ff8920SArnaldo Carvalho de Melo #include "../../util/thread.h" 163d689ed6SArnaldo Carvalho de Melo #include "../../util/sane_ctype.h" 177ccf4f90SNamhyung Kim 187ccf4f90SNamhyung Kim static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin) 197ccf4f90SNamhyung Kim { 207ccf4f90SNamhyung Kim int i; 217ccf4f90SNamhyung Kim int ret = fprintf(fp, " "); 227ccf4f90SNamhyung Kim 237ccf4f90SNamhyung Kim for (i = 0; i < left_margin; i++) 247ccf4f90SNamhyung Kim ret += fprintf(fp, " "); 257ccf4f90SNamhyung Kim 267ccf4f90SNamhyung Kim return ret; 277ccf4f90SNamhyung Kim } 287ccf4f90SNamhyung Kim 297ccf4f90SNamhyung Kim static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask, 307ccf4f90SNamhyung Kim int left_margin) 317ccf4f90SNamhyung Kim { 327ccf4f90SNamhyung Kim int i; 337ccf4f90SNamhyung Kim size_t ret = callchain__fprintf_left_margin(fp, left_margin); 347ccf4f90SNamhyung Kim 357ccf4f90SNamhyung Kim for (i = 0; i < depth; i++) 367ccf4f90SNamhyung Kim if (depth_mask & (1 << i)) 377ccf4f90SNamhyung Kim ret += fprintf(fp, "| "); 387ccf4f90SNamhyung Kim else 397ccf4f90SNamhyung Kim ret += fprintf(fp, " "); 407ccf4f90SNamhyung Kim 417ccf4f90SNamhyung Kim ret += fprintf(fp, "\n"); 427ccf4f90SNamhyung Kim 437ccf4f90SNamhyung Kim return ret; 447ccf4f90SNamhyung Kim } 457ccf4f90SNamhyung Kim 465ab250caSNamhyung Kim static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_node *node, 475ab250caSNamhyung Kim struct callchain_list *chain, 487ccf4f90SNamhyung Kim int depth, int depth_mask, int period, 495ab250caSNamhyung Kim u64 total_samples, int left_margin) 507ccf4f90SNamhyung Kim { 517ccf4f90SNamhyung Kim int i; 527ccf4f90SNamhyung Kim size_t ret = 0; 538577ae6bSJin Yao char bf[1024], *alloc_str = NULL; 548577ae6bSJin Yao char buf[64]; 558577ae6bSJin Yao const char *str; 567ccf4f90SNamhyung Kim 577ccf4f90SNamhyung Kim ret += callchain__fprintf_left_margin(fp, left_margin); 587ccf4f90SNamhyung Kim for (i = 0; i < depth; i++) { 597ccf4f90SNamhyung Kim if (depth_mask & (1 << i)) 607ccf4f90SNamhyung Kim ret += fprintf(fp, "|"); 617ccf4f90SNamhyung Kim else 627ccf4f90SNamhyung Kim ret += fprintf(fp, " "); 637ccf4f90SNamhyung Kim if (!period && i == depth - 1) { 645ab250caSNamhyung Kim ret += fprintf(fp, "--"); 655ab250caSNamhyung Kim ret += callchain_node__fprintf_value(node, fp, total_samples); 665ab250caSNamhyung Kim ret += fprintf(fp, "--"); 677ccf4f90SNamhyung Kim } else 687ccf4f90SNamhyung Kim ret += fprintf(fp, "%s", " "); 697ccf4f90SNamhyung Kim } 708577ae6bSJin Yao 718577ae6bSJin Yao str = callchain_list__sym_name(chain, bf, sizeof(bf), false); 728577ae6bSJin Yao 738577ae6bSJin Yao if (symbol_conf.show_branchflag_count) { 74c4ee0625SJin Yao callchain_list_counts__printf_value(chain, NULL, 758577ae6bSJin Yao buf, sizeof(buf)); 768577ae6bSJin Yao 778577ae6bSJin Yao if (asprintf(&alloc_str, "%s%s", str, buf) < 0) 788577ae6bSJin Yao str = "Not enough memory!"; 798577ae6bSJin Yao else 808577ae6bSJin Yao str = alloc_str; 818577ae6bSJin Yao } 828577ae6bSJin Yao 838577ae6bSJin Yao fputs(str, fp); 842989ccaaSAndi Kleen fputc('\n', fp); 858577ae6bSJin Yao free(alloc_str); 860db64dd0SJin Yao 877ccf4f90SNamhyung Kim return ret; 887ccf4f90SNamhyung Kim } 897ccf4f90SNamhyung Kim 907ccf4f90SNamhyung Kim static struct symbol *rem_sq_bracket; 917ccf4f90SNamhyung Kim static struct callchain_list rem_hits; 927ccf4f90SNamhyung Kim 937ccf4f90SNamhyung Kim static void init_rem_hits(void) 947ccf4f90SNamhyung Kim { 957ccf4f90SNamhyung Kim rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6); 967ccf4f90SNamhyung Kim if (!rem_sq_bracket) { 977ccf4f90SNamhyung Kim fprintf(stderr, "Not enough memory to display remaining hits\n"); 987ccf4f90SNamhyung Kim return; 997ccf4f90SNamhyung Kim } 1007ccf4f90SNamhyung Kim 1017ccf4f90SNamhyung Kim strcpy(rem_sq_bracket->name, "[...]"); 1027ccf4f90SNamhyung Kim rem_hits.ms.sym = rem_sq_bracket; 1037ccf4f90SNamhyung Kim } 1047ccf4f90SNamhyung Kim 1057ccf4f90SNamhyung Kim static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root, 1067ccf4f90SNamhyung Kim u64 total_samples, int depth, 1077ccf4f90SNamhyung Kim int depth_mask, int left_margin) 1087ccf4f90SNamhyung Kim { 1097ccf4f90SNamhyung Kim struct rb_node *node, *next; 110f2af0086SNamhyung Kim struct callchain_node *child = NULL; 1117ccf4f90SNamhyung Kim struct callchain_list *chain; 1127ccf4f90SNamhyung Kim int new_depth_mask = depth_mask; 1137ccf4f90SNamhyung Kim u64 remaining; 1147ccf4f90SNamhyung Kim size_t ret = 0; 1157ccf4f90SNamhyung Kim int i; 1167ccf4f90SNamhyung Kim uint entries_printed = 0; 117f2af0086SNamhyung Kim int cumul_count = 0; 1187ccf4f90SNamhyung Kim 1197ccf4f90SNamhyung Kim remaining = total_samples; 1207ccf4f90SNamhyung Kim 1217ccf4f90SNamhyung Kim node = rb_first(root); 1227ccf4f90SNamhyung Kim while (node) { 1237ccf4f90SNamhyung Kim u64 new_total; 1247ccf4f90SNamhyung Kim u64 cumul; 1257ccf4f90SNamhyung Kim 1267ccf4f90SNamhyung Kim child = rb_entry(node, struct callchain_node, rb_node); 1277ccf4f90SNamhyung Kim cumul = callchain_cumul_hits(child); 1287ccf4f90SNamhyung Kim remaining -= cumul; 129f2af0086SNamhyung Kim cumul_count += callchain_cumul_counts(child); 1307ccf4f90SNamhyung Kim 1317ccf4f90SNamhyung Kim /* 1327ccf4f90SNamhyung Kim * The depth mask manages the output of pipes that show 1337ccf4f90SNamhyung Kim * the depth. We don't want to keep the pipes of the current 1347ccf4f90SNamhyung Kim * level for the last child of this depth. 1357ccf4f90SNamhyung Kim * Except if we have remaining filtered hits. They will 1367ccf4f90SNamhyung Kim * supersede the last child 1377ccf4f90SNamhyung Kim */ 1387ccf4f90SNamhyung Kim next = rb_next(node); 1397ccf4f90SNamhyung Kim if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining)) 1407ccf4f90SNamhyung Kim new_depth_mask &= ~(1 << (depth - 1)); 1417ccf4f90SNamhyung Kim 1427ccf4f90SNamhyung Kim /* 1437ccf4f90SNamhyung Kim * But we keep the older depth mask for the line separator 1447ccf4f90SNamhyung Kim * to keep the level link until we reach the last child 1457ccf4f90SNamhyung Kim */ 1467ccf4f90SNamhyung Kim ret += ipchain__fprintf_graph_line(fp, depth, depth_mask, 1477ccf4f90SNamhyung Kim left_margin); 1487ccf4f90SNamhyung Kim i = 0; 1497ccf4f90SNamhyung Kim list_for_each_entry(chain, &child->val, list) { 1505ab250caSNamhyung Kim ret += ipchain__fprintf_graph(fp, child, chain, depth, 1517ccf4f90SNamhyung Kim new_depth_mask, i++, 1527ccf4f90SNamhyung Kim total_samples, 1537ccf4f90SNamhyung Kim left_margin); 1547ccf4f90SNamhyung Kim } 1557ccf4f90SNamhyung Kim 1567ccf4f90SNamhyung Kim if (callchain_param.mode == CHAIN_GRAPH_REL) 1577ccf4f90SNamhyung Kim new_total = child->children_hit; 1587ccf4f90SNamhyung Kim else 1597ccf4f90SNamhyung Kim new_total = total_samples; 1607ccf4f90SNamhyung Kim 1617ccf4f90SNamhyung Kim ret += __callchain__fprintf_graph(fp, &child->rb_root, new_total, 1627ccf4f90SNamhyung Kim depth + 1, 1637ccf4f90SNamhyung Kim new_depth_mask | (1 << depth), 1647ccf4f90SNamhyung Kim left_margin); 1657ccf4f90SNamhyung Kim node = next; 1667ccf4f90SNamhyung Kim if (++entries_printed == callchain_param.print_limit) 1677ccf4f90SNamhyung Kim break; 1687ccf4f90SNamhyung Kim } 1697ccf4f90SNamhyung Kim 1707ccf4f90SNamhyung Kim if (callchain_param.mode == CHAIN_GRAPH_REL && 1717ccf4f90SNamhyung Kim remaining && remaining != total_samples) { 1725ab250caSNamhyung Kim struct callchain_node rem_node = { 1735ab250caSNamhyung Kim .hit = remaining, 1745ab250caSNamhyung Kim }; 1757ccf4f90SNamhyung Kim 1767ccf4f90SNamhyung Kim if (!rem_sq_bracket) 1777ccf4f90SNamhyung Kim return ret; 1787ccf4f90SNamhyung Kim 179f2af0086SNamhyung Kim if (callchain_param.value == CCVAL_COUNT && child && child->parent) { 180f2af0086SNamhyung Kim rem_node.count = child->parent->children_count - cumul_count; 181f2af0086SNamhyung Kim if (rem_node.count <= 0) 182f2af0086SNamhyung Kim return ret; 183f2af0086SNamhyung Kim } 184f2af0086SNamhyung Kim 1857ccf4f90SNamhyung Kim new_depth_mask &= ~(1 << (depth - 1)); 1865ab250caSNamhyung Kim ret += ipchain__fprintf_graph(fp, &rem_node, &rem_hits, depth, 1877ccf4f90SNamhyung Kim new_depth_mask, 0, total_samples, 1885ab250caSNamhyung Kim left_margin); 1897ccf4f90SNamhyung Kim } 1907ccf4f90SNamhyung Kim 1917ccf4f90SNamhyung Kim return ret; 1927ccf4f90SNamhyung Kim } 1937ccf4f90SNamhyung Kim 1947ed5d6e2SNamhyung Kim /* 1957ed5d6e2SNamhyung Kim * If have one single callchain root, don't bother printing 1967ed5d6e2SNamhyung Kim * its percentage (100 % in fractal mode and the same percentage 1977ed5d6e2SNamhyung Kim * than the hist in graph mode). This also avoid one level of column. 1987ed5d6e2SNamhyung Kim * 1997ed5d6e2SNamhyung Kim * However when percent-limit applied, it's possible that single callchain 2007ed5d6e2SNamhyung Kim * node have different (non-100% in fractal mode) percentage. 2017ed5d6e2SNamhyung Kim */ 2027ed5d6e2SNamhyung Kim static bool need_percent_display(struct rb_node *node, u64 parent_samples) 2037ed5d6e2SNamhyung Kim { 2047ed5d6e2SNamhyung Kim struct callchain_node *cnode; 2057ed5d6e2SNamhyung Kim 2067ed5d6e2SNamhyung Kim if (rb_next(node)) 2077ed5d6e2SNamhyung Kim return true; 2087ed5d6e2SNamhyung Kim 2097ed5d6e2SNamhyung Kim cnode = rb_entry(node, struct callchain_node, rb_node); 2107ed5d6e2SNamhyung Kim return callchain_cumul_hits(cnode) != parent_samples; 2117ed5d6e2SNamhyung Kim } 2127ed5d6e2SNamhyung Kim 2137ccf4f90SNamhyung Kim static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root, 21454d27b31SNamhyung Kim u64 total_samples, u64 parent_samples, 21554d27b31SNamhyung Kim int left_margin) 2167ccf4f90SNamhyung Kim { 2177ccf4f90SNamhyung Kim struct callchain_node *cnode; 2187ccf4f90SNamhyung Kim struct callchain_list *chain; 2197ccf4f90SNamhyung Kim u32 entries_printed = 0; 2207ccf4f90SNamhyung Kim bool printed = false; 2217ccf4f90SNamhyung Kim struct rb_node *node; 2227ccf4f90SNamhyung Kim int i = 0; 2237ccf4f90SNamhyung Kim int ret = 0; 2242989ccaaSAndi Kleen char bf[1024]; 2257ccf4f90SNamhyung Kim 2267ccf4f90SNamhyung Kim node = rb_first(root); 2277ed5d6e2SNamhyung Kim if (node && !need_percent_display(node, parent_samples)) { 2287ccf4f90SNamhyung Kim cnode = rb_entry(node, struct callchain_node, rb_node); 2297ccf4f90SNamhyung Kim list_for_each_entry(chain, &cnode->val, list) { 2307ccf4f90SNamhyung Kim /* 2317ccf4f90SNamhyung Kim * If we sort by symbol, the first entry is the same than 2327ccf4f90SNamhyung Kim * the symbol. No need to print it otherwise it appears as 2337ccf4f90SNamhyung Kim * displayed twice. 2347ccf4f90SNamhyung Kim */ 235cfaa154bSNamhyung Kim if (!i++ && field_order == NULL && 2368e99b6d4SArnaldo Carvalho de Melo sort_order && strstarts(sort_order, "sym")) 2377ccf4f90SNamhyung Kim continue; 2380db64dd0SJin Yao 2397ccf4f90SNamhyung Kim if (!printed) { 2407ccf4f90SNamhyung Kim ret += callchain__fprintf_left_margin(fp, left_margin); 2417ccf4f90SNamhyung Kim ret += fprintf(fp, "|\n"); 2427ccf4f90SNamhyung Kim ret += callchain__fprintf_left_margin(fp, left_margin); 2437ccf4f90SNamhyung Kim ret += fprintf(fp, "---"); 2447ccf4f90SNamhyung Kim left_margin += 3; 2457ccf4f90SNamhyung Kim printed = true; 2467ccf4f90SNamhyung Kim } else 2477ccf4f90SNamhyung Kim ret += callchain__fprintf_left_margin(fp, left_margin); 2487ccf4f90SNamhyung Kim 2498577ae6bSJin Yao ret += fprintf(fp, "%s", 2508577ae6bSJin Yao callchain_list__sym_name(chain, bf, 2518577ae6bSJin Yao sizeof(bf), 2522989ccaaSAndi Kleen false)); 2537ccf4f90SNamhyung Kim 2548577ae6bSJin Yao if (symbol_conf.show_branchflag_count) 2558577ae6bSJin Yao ret += callchain_list_counts__printf_value( 256c4ee0625SJin Yao chain, fp, NULL, 0); 2578577ae6bSJin Yao ret += fprintf(fp, "\n"); 2588577ae6bSJin Yao 2597ccf4f90SNamhyung Kim if (++entries_printed == callchain_param.print_limit) 2607ccf4f90SNamhyung Kim break; 2617ccf4f90SNamhyung Kim } 2627ccf4f90SNamhyung Kim root = &cnode->rb_root; 2637ccf4f90SNamhyung Kim } 2647ccf4f90SNamhyung Kim 26554d27b31SNamhyung Kim if (callchain_param.mode == CHAIN_GRAPH_REL) 26654d27b31SNamhyung Kim total_samples = parent_samples; 26754d27b31SNamhyung Kim 2687ccf4f90SNamhyung Kim ret += __callchain__fprintf_graph(fp, root, total_samples, 2697ccf4f90SNamhyung Kim 1, 1, left_margin); 2703848c23bSNamhyung Kim if (ret) { 2713848c23bSNamhyung Kim /* do not add a blank line if it printed nothing */ 2727ccf4f90SNamhyung Kim ret += fprintf(fp, "\n"); 2733848c23bSNamhyung Kim } 2747ccf4f90SNamhyung Kim 2757ccf4f90SNamhyung Kim return ret; 2767ccf4f90SNamhyung Kim } 2777ccf4f90SNamhyung Kim 278316c7136SArnaldo Carvalho de Melo static size_t __callchain__fprintf_flat(FILE *fp, struct callchain_node *node, 2797ccf4f90SNamhyung Kim u64 total_samples) 2807ccf4f90SNamhyung Kim { 2817ccf4f90SNamhyung Kim struct callchain_list *chain; 2827ccf4f90SNamhyung Kim size_t ret = 0; 2832989ccaaSAndi Kleen char bf[1024]; 2847ccf4f90SNamhyung Kim 285316c7136SArnaldo Carvalho de Melo if (!node) 2867ccf4f90SNamhyung Kim return 0; 2877ccf4f90SNamhyung Kim 288316c7136SArnaldo Carvalho de Melo ret += __callchain__fprintf_flat(fp, node->parent, total_samples); 2897ccf4f90SNamhyung Kim 2907ccf4f90SNamhyung Kim 291316c7136SArnaldo Carvalho de Melo list_for_each_entry(chain, &node->val, list) { 2927ccf4f90SNamhyung Kim if (chain->ip >= PERF_CONTEXT_MAX) 2937ccf4f90SNamhyung Kim continue; 2942989ccaaSAndi Kleen ret += fprintf(fp, " %s\n", callchain_list__sym_name(chain, 2952989ccaaSAndi Kleen bf, sizeof(bf), false)); 2967ccf4f90SNamhyung Kim } 2977ccf4f90SNamhyung Kim 2987ccf4f90SNamhyung Kim return ret; 2997ccf4f90SNamhyung Kim } 3007ccf4f90SNamhyung Kim 301316c7136SArnaldo Carvalho de Melo static size_t callchain__fprintf_flat(FILE *fp, struct rb_root *tree, 3027ccf4f90SNamhyung Kim u64 total_samples) 3037ccf4f90SNamhyung Kim { 3047ccf4f90SNamhyung Kim size_t ret = 0; 3057ccf4f90SNamhyung Kim u32 entries_printed = 0; 3067ccf4f90SNamhyung Kim struct callchain_node *chain; 307316c7136SArnaldo Carvalho de Melo struct rb_node *rb_node = rb_first(tree); 3087ccf4f90SNamhyung Kim 3097ccf4f90SNamhyung Kim while (rb_node) { 3107ccf4f90SNamhyung Kim chain = rb_entry(rb_node, struct callchain_node, rb_node); 3117ccf4f90SNamhyung Kim 3125ab250caSNamhyung Kim ret += fprintf(fp, " "); 3135ab250caSNamhyung Kim ret += callchain_node__fprintf_value(chain, fp, total_samples); 3145ab250caSNamhyung Kim ret += fprintf(fp, "\n"); 3157ccf4f90SNamhyung Kim ret += __callchain__fprintf_flat(fp, chain, total_samples); 3167ccf4f90SNamhyung Kim ret += fprintf(fp, "\n"); 3177ccf4f90SNamhyung Kim if (++entries_printed == callchain_param.print_limit) 3187ccf4f90SNamhyung Kim break; 3197ccf4f90SNamhyung Kim 3207ccf4f90SNamhyung Kim rb_node = rb_next(rb_node); 3217ccf4f90SNamhyung Kim } 3227ccf4f90SNamhyung Kim 3237ccf4f90SNamhyung Kim return ret; 3247ccf4f90SNamhyung Kim } 3257ccf4f90SNamhyung Kim 32626e77924SNamhyung Kim static size_t __callchain__fprintf_folded(FILE *fp, struct callchain_node *node) 32726e77924SNamhyung Kim { 32826e77924SNamhyung Kim const char *sep = symbol_conf.field_sep ?: ";"; 32926e77924SNamhyung Kim struct callchain_list *chain; 33026e77924SNamhyung Kim size_t ret = 0; 33126e77924SNamhyung Kim char bf[1024]; 33226e77924SNamhyung Kim bool first; 33326e77924SNamhyung Kim 33426e77924SNamhyung Kim if (!node) 33526e77924SNamhyung Kim return 0; 33626e77924SNamhyung Kim 33726e77924SNamhyung Kim ret += __callchain__fprintf_folded(fp, node->parent); 33826e77924SNamhyung Kim 33926e77924SNamhyung Kim first = (ret == 0); 34026e77924SNamhyung Kim list_for_each_entry(chain, &node->val, list) { 34126e77924SNamhyung Kim if (chain->ip >= PERF_CONTEXT_MAX) 34226e77924SNamhyung Kim continue; 34326e77924SNamhyung Kim ret += fprintf(fp, "%s%s", first ? "" : sep, 34426e77924SNamhyung Kim callchain_list__sym_name(chain, 34526e77924SNamhyung Kim bf, sizeof(bf), false)); 34626e77924SNamhyung Kim first = false; 34726e77924SNamhyung Kim } 34826e77924SNamhyung Kim 34926e77924SNamhyung Kim return ret; 35026e77924SNamhyung Kim } 35126e77924SNamhyung Kim 35226e77924SNamhyung Kim static size_t callchain__fprintf_folded(FILE *fp, struct rb_root *tree, 35326e77924SNamhyung Kim u64 total_samples) 35426e77924SNamhyung Kim { 35526e77924SNamhyung Kim size_t ret = 0; 35626e77924SNamhyung Kim u32 entries_printed = 0; 35726e77924SNamhyung Kim struct callchain_node *chain; 35826e77924SNamhyung Kim struct rb_node *rb_node = rb_first(tree); 35926e77924SNamhyung Kim 36026e77924SNamhyung Kim while (rb_node) { 36126e77924SNamhyung Kim 36226e77924SNamhyung Kim chain = rb_entry(rb_node, struct callchain_node, rb_node); 36326e77924SNamhyung Kim 3645ab250caSNamhyung Kim ret += callchain_node__fprintf_value(chain, fp, total_samples); 3655ab250caSNamhyung Kim ret += fprintf(fp, " "); 36626e77924SNamhyung Kim ret += __callchain__fprintf_folded(fp, chain); 36726e77924SNamhyung Kim ret += fprintf(fp, "\n"); 36826e77924SNamhyung Kim if (++entries_printed == callchain_param.print_limit) 36926e77924SNamhyung Kim break; 37026e77924SNamhyung Kim 37126e77924SNamhyung Kim rb_node = rb_next(rb_node); 37226e77924SNamhyung Kim } 37326e77924SNamhyung Kim 37426e77924SNamhyung Kim return ret; 37526e77924SNamhyung Kim } 37626e77924SNamhyung Kim 3777ccf4f90SNamhyung Kim static size_t hist_entry_callchain__fprintf(struct hist_entry *he, 3787ccf4f90SNamhyung Kim u64 total_samples, int left_margin, 3797ccf4f90SNamhyung Kim FILE *fp) 3807ccf4f90SNamhyung Kim { 38154d27b31SNamhyung Kim u64 parent_samples = he->stat.period; 38254d27b31SNamhyung Kim 38354d27b31SNamhyung Kim if (symbol_conf.cumulate_callchain) 38454d27b31SNamhyung Kim parent_samples = he->stat_acc->period; 38554d27b31SNamhyung Kim 3867ccf4f90SNamhyung Kim switch (callchain_param.mode) { 3877ccf4f90SNamhyung Kim case CHAIN_GRAPH_REL: 38854d27b31SNamhyung Kim return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples, 38954d27b31SNamhyung Kim parent_samples, left_margin); 3907ccf4f90SNamhyung Kim break; 3917ccf4f90SNamhyung Kim case CHAIN_GRAPH_ABS: 3927ccf4f90SNamhyung Kim return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples, 39354d27b31SNamhyung Kim parent_samples, left_margin); 3947ccf4f90SNamhyung Kim break; 3957ccf4f90SNamhyung Kim case CHAIN_FLAT: 3967ccf4f90SNamhyung Kim return callchain__fprintf_flat(fp, &he->sorted_chain, total_samples); 3977ccf4f90SNamhyung Kim break; 39826e77924SNamhyung Kim case CHAIN_FOLDED: 39926e77924SNamhyung Kim return callchain__fprintf_folded(fp, &he->sorted_chain, total_samples); 40026e77924SNamhyung Kim break; 4017ccf4f90SNamhyung Kim case CHAIN_NONE: 4027ccf4f90SNamhyung Kim break; 4037ccf4f90SNamhyung Kim default: 4047ccf4f90SNamhyung Kim pr_err("Bad callchain mode\n"); 4057ccf4f90SNamhyung Kim } 4067ccf4f90SNamhyung Kim 4077ccf4f90SNamhyung Kim return 0; 4087ccf4f90SNamhyung Kim } 4097ccf4f90SNamhyung Kim 410bd28d0c5SJiri Olsa int __hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp, 4119da44db1SJiri Olsa struct perf_hpp_list *hpp_list) 412be0e6d10SJiri Olsa { 413be0e6d10SJiri Olsa const char *sep = symbol_conf.field_sep; 414be0e6d10SJiri Olsa struct perf_hpp_fmt *fmt; 415be0e6d10SJiri Olsa char *start = hpp->buf; 416be0e6d10SJiri Olsa int ret; 417be0e6d10SJiri Olsa bool first = true; 418be0e6d10SJiri Olsa 419be0e6d10SJiri Olsa if (symbol_conf.exclude_other && !he->parent) 420be0e6d10SJiri Olsa return 0; 421be0e6d10SJiri Olsa 4229da44db1SJiri Olsa perf_hpp_list__for_each_format(hpp_list, fmt) { 423361459f1SNamhyung Kim if (perf_hpp__should_skip(fmt, he->hists)) 424e67d49a7SNamhyung Kim continue; 425e67d49a7SNamhyung Kim 426be0e6d10SJiri Olsa /* 427be0e6d10SJiri Olsa * If there's no field_sep, we still need 428be0e6d10SJiri Olsa * to display initial ' '. 429be0e6d10SJiri Olsa */ 430be0e6d10SJiri Olsa if (!sep || !first) { 431be0e6d10SJiri Olsa ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " "); 432be0e6d10SJiri Olsa advance_hpp(hpp, ret); 433be0e6d10SJiri Olsa } else 434be0e6d10SJiri Olsa first = false; 435be0e6d10SJiri Olsa 4369754c4f9SJiri Olsa if (perf_hpp__use_color() && fmt->color) 437be0e6d10SJiri Olsa ret = fmt->color(fmt, hpp, he); 438be0e6d10SJiri Olsa else 439be0e6d10SJiri Olsa ret = fmt->entry(fmt, hpp, he); 440be0e6d10SJiri Olsa 44189fee709SArnaldo Carvalho de Melo ret = hist_entry__snprintf_alignment(he, hpp, fmt, ret); 442be0e6d10SJiri Olsa advance_hpp(hpp, ret); 443be0e6d10SJiri Olsa } 444be0e6d10SJiri Olsa 445be0e6d10SJiri Olsa return hpp->buf - start; 446be0e6d10SJiri Olsa } 447be0e6d10SJiri Olsa 4489da44db1SJiri Olsa static int hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp) 4499da44db1SJiri Olsa { 4509da44db1SJiri Olsa return __hist_entry__snprintf(he, hpp, he->hists->hpp_list); 4519da44db1SJiri Olsa } 4529da44db1SJiri Olsa 453ef86d68aSNamhyung Kim static int hist_entry__hierarchy_fprintf(struct hist_entry *he, 454ef86d68aSNamhyung Kim struct perf_hpp *hpp, 4552dbbe9f2SNamhyung Kim struct hists *hists, 456ef86d68aSNamhyung Kim FILE *fp) 457ef86d68aSNamhyung Kim { 458ef86d68aSNamhyung Kim const char *sep = symbol_conf.field_sep; 459ef86d68aSNamhyung Kim struct perf_hpp_fmt *fmt; 460f58c95e3SNamhyung Kim struct perf_hpp_list_node *fmt_node; 461ef86d68aSNamhyung Kim char *buf = hpp->buf; 462cb1fab91SNamhyung Kim size_t size = hpp->size; 463ef86d68aSNamhyung Kim int ret, printed = 0; 464ef86d68aSNamhyung Kim bool first = true; 465ef86d68aSNamhyung Kim 466ef86d68aSNamhyung Kim if (symbol_conf.exclude_other && !he->parent) 467ef86d68aSNamhyung Kim return 0; 468ef86d68aSNamhyung Kim 469ef86d68aSNamhyung Kim ret = scnprintf(hpp->buf, hpp->size, "%*s", he->depth * HIERARCHY_INDENT, ""); 470ef86d68aSNamhyung Kim advance_hpp(hpp, ret); 471ef86d68aSNamhyung Kim 472f58c95e3SNamhyung Kim /* the first hpp_list_node is for overhead columns */ 473f58c95e3SNamhyung Kim fmt_node = list_first_entry(&hists->hpp_formats, 474f58c95e3SNamhyung Kim struct perf_hpp_list_node, list); 475f58c95e3SNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { 476ef86d68aSNamhyung Kim /* 477ef86d68aSNamhyung Kim * If there's no field_sep, we still need 478ef86d68aSNamhyung Kim * to display initial ' '. 479ef86d68aSNamhyung Kim */ 480ef86d68aSNamhyung Kim if (!sep || !first) { 481ef86d68aSNamhyung Kim ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " "); 482ef86d68aSNamhyung Kim advance_hpp(hpp, ret); 483ef86d68aSNamhyung Kim } else 484ef86d68aSNamhyung Kim first = false; 485ef86d68aSNamhyung Kim 486ef86d68aSNamhyung Kim if (perf_hpp__use_color() && fmt->color) 487ef86d68aSNamhyung Kim ret = fmt->color(fmt, hpp, he); 488ef86d68aSNamhyung Kim else 489ef86d68aSNamhyung Kim ret = fmt->entry(fmt, hpp, he); 490ef86d68aSNamhyung Kim 491ef86d68aSNamhyung Kim ret = hist_entry__snprintf_alignment(he, hpp, fmt, ret); 492ef86d68aSNamhyung Kim advance_hpp(hpp, ret); 493ef86d68aSNamhyung Kim } 494ef86d68aSNamhyung Kim 4951b2dbbf4SNamhyung Kim if (!sep) 496ef86d68aSNamhyung Kim ret = scnprintf(hpp->buf, hpp->size, "%*s", 4972dbbe9f2SNamhyung Kim (hists->nr_hpp_node - 2) * HIERARCHY_INDENT, ""); 498ef86d68aSNamhyung Kim advance_hpp(hpp, ret); 499ef86d68aSNamhyung Kim 500cb1fab91SNamhyung Kim printed += fprintf(fp, "%s", buf); 501cb1fab91SNamhyung Kim 5021b2dbbf4SNamhyung Kim perf_hpp_list__for_each_format(he->hpp_list, fmt) { 503cb1fab91SNamhyung Kim hpp->buf = buf; 504cb1fab91SNamhyung Kim hpp->size = size; 505cb1fab91SNamhyung Kim 506ef86d68aSNamhyung Kim /* 507ef86d68aSNamhyung Kim * No need to call hist_entry__snprintf_alignment() since this 508ef86d68aSNamhyung Kim * fmt is always the last column in the hierarchy mode. 509ef86d68aSNamhyung Kim */ 510ef86d68aSNamhyung Kim if (perf_hpp__use_color() && fmt->color) 511ef86d68aSNamhyung Kim fmt->color(fmt, hpp, he); 512ef86d68aSNamhyung Kim else 513ef86d68aSNamhyung Kim fmt->entry(fmt, hpp, he); 514ef86d68aSNamhyung Kim 515cb1fab91SNamhyung Kim /* 516cb1fab91SNamhyung Kim * dynamic entries are right-aligned but we want left-aligned 517cb1fab91SNamhyung Kim * in the hierarchy mode 518cb1fab91SNamhyung Kim */ 5191b2dbbf4SNamhyung Kim printed += fprintf(fp, "%s%s", sep ?: " ", ltrim(buf)); 5201b2dbbf4SNamhyung Kim } 5211b2dbbf4SNamhyung Kim printed += putc('\n', fp); 522ef86d68aSNamhyung Kim 523fabd37b8SArnaldo Carvalho de Melo if (he->leaf && hist_entry__has_callchains(he) && symbol_conf.use_callchain) { 524ef86d68aSNamhyung Kim u64 total = hists__total_period(hists); 525ef86d68aSNamhyung Kim 526ef86d68aSNamhyung Kim printed += hist_entry_callchain__fprintf(he, total, 0, fp); 527ef86d68aSNamhyung Kim goto out; 528ef86d68aSNamhyung Kim } 529ef86d68aSNamhyung Kim 530ef86d68aSNamhyung Kim out: 531ef86d68aSNamhyung Kim return printed; 532ef86d68aSNamhyung Kim } 533ef86d68aSNamhyung Kim 534000078bcSNamhyung Kim static int hist_entry__fprintf(struct hist_entry *he, size_t size, 535d05e3aaeSJiri Olsa char *bf, size_t bfsz, FILE *fp, 536e9de7e2fSArnaldo Carvalho de Melo bool ignore_callchains) 537000078bcSNamhyung Kim { 538000078bcSNamhyung Kim int ret; 5390db64dd0SJin Yao int callchain_ret = 0; 540ea251d51SNamhyung Kim struct perf_hpp hpp = { 541ea251d51SNamhyung Kim .buf = bf, 542ea251d51SNamhyung Kim .size = size, 543ea251d51SNamhyung Kim }; 5448f1d1b44SJiri Olsa struct hists *hists = he->hists; 5457e597d32SNamhyung Kim u64 total_period = hists->stats.total_period; 546000078bcSNamhyung Kim 54799cf666cSArnaldo Carvalho de Melo if (size == 0 || size > bfsz) 54899cf666cSArnaldo Carvalho de Melo size = hpp.size = bfsz; 549000078bcSNamhyung Kim 5502dbbe9f2SNamhyung Kim if (symbol_conf.report_hierarchy) 5512dbbe9f2SNamhyung Kim return hist_entry__hierarchy_fprintf(he, &hpp, hists, fp); 552ef86d68aSNamhyung Kim 55326d8b338SNamhyung Kim hist_entry__snprintf(he, &hpp); 554000078bcSNamhyung Kim 555000078bcSNamhyung Kim ret = fprintf(fp, "%s\n", bf); 556000078bcSNamhyung Kim 557e9de7e2fSArnaldo Carvalho de Melo if (hist_entry__has_callchains(he) && !ignore_callchains) 5580db64dd0SJin Yao callchain_ret = hist_entry_callchain__fprintf(he, total_period, 5590db64dd0SJin Yao 0, fp); 5600db64dd0SJin Yao 5610db64dd0SJin Yao ret += callchain_ret; 562000078bcSNamhyung Kim 563000078bcSNamhyung Kim return ret; 564000078bcSNamhyung Kim } 565000078bcSNamhyung Kim 5662dbbe9f2SNamhyung Kim static int print_hierarchy_indent(const char *sep, int indent, 5678e2fc44fSNamhyung Kim const char *line, FILE *fp) 5688e2fc44fSNamhyung Kim { 5692dbbe9f2SNamhyung Kim if (sep != NULL || indent < 2) 5708e2fc44fSNamhyung Kim return 0; 5718e2fc44fSNamhyung Kim 5722dbbe9f2SNamhyung Kim return fprintf(fp, "%-.*s", (indent - 2) * HIERARCHY_INDENT, line); 5738e2fc44fSNamhyung Kim } 5748e2fc44fSNamhyung Kim 575195bc0f8SNamhyung Kim static int hists__fprintf_hierarchy_headers(struct hists *hists, 576195bc0f8SNamhyung Kim struct perf_hpp *hpp, FILE *fp) 5778e2fc44fSNamhyung Kim { 578f58c95e3SNamhyung Kim bool first_node, first_col; 5792dbbe9f2SNamhyung Kim int indent; 580cb1fab91SNamhyung Kim int depth; 5818e2fc44fSNamhyung Kim unsigned width = 0; 5828e2fc44fSNamhyung Kim unsigned header_width = 0; 5838e2fc44fSNamhyung Kim struct perf_hpp_fmt *fmt; 584f58c95e3SNamhyung Kim struct perf_hpp_list_node *fmt_node; 585195bc0f8SNamhyung Kim const char *sep = symbol_conf.field_sep; 5868e2fc44fSNamhyung Kim 5872dbbe9f2SNamhyung Kim indent = hists->nr_hpp_node; 5888e2fc44fSNamhyung Kim 5898e2fc44fSNamhyung Kim /* preserve max indent depth for column headers */ 5902dbbe9f2SNamhyung Kim print_hierarchy_indent(sep, indent, spaces, fp); 5918e2fc44fSNamhyung Kim 592f58c95e3SNamhyung Kim /* the first hpp_list_node is for overhead columns */ 593f58c95e3SNamhyung Kim fmt_node = list_first_entry(&hists->hpp_formats, 594f58c95e3SNamhyung Kim struct perf_hpp_list_node, list); 5958e2fc44fSNamhyung Kim 596f58c95e3SNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { 59729659ab4SJiri Olsa fmt->header(fmt, hpp, hists, 0, NULL); 598f58c95e3SNamhyung Kim fprintf(fp, "%s%s", hpp->buf, sep ?: " "); 5998e2fc44fSNamhyung Kim } 6008e2fc44fSNamhyung Kim 6018e2fc44fSNamhyung Kim /* combine sort headers with ' / ' */ 602f58c95e3SNamhyung Kim first_node = true; 603f58c95e3SNamhyung Kim list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) { 604f58c95e3SNamhyung Kim if (!first_node) 605f58c95e3SNamhyung Kim header_width += fprintf(fp, " / "); 606f58c95e3SNamhyung Kim first_node = false; 607f58c95e3SNamhyung Kim 608f58c95e3SNamhyung Kim first_col = true; 609f58c95e3SNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { 6108e2fc44fSNamhyung Kim if (perf_hpp__should_skip(fmt, hists)) 6118e2fc44fSNamhyung Kim continue; 6128e2fc44fSNamhyung Kim 613f58c95e3SNamhyung Kim if (!first_col) 614f58c95e3SNamhyung Kim header_width += fprintf(fp, "+"); 615f58c95e3SNamhyung Kim first_col = false; 6168e2fc44fSNamhyung Kim 61729659ab4SJiri Olsa fmt->header(fmt, hpp, hists, 0, NULL); 6188e2fc44fSNamhyung Kim 6197d6a7e78SJiri Olsa header_width += fprintf(fp, "%s", trim(hpp->buf)); 6208e2fc44fSNamhyung Kim } 621f58c95e3SNamhyung Kim } 6228e2fc44fSNamhyung Kim 6238e2fc44fSNamhyung Kim fprintf(fp, "\n# "); 6248e2fc44fSNamhyung Kim 6258e2fc44fSNamhyung Kim /* preserve max indent depth for initial dots */ 6262dbbe9f2SNamhyung Kim print_hierarchy_indent(sep, indent, dots, fp); 6278e2fc44fSNamhyung Kim 628f58c95e3SNamhyung Kim /* the first hpp_list_node is for overhead columns */ 629f58c95e3SNamhyung Kim fmt_node = list_first_entry(&hists->hpp_formats, 630f58c95e3SNamhyung Kim struct perf_hpp_list_node, list); 6318e2fc44fSNamhyung Kim 632f58c95e3SNamhyung Kim first_col = true; 633f58c95e3SNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { 634f58c95e3SNamhyung Kim if (!first_col) 635f58c95e3SNamhyung Kim fprintf(fp, "%s", sep ?: ".."); 636f58c95e3SNamhyung Kim first_col = false; 6378e2fc44fSNamhyung Kim 638da1b0407SJiri Olsa width = fmt->width(fmt, hpp, hists); 6398e2fc44fSNamhyung Kim fprintf(fp, "%.*s", width, dots); 6408e2fc44fSNamhyung Kim } 6418e2fc44fSNamhyung Kim 642cb1fab91SNamhyung Kim depth = 0; 643f58c95e3SNamhyung Kim list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) { 644f58c95e3SNamhyung Kim first_col = true; 645f58c95e3SNamhyung Kim width = depth * HIERARCHY_INDENT; 646f58c95e3SNamhyung Kim 647f58c95e3SNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { 6488e2fc44fSNamhyung Kim if (perf_hpp__should_skip(fmt, hists)) 6498e2fc44fSNamhyung Kim continue; 6508e2fc44fSNamhyung Kim 651f58c95e3SNamhyung Kim if (!first_col) 652f58c95e3SNamhyung Kim width++; /* for '+' sign between column header */ 653f58c95e3SNamhyung Kim first_col = false; 654f58c95e3SNamhyung Kim 655da1b0407SJiri Olsa width += fmt->width(fmt, hpp, hists); 656f58c95e3SNamhyung Kim } 657cb1fab91SNamhyung Kim 6588e2fc44fSNamhyung Kim if (width > header_width) 6598e2fc44fSNamhyung Kim header_width = width; 660cb1fab91SNamhyung Kim 661cb1fab91SNamhyung Kim depth++; 6628e2fc44fSNamhyung Kim } 6638e2fc44fSNamhyung Kim 6648e2fc44fSNamhyung Kim fprintf(fp, "%s%-.*s", sep ?: " ", header_width, dots); 6658e2fc44fSNamhyung Kim 6668e2fc44fSNamhyung Kim fprintf(fp, "\n#\n"); 6678e2fc44fSNamhyung Kim 6688e2fc44fSNamhyung Kim return 2; 6698e2fc44fSNamhyung Kim } 6708e2fc44fSNamhyung Kim 671f3705b06SJiri Olsa static void fprintf_line(struct hists *hists, struct perf_hpp *hpp, 672f3705b06SJiri Olsa int line, FILE *fp) 6737ccf4f90SNamhyung Kim { 6741240005eSJiri Olsa struct perf_hpp_fmt *fmt; 6757ccf4f90SNamhyung Kim const char *sep = symbol_conf.field_sep; 6765395a048SJiri Olsa bool first = true; 67729659ab4SJiri Olsa int span = 0; 6787ccf4f90SNamhyung Kim 679f0786af5SJiri Olsa hists__for_each_format(hists, fmt) { 680361459f1SNamhyung Kim if (perf_hpp__should_skip(fmt, hists)) 681e67d49a7SNamhyung Kim continue; 682e67d49a7SNamhyung Kim 68329659ab4SJiri Olsa if (!first && !span) 684ea251d51SNamhyung Kim fprintf(fp, "%s", sep ?: " "); 6855395a048SJiri Olsa else 6865395a048SJiri Olsa first = false; 6877ccf4f90SNamhyung Kim 68829659ab4SJiri Olsa fmt->header(fmt, hpp, hists, line, &span); 68929659ab4SJiri Olsa 69029659ab4SJiri Olsa if (!span) 6917a72a2e5SJiri Olsa fprintf(fp, "%s", hpp->buf); 6927ccf4f90SNamhyung Kim } 693f3705b06SJiri Olsa } 6947ccf4f90SNamhyung Kim 695f3705b06SJiri Olsa static int 696f3705b06SJiri Olsa hists__fprintf_standard_headers(struct hists *hists, 697f3705b06SJiri Olsa struct perf_hpp *hpp, 698f3705b06SJiri Olsa FILE *fp) 699f3705b06SJiri Olsa { 700f3705b06SJiri Olsa struct perf_hpp_list *hpp_list = hists->hpp_list; 701f3705b06SJiri Olsa struct perf_hpp_fmt *fmt; 702f3705b06SJiri Olsa unsigned int width; 703f3705b06SJiri Olsa const char *sep = symbol_conf.field_sep; 704f3705b06SJiri Olsa bool first = true; 705f3705b06SJiri Olsa int line; 706f3705b06SJiri Olsa 707f3705b06SJiri Olsa for (line = 0; line < hpp_list->nr_header_lines; line++) { 708f3705b06SJiri Olsa /* first # is displayed one level up */ 709f3705b06SJiri Olsa if (line) 710f3705b06SJiri Olsa fprintf(fp, "# "); 711f3705b06SJiri Olsa fprintf_line(hists, hpp, line, fp); 7127ccf4f90SNamhyung Kim fprintf(fp, "\n"); 713f3705b06SJiri Olsa } 7147ccf4f90SNamhyung Kim 7157ccf4f90SNamhyung Kim if (sep) 716f3705b06SJiri Olsa return hpp_list->nr_header_lines; 7177ccf4f90SNamhyung Kim 7185395a048SJiri Olsa first = true; 7195395a048SJiri Olsa 720ea251d51SNamhyung Kim fprintf(fp, "# "); 721ea251d51SNamhyung Kim 722f0786af5SJiri Olsa hists__for_each_format(hists, fmt) { 7231240005eSJiri Olsa unsigned int i; 724ea251d51SNamhyung Kim 725361459f1SNamhyung Kim if (perf_hpp__should_skip(fmt, hists)) 726e67d49a7SNamhyung Kim continue; 727e67d49a7SNamhyung Kim 7285395a048SJiri Olsa if (!first) 729ea251d51SNamhyung Kim fprintf(fp, "%s", sep ?: " "); 7305395a048SJiri Olsa else 7315395a048SJiri Olsa first = false; 732ea251d51SNamhyung Kim 733da1b0407SJiri Olsa width = fmt->width(fmt, hpp, hists); 734ea251d51SNamhyung Kim for (i = 0; i < width; i++) 735ea251d51SNamhyung Kim fprintf(fp, "."); 7367ccf4f90SNamhyung Kim } 737ea251d51SNamhyung Kim 7387ccf4f90SNamhyung Kim fprintf(fp, "\n"); 7397ccf4f90SNamhyung Kim fprintf(fp, "#\n"); 740f3705b06SJiri Olsa return hpp_list->nr_header_lines + 2; 74136592ebbSJiri Olsa } 74236592ebbSJiri Olsa 7432d831454SJiri Olsa int hists__fprintf_headers(struct hists *hists, FILE *fp) 7447a72a2e5SJiri Olsa { 745d5278220SJiri Olsa char bf[1024]; 7467a72a2e5SJiri Olsa struct perf_hpp dummy_hpp = { 7477a72a2e5SJiri Olsa .buf = bf, 7487a72a2e5SJiri Olsa .size = sizeof(bf), 7497a72a2e5SJiri Olsa }; 7507a72a2e5SJiri Olsa 7517a72a2e5SJiri Olsa fprintf(fp, "# "); 7527a72a2e5SJiri Olsa 7537a72a2e5SJiri Olsa if (symbol_conf.report_hierarchy) 7547a72a2e5SJiri Olsa return hists__fprintf_hierarchy_headers(hists, &dummy_hpp, fp); 7557a72a2e5SJiri Olsa else 7567a72a2e5SJiri Olsa return hists__fprintf_standard_headers(hists, &dummy_hpp, fp); 7577a72a2e5SJiri Olsa 7587a72a2e5SJiri Olsa } 7597a72a2e5SJiri Olsa 76036592ebbSJiri Olsa size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, 761d05e3aaeSJiri Olsa int max_cols, float min_pcnt, FILE *fp, 762e9de7e2fSArnaldo Carvalho de Melo bool ignore_callchains) 76336592ebbSJiri Olsa { 76436592ebbSJiri Olsa struct rb_node *nd; 76536592ebbSJiri Olsa size_t ret = 0; 76636592ebbSJiri Olsa const char *sep = symbol_conf.field_sep; 76736592ebbSJiri Olsa int nr_rows = 0; 76836592ebbSJiri Olsa size_t linesz; 76936592ebbSJiri Olsa char *line = NULL; 77036592ebbSJiri Olsa unsigned indent; 77136592ebbSJiri Olsa 77236592ebbSJiri Olsa init_rem_hits(); 77336592ebbSJiri Olsa 774e3b60bc9SNamhyung Kim hists__reset_column_width(hists); 77536592ebbSJiri Olsa 77636592ebbSJiri Olsa if (symbol_conf.col_width_list_str) 77736592ebbSJiri Olsa perf_hpp__set_user_width(symbol_conf.col_width_list_str); 77836592ebbSJiri Olsa 77936592ebbSJiri Olsa if (show_header) 78036592ebbSJiri Olsa nr_rows += hists__fprintf_headers(hists, fp); 78136592ebbSJiri Olsa 78236592ebbSJiri Olsa if (max_rows && nr_rows >= max_rows) 7837ccf4f90SNamhyung Kim goto out; 7847ccf4f90SNamhyung Kim 78599cf666cSArnaldo Carvalho de Melo linesz = hists__sort_list_width(hists) + 3 + 1; 7869754c4f9SJiri Olsa linesz += perf_hpp__color_overhead(); 78799cf666cSArnaldo Carvalho de Melo line = malloc(linesz); 78899cf666cSArnaldo Carvalho de Melo if (line == NULL) { 78999cf666cSArnaldo Carvalho de Melo ret = -1; 79099cf666cSArnaldo Carvalho de Melo goto out; 79199cf666cSArnaldo Carvalho de Melo } 79299cf666cSArnaldo Carvalho de Melo 793bd4abd39SNamhyung Kim indent = hists__overhead_width(hists) + 4; 794bd4abd39SNamhyung Kim 7952eb3d689SDavidlohr Bueso for (nd = rb_first_cached(&hists->entries); nd; 7962eb3d689SDavidlohr Bueso nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD)) { 7977ccf4f90SNamhyung Kim struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 79814135663SNamhyung Kim float percent; 7997ccf4f90SNamhyung Kim 8007ccf4f90SNamhyung Kim if (h->filtered) 8017ccf4f90SNamhyung Kim continue; 8027ccf4f90SNamhyung Kim 80314135663SNamhyung Kim percent = hist_entry__get_percent_limit(h); 804064f1981SNamhyung Kim if (percent < min_pcnt) 805064f1981SNamhyung Kim continue; 806064f1981SNamhyung Kim 807e9de7e2fSArnaldo Carvalho de Melo ret += hist_entry__fprintf(h, max_cols, line, linesz, fp, ignore_callchains); 8087ccf4f90SNamhyung Kim 8097ccf4f90SNamhyung Kim if (max_rows && ++nr_rows >= max_rows) 81099cf666cSArnaldo Carvalho de Melo break; 8117ccf4f90SNamhyung Kim 812bd4abd39SNamhyung Kim /* 813bd4abd39SNamhyung Kim * If all children are filtered out or percent-limited, 814bd4abd39SNamhyung Kim * display "no entry >= x.xx%" message. 815bd4abd39SNamhyung Kim */ 816bd4abd39SNamhyung Kim if (!h->leaf && !hist_entry__has_hierarchy_children(h, min_pcnt)) { 817f58c95e3SNamhyung Kim int depth = hists->nr_hpp_node + h->depth + 1; 818bd4abd39SNamhyung Kim 819f58c95e3SNamhyung Kim print_hierarchy_indent(sep, depth, spaces, fp); 820bd4abd39SNamhyung Kim fprintf(fp, "%*sno entry >= %.2f%%\n", indent, "", min_pcnt); 821bd4abd39SNamhyung Kim 822bd4abd39SNamhyung Kim if (max_rows && ++nr_rows >= max_rows) 823bd4abd39SNamhyung Kim break; 824bd4abd39SNamhyung Kim } 825bd4abd39SNamhyung Kim 8267ccf4f90SNamhyung Kim if (h->ms.map == NULL && verbose > 1) { 827b0867f0cSArnaldo Carvalho de Melo map_groups__fprintf(h->thread->mg, fp); 8287ccf4f90SNamhyung Kim fprintf(fp, "%.10s end\n", graph_dotted_line); 8297ccf4f90SNamhyung Kim } 8307ccf4f90SNamhyung Kim } 83199cf666cSArnaldo Carvalho de Melo 83299cf666cSArnaldo Carvalho de Melo free(line); 8337ccf4f90SNamhyung Kim out: 83474cf249dSArnaldo Carvalho de Melo zfree(&rem_sq_bracket); 8357ccf4f90SNamhyung Kim 8367ccf4f90SNamhyung Kim return ret; 8377ccf4f90SNamhyung Kim } 8387ccf4f90SNamhyung Kim 83952168eeaSArnaldo Carvalho de Melo size_t events_stats__fprintf(struct events_stats *stats, FILE *fp) 8407ccf4f90SNamhyung Kim { 8417ccf4f90SNamhyung Kim int i; 8427ccf4f90SNamhyung Kim size_t ret = 0; 8437ccf4f90SNamhyung Kim 8447ccf4f90SNamhyung Kim for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { 8457ccf4f90SNamhyung Kim const char *name; 8467ccf4f90SNamhyung Kim 8477ccf4f90SNamhyung Kim name = perf_event__name(i); 8487ccf4f90SNamhyung Kim if (!strcmp(name, "UNKNOWN")) 8497ccf4f90SNamhyung Kim continue; 8507ccf4f90SNamhyung Kim 85139ce7fb3SIngo Molnar ret += fprintf(fp, "%16s events: %10d\n", name, stats->nr_events[i]); 8527ccf4f90SNamhyung Kim } 8537ccf4f90SNamhyung Kim 8547ccf4f90SNamhyung Kim return ret; 8557ccf4f90SNamhyung Kim } 856