1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 27ccf4f90SNamhyung Kim #include <stdio.h> 3f2a39fe8SArnaldo Carvalho de Melo #include <stdlib.h> 48e99b6d4SArnaldo Carvalho de Melo #include <linux/string.h> 57ccf4f90SNamhyung Kim 6b10ba7f1SArnaldo Carvalho de Melo #include "../../util/callchain.h" 7185bcb92SArnaldo Carvalho de Melo #include "../../util/debug.h" 8ea49e01cSArnaldo Carvalho de Melo #include "../../util/event.h" 97ccf4f90SNamhyung Kim #include "../../util/hist.h" 107b644f9aSArnaldo Carvalho de Melo #include "../../util/map.h" 11c54d241bSArnaldo Carvalho de Melo #include "../../util/maps.h" 12daecf9e0SArnaldo Carvalho de Melo #include "../../util/symbol.h" 137ccf4f90SNamhyung Kim #include "../../util/sort.h" 145b9e2146SNamhyung Kim #include "../../util/evsel.h" 15632a5cabSArnaldo Carvalho de Melo #include "../../util/srcline.h" 16a067558eSArnaldo Carvalho de Melo #include "../../util/string2.h" 17e7ff8920SArnaldo Carvalho de Melo #include "../../util/thread.h" 180b49f836SJin Yao #include "../../util/block-info.h" 193052ba56SArnaldo Carvalho de Melo #include <linux/ctype.h> 207f7c536fSArnaldo Carvalho de Melo #include <linux/zalloc.h> 217ccf4f90SNamhyung Kim 227ccf4f90SNamhyung Kim static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin) 237ccf4f90SNamhyung Kim { 247ccf4f90SNamhyung Kim int i; 257ccf4f90SNamhyung Kim int ret = fprintf(fp, " "); 267ccf4f90SNamhyung Kim 277ccf4f90SNamhyung Kim for (i = 0; i < left_margin; i++) 287ccf4f90SNamhyung Kim ret += fprintf(fp, " "); 297ccf4f90SNamhyung Kim 307ccf4f90SNamhyung Kim return ret; 317ccf4f90SNamhyung Kim } 327ccf4f90SNamhyung Kim 337ccf4f90SNamhyung Kim static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask, 347ccf4f90SNamhyung Kim int left_margin) 357ccf4f90SNamhyung Kim { 367ccf4f90SNamhyung Kim int i; 377ccf4f90SNamhyung Kim size_t ret = callchain__fprintf_left_margin(fp, left_margin); 387ccf4f90SNamhyung Kim 397ccf4f90SNamhyung Kim for (i = 0; i < depth; i++) 407ccf4f90SNamhyung Kim if (depth_mask & (1 << i)) 417ccf4f90SNamhyung Kim ret += fprintf(fp, "| "); 427ccf4f90SNamhyung Kim else 437ccf4f90SNamhyung Kim ret += fprintf(fp, " "); 447ccf4f90SNamhyung Kim 457ccf4f90SNamhyung Kim ret += fprintf(fp, "\n"); 467ccf4f90SNamhyung Kim 477ccf4f90SNamhyung Kim return ret; 487ccf4f90SNamhyung Kim } 497ccf4f90SNamhyung Kim 505ab250caSNamhyung Kim static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_node *node, 515ab250caSNamhyung Kim struct callchain_list *chain, 527ccf4f90SNamhyung Kim int depth, int depth_mask, int period, 535ab250caSNamhyung Kim u64 total_samples, int left_margin) 547ccf4f90SNamhyung Kim { 557ccf4f90SNamhyung Kim int i; 567ccf4f90SNamhyung Kim size_t ret = 0; 578577ae6bSJin Yao char bf[1024], *alloc_str = NULL; 588577ae6bSJin Yao char buf[64]; 598577ae6bSJin Yao const char *str; 607ccf4f90SNamhyung Kim 617ccf4f90SNamhyung Kim ret += callchain__fprintf_left_margin(fp, left_margin); 627ccf4f90SNamhyung Kim for (i = 0; i < depth; i++) { 637ccf4f90SNamhyung Kim if (depth_mask & (1 << i)) 647ccf4f90SNamhyung Kim ret += fprintf(fp, "|"); 657ccf4f90SNamhyung Kim else 667ccf4f90SNamhyung Kim ret += fprintf(fp, " "); 677ccf4f90SNamhyung Kim if (!period && i == depth - 1) { 685ab250caSNamhyung Kim ret += fprintf(fp, "--"); 695ab250caSNamhyung Kim ret += callchain_node__fprintf_value(node, fp, total_samples); 705ab250caSNamhyung Kim ret += fprintf(fp, "--"); 717ccf4f90SNamhyung Kim } else 727ccf4f90SNamhyung Kim ret += fprintf(fp, "%s", " "); 737ccf4f90SNamhyung Kim } 748577ae6bSJin Yao 758577ae6bSJin Yao str = callchain_list__sym_name(chain, bf, sizeof(bf), false); 768577ae6bSJin Yao 778577ae6bSJin Yao if (symbol_conf.show_branchflag_count) { 78c4ee0625SJin Yao callchain_list_counts__printf_value(chain, NULL, 798577ae6bSJin Yao buf, sizeof(buf)); 808577ae6bSJin Yao 818577ae6bSJin Yao if (asprintf(&alloc_str, "%s%s", str, buf) < 0) 828577ae6bSJin Yao str = "Not enough memory!"; 838577ae6bSJin Yao else 848577ae6bSJin Yao str = alloc_str; 858577ae6bSJin Yao } 868577ae6bSJin Yao 878577ae6bSJin Yao fputs(str, fp); 882989ccaaSAndi Kleen fputc('\n', fp); 898577ae6bSJin Yao free(alloc_str); 900db64dd0SJin Yao 917ccf4f90SNamhyung Kim return ret; 927ccf4f90SNamhyung Kim } 937ccf4f90SNamhyung Kim 947ccf4f90SNamhyung Kim static struct symbol *rem_sq_bracket; 957ccf4f90SNamhyung Kim static struct callchain_list rem_hits; 967ccf4f90SNamhyung Kim 977ccf4f90SNamhyung Kim static void init_rem_hits(void) 987ccf4f90SNamhyung Kim { 997ccf4f90SNamhyung Kim rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6); 1007ccf4f90SNamhyung Kim if (!rem_sq_bracket) { 1017ccf4f90SNamhyung Kim fprintf(stderr, "Not enough memory to display remaining hits\n"); 1027ccf4f90SNamhyung Kim return; 1037ccf4f90SNamhyung Kim } 1047ccf4f90SNamhyung Kim 1057ccf4f90SNamhyung Kim strcpy(rem_sq_bracket->name, "[...]"); 1067ccf4f90SNamhyung Kim rem_hits.ms.sym = rem_sq_bracket; 1077ccf4f90SNamhyung Kim } 1087ccf4f90SNamhyung Kim 1097ccf4f90SNamhyung Kim static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root, 1107ccf4f90SNamhyung Kim u64 total_samples, int depth, 1117ccf4f90SNamhyung Kim int depth_mask, int left_margin) 1127ccf4f90SNamhyung Kim { 1137ccf4f90SNamhyung Kim struct rb_node *node, *next; 114f2af0086SNamhyung Kim struct callchain_node *child = NULL; 1157ccf4f90SNamhyung Kim struct callchain_list *chain; 1167ccf4f90SNamhyung Kim int new_depth_mask = depth_mask; 1177ccf4f90SNamhyung Kim u64 remaining; 1187ccf4f90SNamhyung Kim size_t ret = 0; 1197ccf4f90SNamhyung Kim int i; 1207ccf4f90SNamhyung Kim uint entries_printed = 0; 121f2af0086SNamhyung Kim int cumul_count = 0; 1227ccf4f90SNamhyung Kim 1237ccf4f90SNamhyung Kim remaining = total_samples; 1247ccf4f90SNamhyung Kim 1257ccf4f90SNamhyung Kim node = rb_first(root); 1267ccf4f90SNamhyung Kim while (node) { 1277ccf4f90SNamhyung Kim u64 new_total; 1287ccf4f90SNamhyung Kim u64 cumul; 1297ccf4f90SNamhyung Kim 1307ccf4f90SNamhyung Kim child = rb_entry(node, struct callchain_node, rb_node); 1317ccf4f90SNamhyung Kim cumul = callchain_cumul_hits(child); 1327ccf4f90SNamhyung Kim remaining -= cumul; 133f2af0086SNamhyung Kim cumul_count += callchain_cumul_counts(child); 1347ccf4f90SNamhyung Kim 1357ccf4f90SNamhyung Kim /* 1367ccf4f90SNamhyung Kim * The depth mask manages the output of pipes that show 1377ccf4f90SNamhyung Kim * the depth. We don't want to keep the pipes of the current 1387ccf4f90SNamhyung Kim * level for the last child of this depth. 1397ccf4f90SNamhyung Kim * Except if we have remaining filtered hits. They will 1407ccf4f90SNamhyung Kim * supersede the last child 1417ccf4f90SNamhyung Kim */ 1427ccf4f90SNamhyung Kim next = rb_next(node); 1437ccf4f90SNamhyung Kim if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining)) 1447ccf4f90SNamhyung Kim new_depth_mask &= ~(1 << (depth - 1)); 1457ccf4f90SNamhyung Kim 1467ccf4f90SNamhyung Kim /* 1477ccf4f90SNamhyung Kim * But we keep the older depth mask for the line separator 1487ccf4f90SNamhyung Kim * to keep the level link until we reach the last child 1497ccf4f90SNamhyung Kim */ 1507ccf4f90SNamhyung Kim ret += ipchain__fprintf_graph_line(fp, depth, depth_mask, 1517ccf4f90SNamhyung Kim left_margin); 1527ccf4f90SNamhyung Kim i = 0; 1537ccf4f90SNamhyung Kim list_for_each_entry(chain, &child->val, list) { 1545ab250caSNamhyung Kim ret += ipchain__fprintf_graph(fp, child, chain, depth, 1557ccf4f90SNamhyung Kim new_depth_mask, i++, 1567ccf4f90SNamhyung Kim total_samples, 1577ccf4f90SNamhyung Kim left_margin); 1587ccf4f90SNamhyung Kim } 1597ccf4f90SNamhyung Kim 1607ccf4f90SNamhyung Kim if (callchain_param.mode == CHAIN_GRAPH_REL) 1617ccf4f90SNamhyung Kim new_total = child->children_hit; 1627ccf4f90SNamhyung Kim else 1637ccf4f90SNamhyung Kim new_total = total_samples; 1647ccf4f90SNamhyung Kim 1657ccf4f90SNamhyung Kim ret += __callchain__fprintf_graph(fp, &child->rb_root, new_total, 1667ccf4f90SNamhyung Kim depth + 1, 1677ccf4f90SNamhyung Kim new_depth_mask | (1 << depth), 1687ccf4f90SNamhyung Kim left_margin); 1697ccf4f90SNamhyung Kim node = next; 1707ccf4f90SNamhyung Kim if (++entries_printed == callchain_param.print_limit) 1717ccf4f90SNamhyung Kim break; 1727ccf4f90SNamhyung Kim } 1737ccf4f90SNamhyung Kim 1747ccf4f90SNamhyung Kim if (callchain_param.mode == CHAIN_GRAPH_REL && 1757ccf4f90SNamhyung Kim remaining && remaining != total_samples) { 1765ab250caSNamhyung Kim struct callchain_node rem_node = { 1775ab250caSNamhyung Kim .hit = remaining, 1785ab250caSNamhyung Kim }; 1797ccf4f90SNamhyung Kim 1807ccf4f90SNamhyung Kim if (!rem_sq_bracket) 1817ccf4f90SNamhyung Kim return ret; 1827ccf4f90SNamhyung Kim 183f2af0086SNamhyung Kim if (callchain_param.value == CCVAL_COUNT && child && child->parent) { 184f2af0086SNamhyung Kim rem_node.count = child->parent->children_count - cumul_count; 185f2af0086SNamhyung Kim if (rem_node.count <= 0) 186f2af0086SNamhyung Kim return ret; 187f2af0086SNamhyung Kim } 188f2af0086SNamhyung Kim 1897ccf4f90SNamhyung Kim new_depth_mask &= ~(1 << (depth - 1)); 1905ab250caSNamhyung Kim ret += ipchain__fprintf_graph(fp, &rem_node, &rem_hits, depth, 1917ccf4f90SNamhyung Kim new_depth_mask, 0, total_samples, 1925ab250caSNamhyung Kim left_margin); 1937ccf4f90SNamhyung Kim } 1947ccf4f90SNamhyung Kim 1957ccf4f90SNamhyung Kim return ret; 1967ccf4f90SNamhyung Kim } 1977ccf4f90SNamhyung Kim 1987ed5d6e2SNamhyung Kim /* 1997ed5d6e2SNamhyung Kim * If have one single callchain root, don't bother printing 2007ed5d6e2SNamhyung Kim * its percentage (100 % in fractal mode and the same percentage 2017ed5d6e2SNamhyung Kim * than the hist in graph mode). This also avoid one level of column. 2027ed5d6e2SNamhyung Kim * 2037ed5d6e2SNamhyung Kim * However when percent-limit applied, it's possible that single callchain 2047ed5d6e2SNamhyung Kim * node have different (non-100% in fractal mode) percentage. 2057ed5d6e2SNamhyung Kim */ 2067ed5d6e2SNamhyung Kim static bool need_percent_display(struct rb_node *node, u64 parent_samples) 2077ed5d6e2SNamhyung Kim { 2087ed5d6e2SNamhyung Kim struct callchain_node *cnode; 2097ed5d6e2SNamhyung Kim 2107ed5d6e2SNamhyung Kim if (rb_next(node)) 2117ed5d6e2SNamhyung Kim return true; 2127ed5d6e2SNamhyung Kim 2137ed5d6e2SNamhyung Kim cnode = rb_entry(node, struct callchain_node, rb_node); 2147ed5d6e2SNamhyung Kim return callchain_cumul_hits(cnode) != parent_samples; 2157ed5d6e2SNamhyung Kim } 2167ed5d6e2SNamhyung Kim 2177ccf4f90SNamhyung Kim static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root, 21854d27b31SNamhyung Kim u64 total_samples, u64 parent_samples, 21954d27b31SNamhyung Kim int left_margin) 2207ccf4f90SNamhyung Kim { 2217ccf4f90SNamhyung Kim struct callchain_node *cnode; 2227ccf4f90SNamhyung Kim struct callchain_list *chain; 2237ccf4f90SNamhyung Kim u32 entries_printed = 0; 2247ccf4f90SNamhyung Kim bool printed = false; 2257ccf4f90SNamhyung Kim struct rb_node *node; 2267ccf4f90SNamhyung Kim int i = 0; 2277ccf4f90SNamhyung Kim int ret = 0; 2282989ccaaSAndi Kleen char bf[1024]; 2297ccf4f90SNamhyung Kim 2307ccf4f90SNamhyung Kim node = rb_first(root); 2317ed5d6e2SNamhyung Kim if (node && !need_percent_display(node, parent_samples)) { 2327ccf4f90SNamhyung Kim cnode = rb_entry(node, struct callchain_node, rb_node); 2337ccf4f90SNamhyung Kim list_for_each_entry(chain, &cnode->val, list) { 2347ccf4f90SNamhyung Kim /* 2357ccf4f90SNamhyung Kim * If we sort by symbol, the first entry is the same than 2367ccf4f90SNamhyung Kim * the symbol. No need to print it otherwise it appears as 2377ccf4f90SNamhyung Kim * displayed twice. 2387ccf4f90SNamhyung Kim */ 239cfaa154bSNamhyung Kim if (!i++ && field_order == NULL && 2408e99b6d4SArnaldo Carvalho de Melo sort_order && strstarts(sort_order, "sym")) 2417ccf4f90SNamhyung Kim continue; 2420db64dd0SJin Yao 2437ccf4f90SNamhyung Kim if (!printed) { 2447ccf4f90SNamhyung Kim ret += callchain__fprintf_left_margin(fp, left_margin); 2457ccf4f90SNamhyung Kim ret += fprintf(fp, "|\n"); 2467ccf4f90SNamhyung Kim ret += callchain__fprintf_left_margin(fp, left_margin); 2477ccf4f90SNamhyung Kim ret += fprintf(fp, "---"); 2487ccf4f90SNamhyung Kim left_margin += 3; 2497ccf4f90SNamhyung Kim printed = true; 2507ccf4f90SNamhyung Kim } else 2517ccf4f90SNamhyung Kim ret += callchain__fprintf_left_margin(fp, left_margin); 2527ccf4f90SNamhyung Kim 2538577ae6bSJin Yao ret += fprintf(fp, "%s", 2548577ae6bSJin Yao callchain_list__sym_name(chain, bf, 2558577ae6bSJin Yao sizeof(bf), 2562989ccaaSAndi Kleen false)); 2577ccf4f90SNamhyung Kim 2588577ae6bSJin Yao if (symbol_conf.show_branchflag_count) 2598577ae6bSJin Yao ret += callchain_list_counts__printf_value( 260c4ee0625SJin Yao chain, fp, NULL, 0); 2618577ae6bSJin Yao ret += fprintf(fp, "\n"); 2628577ae6bSJin Yao 2637ccf4f90SNamhyung Kim if (++entries_printed == callchain_param.print_limit) 2647ccf4f90SNamhyung Kim break; 2657ccf4f90SNamhyung Kim } 2667ccf4f90SNamhyung Kim root = &cnode->rb_root; 2677ccf4f90SNamhyung Kim } 2687ccf4f90SNamhyung Kim 26954d27b31SNamhyung Kim if (callchain_param.mode == CHAIN_GRAPH_REL) 27054d27b31SNamhyung Kim total_samples = parent_samples; 27154d27b31SNamhyung Kim 2727ccf4f90SNamhyung Kim ret += __callchain__fprintf_graph(fp, root, total_samples, 2737ccf4f90SNamhyung Kim 1, 1, left_margin); 2743848c23bSNamhyung Kim if (ret) { 2753848c23bSNamhyung Kim /* do not add a blank line if it printed nothing */ 2767ccf4f90SNamhyung Kim ret += fprintf(fp, "\n"); 2773848c23bSNamhyung Kim } 2787ccf4f90SNamhyung Kim 2797ccf4f90SNamhyung Kim return ret; 2807ccf4f90SNamhyung Kim } 2817ccf4f90SNamhyung Kim 282316c7136SArnaldo Carvalho de Melo static size_t __callchain__fprintf_flat(FILE *fp, struct callchain_node *node, 2837ccf4f90SNamhyung Kim u64 total_samples) 2847ccf4f90SNamhyung Kim { 2857ccf4f90SNamhyung Kim struct callchain_list *chain; 2867ccf4f90SNamhyung Kim size_t ret = 0; 2872989ccaaSAndi Kleen char bf[1024]; 2887ccf4f90SNamhyung Kim 289316c7136SArnaldo Carvalho de Melo if (!node) 2907ccf4f90SNamhyung Kim return 0; 2917ccf4f90SNamhyung Kim 292316c7136SArnaldo Carvalho de Melo ret += __callchain__fprintf_flat(fp, node->parent, total_samples); 2937ccf4f90SNamhyung Kim 2947ccf4f90SNamhyung Kim 295316c7136SArnaldo Carvalho de Melo list_for_each_entry(chain, &node->val, list) { 2967ccf4f90SNamhyung Kim if (chain->ip >= PERF_CONTEXT_MAX) 2977ccf4f90SNamhyung Kim continue; 2982989ccaaSAndi Kleen ret += fprintf(fp, " %s\n", callchain_list__sym_name(chain, 2992989ccaaSAndi Kleen bf, sizeof(bf), false)); 3007ccf4f90SNamhyung Kim } 3017ccf4f90SNamhyung Kim 3027ccf4f90SNamhyung Kim return ret; 3037ccf4f90SNamhyung Kim } 3047ccf4f90SNamhyung Kim 305316c7136SArnaldo Carvalho de Melo static size_t callchain__fprintf_flat(FILE *fp, struct rb_root *tree, 3067ccf4f90SNamhyung Kim u64 total_samples) 3077ccf4f90SNamhyung Kim { 3087ccf4f90SNamhyung Kim size_t ret = 0; 3097ccf4f90SNamhyung Kim u32 entries_printed = 0; 3107ccf4f90SNamhyung Kim struct callchain_node *chain; 311316c7136SArnaldo Carvalho de Melo struct rb_node *rb_node = rb_first(tree); 3127ccf4f90SNamhyung Kim 3137ccf4f90SNamhyung Kim while (rb_node) { 3147ccf4f90SNamhyung Kim chain = rb_entry(rb_node, struct callchain_node, rb_node); 3157ccf4f90SNamhyung Kim 3165ab250caSNamhyung Kim ret += fprintf(fp, " "); 3175ab250caSNamhyung Kim ret += callchain_node__fprintf_value(chain, fp, total_samples); 3185ab250caSNamhyung Kim ret += fprintf(fp, "\n"); 3197ccf4f90SNamhyung Kim ret += __callchain__fprintf_flat(fp, chain, total_samples); 3207ccf4f90SNamhyung Kim ret += fprintf(fp, "\n"); 3217ccf4f90SNamhyung Kim if (++entries_printed == callchain_param.print_limit) 3227ccf4f90SNamhyung Kim break; 3237ccf4f90SNamhyung Kim 3247ccf4f90SNamhyung Kim rb_node = rb_next(rb_node); 3257ccf4f90SNamhyung Kim } 3267ccf4f90SNamhyung Kim 3277ccf4f90SNamhyung Kim return ret; 3287ccf4f90SNamhyung Kim } 3297ccf4f90SNamhyung Kim 33026e77924SNamhyung Kim static size_t __callchain__fprintf_folded(FILE *fp, struct callchain_node *node) 33126e77924SNamhyung Kim { 33226e77924SNamhyung Kim const char *sep = symbol_conf.field_sep ?: ";"; 33326e77924SNamhyung Kim struct callchain_list *chain; 33426e77924SNamhyung Kim size_t ret = 0; 33526e77924SNamhyung Kim char bf[1024]; 33626e77924SNamhyung Kim bool first; 33726e77924SNamhyung Kim 33826e77924SNamhyung Kim if (!node) 33926e77924SNamhyung Kim return 0; 34026e77924SNamhyung Kim 34126e77924SNamhyung Kim ret += __callchain__fprintf_folded(fp, node->parent); 34226e77924SNamhyung Kim 34326e77924SNamhyung Kim first = (ret == 0); 34426e77924SNamhyung Kim list_for_each_entry(chain, &node->val, list) { 34526e77924SNamhyung Kim if (chain->ip >= PERF_CONTEXT_MAX) 34626e77924SNamhyung Kim continue; 34726e77924SNamhyung Kim ret += fprintf(fp, "%s%s", first ? "" : sep, 34826e77924SNamhyung Kim callchain_list__sym_name(chain, 34926e77924SNamhyung Kim bf, sizeof(bf), false)); 35026e77924SNamhyung Kim first = false; 35126e77924SNamhyung Kim } 35226e77924SNamhyung Kim 35326e77924SNamhyung Kim return ret; 35426e77924SNamhyung Kim } 35526e77924SNamhyung Kim 35626e77924SNamhyung Kim static size_t callchain__fprintf_folded(FILE *fp, struct rb_root *tree, 35726e77924SNamhyung Kim u64 total_samples) 35826e77924SNamhyung Kim { 35926e77924SNamhyung Kim size_t ret = 0; 36026e77924SNamhyung Kim u32 entries_printed = 0; 36126e77924SNamhyung Kim struct callchain_node *chain; 36226e77924SNamhyung Kim struct rb_node *rb_node = rb_first(tree); 36326e77924SNamhyung Kim 36426e77924SNamhyung Kim while (rb_node) { 36526e77924SNamhyung Kim 36626e77924SNamhyung Kim chain = rb_entry(rb_node, struct callchain_node, rb_node); 36726e77924SNamhyung Kim 3685ab250caSNamhyung Kim ret += callchain_node__fprintf_value(chain, fp, total_samples); 3695ab250caSNamhyung Kim ret += fprintf(fp, " "); 37026e77924SNamhyung Kim ret += __callchain__fprintf_folded(fp, chain); 37126e77924SNamhyung Kim ret += fprintf(fp, "\n"); 37226e77924SNamhyung Kim if (++entries_printed == callchain_param.print_limit) 37326e77924SNamhyung Kim break; 37426e77924SNamhyung Kim 37526e77924SNamhyung Kim rb_node = rb_next(rb_node); 37626e77924SNamhyung Kim } 37726e77924SNamhyung Kim 37826e77924SNamhyung Kim return ret; 37926e77924SNamhyung Kim } 38026e77924SNamhyung Kim 3817ccf4f90SNamhyung Kim static size_t hist_entry_callchain__fprintf(struct hist_entry *he, 3827ccf4f90SNamhyung Kim u64 total_samples, int left_margin, 3837ccf4f90SNamhyung Kim FILE *fp) 3847ccf4f90SNamhyung Kim { 38554d27b31SNamhyung Kim u64 parent_samples = he->stat.period; 38654d27b31SNamhyung Kim 38754d27b31SNamhyung Kim if (symbol_conf.cumulate_callchain) 38854d27b31SNamhyung Kim parent_samples = he->stat_acc->period; 38954d27b31SNamhyung Kim 3907ccf4f90SNamhyung Kim switch (callchain_param.mode) { 3917ccf4f90SNamhyung Kim case CHAIN_GRAPH_REL: 39254d27b31SNamhyung Kim return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples, 39354d27b31SNamhyung Kim parent_samples, left_margin); 3947ccf4f90SNamhyung Kim break; 3957ccf4f90SNamhyung Kim case CHAIN_GRAPH_ABS: 3967ccf4f90SNamhyung Kim return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples, 39754d27b31SNamhyung Kim parent_samples, left_margin); 3987ccf4f90SNamhyung Kim break; 3997ccf4f90SNamhyung Kim case CHAIN_FLAT: 4007ccf4f90SNamhyung Kim return callchain__fprintf_flat(fp, &he->sorted_chain, total_samples); 4017ccf4f90SNamhyung Kim break; 40226e77924SNamhyung Kim case CHAIN_FOLDED: 40326e77924SNamhyung Kim return callchain__fprintf_folded(fp, &he->sorted_chain, total_samples); 40426e77924SNamhyung Kim break; 4057ccf4f90SNamhyung Kim case CHAIN_NONE: 4067ccf4f90SNamhyung Kim break; 4077ccf4f90SNamhyung Kim default: 4087ccf4f90SNamhyung Kim pr_err("Bad callchain mode\n"); 4097ccf4f90SNamhyung Kim } 4107ccf4f90SNamhyung Kim 4117ccf4f90SNamhyung Kim return 0; 4127ccf4f90SNamhyung Kim } 4137ccf4f90SNamhyung Kim 414bd28d0c5SJiri Olsa int __hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp, 4159da44db1SJiri Olsa struct perf_hpp_list *hpp_list) 416be0e6d10SJiri Olsa { 417be0e6d10SJiri Olsa const char *sep = symbol_conf.field_sep; 418be0e6d10SJiri Olsa struct perf_hpp_fmt *fmt; 419be0e6d10SJiri Olsa char *start = hpp->buf; 420be0e6d10SJiri Olsa int ret; 421be0e6d10SJiri Olsa bool first = true; 422be0e6d10SJiri Olsa 423be0e6d10SJiri Olsa if (symbol_conf.exclude_other && !he->parent) 424be0e6d10SJiri Olsa return 0; 425be0e6d10SJiri Olsa 4269da44db1SJiri Olsa perf_hpp_list__for_each_format(hpp_list, fmt) { 427361459f1SNamhyung Kim if (perf_hpp__should_skip(fmt, he->hists)) 428e67d49a7SNamhyung Kim continue; 429e67d49a7SNamhyung Kim 430be0e6d10SJiri Olsa /* 431be0e6d10SJiri Olsa * If there's no field_sep, we still need 432be0e6d10SJiri Olsa * to display initial ' '. 433be0e6d10SJiri Olsa */ 434be0e6d10SJiri Olsa if (!sep || !first) { 435be0e6d10SJiri Olsa ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " "); 436be0e6d10SJiri Olsa advance_hpp(hpp, ret); 437be0e6d10SJiri Olsa } else 438be0e6d10SJiri Olsa first = false; 439be0e6d10SJiri Olsa 4409754c4f9SJiri Olsa if (perf_hpp__use_color() && fmt->color) 441be0e6d10SJiri Olsa ret = fmt->color(fmt, hpp, he); 442be0e6d10SJiri Olsa else 443be0e6d10SJiri Olsa ret = fmt->entry(fmt, hpp, he); 444be0e6d10SJiri Olsa 44589fee709SArnaldo Carvalho de Melo ret = hist_entry__snprintf_alignment(he, hpp, fmt, ret); 446be0e6d10SJiri Olsa advance_hpp(hpp, ret); 447be0e6d10SJiri Olsa } 448be0e6d10SJiri Olsa 449be0e6d10SJiri Olsa return hpp->buf - start; 450be0e6d10SJiri Olsa } 451be0e6d10SJiri Olsa 4529da44db1SJiri Olsa static int hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp) 4539da44db1SJiri Olsa { 4549da44db1SJiri Olsa return __hist_entry__snprintf(he, hpp, he->hists->hpp_list); 4559da44db1SJiri Olsa } 4569da44db1SJiri Olsa 457ef86d68aSNamhyung Kim static int hist_entry__hierarchy_fprintf(struct hist_entry *he, 458ef86d68aSNamhyung Kim struct perf_hpp *hpp, 4592dbbe9f2SNamhyung Kim struct hists *hists, 460ef86d68aSNamhyung Kim FILE *fp) 461ef86d68aSNamhyung Kim { 462ef86d68aSNamhyung Kim const char *sep = symbol_conf.field_sep; 463ef86d68aSNamhyung Kim struct perf_hpp_fmt *fmt; 464f58c95e3SNamhyung Kim struct perf_hpp_list_node *fmt_node; 465ef86d68aSNamhyung Kim char *buf = hpp->buf; 466cb1fab91SNamhyung Kim size_t size = hpp->size; 467ef86d68aSNamhyung Kim int ret, printed = 0; 468ef86d68aSNamhyung Kim bool first = true; 469ef86d68aSNamhyung Kim 470ef86d68aSNamhyung Kim if (symbol_conf.exclude_other && !he->parent) 471ef86d68aSNamhyung Kim return 0; 472ef86d68aSNamhyung Kim 473ef86d68aSNamhyung Kim ret = scnprintf(hpp->buf, hpp->size, "%*s", he->depth * HIERARCHY_INDENT, ""); 474ef86d68aSNamhyung Kim advance_hpp(hpp, ret); 475ef86d68aSNamhyung Kim 476f58c95e3SNamhyung Kim /* the first hpp_list_node is for overhead columns */ 477f58c95e3SNamhyung Kim fmt_node = list_first_entry(&hists->hpp_formats, 478f58c95e3SNamhyung Kim struct perf_hpp_list_node, list); 479f58c95e3SNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { 480ef86d68aSNamhyung Kim /* 481ef86d68aSNamhyung Kim * If there's no field_sep, we still need 482ef86d68aSNamhyung Kim * to display initial ' '. 483ef86d68aSNamhyung Kim */ 484ef86d68aSNamhyung Kim if (!sep || !first) { 485ef86d68aSNamhyung Kim ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " "); 486ef86d68aSNamhyung Kim advance_hpp(hpp, ret); 487ef86d68aSNamhyung Kim } else 488ef86d68aSNamhyung Kim first = false; 489ef86d68aSNamhyung Kim 490ef86d68aSNamhyung Kim if (perf_hpp__use_color() && fmt->color) 491ef86d68aSNamhyung Kim ret = fmt->color(fmt, hpp, he); 492ef86d68aSNamhyung Kim else 493ef86d68aSNamhyung Kim ret = fmt->entry(fmt, hpp, he); 494ef86d68aSNamhyung Kim 495ef86d68aSNamhyung Kim ret = hist_entry__snprintf_alignment(he, hpp, fmt, ret); 496ef86d68aSNamhyung Kim advance_hpp(hpp, ret); 497ef86d68aSNamhyung Kim } 498ef86d68aSNamhyung Kim 4991b2dbbf4SNamhyung Kim if (!sep) 500ef86d68aSNamhyung Kim ret = scnprintf(hpp->buf, hpp->size, "%*s", 5012dbbe9f2SNamhyung Kim (hists->nr_hpp_node - 2) * HIERARCHY_INDENT, ""); 502ef86d68aSNamhyung Kim advance_hpp(hpp, ret); 503ef86d68aSNamhyung Kim 504cb1fab91SNamhyung Kim printed += fprintf(fp, "%s", buf); 505cb1fab91SNamhyung Kim 5061b2dbbf4SNamhyung Kim perf_hpp_list__for_each_format(he->hpp_list, fmt) { 507cb1fab91SNamhyung Kim hpp->buf = buf; 508cb1fab91SNamhyung Kim hpp->size = size; 509cb1fab91SNamhyung Kim 510ef86d68aSNamhyung Kim /* 511ef86d68aSNamhyung Kim * No need to call hist_entry__snprintf_alignment() since this 512ef86d68aSNamhyung Kim * fmt is always the last column in the hierarchy mode. 513ef86d68aSNamhyung Kim */ 514ef86d68aSNamhyung Kim if (perf_hpp__use_color() && fmt->color) 515ef86d68aSNamhyung Kim fmt->color(fmt, hpp, he); 516ef86d68aSNamhyung Kim else 517ef86d68aSNamhyung Kim fmt->entry(fmt, hpp, he); 518ef86d68aSNamhyung Kim 519cb1fab91SNamhyung Kim /* 520cb1fab91SNamhyung Kim * dynamic entries are right-aligned but we want left-aligned 521cb1fab91SNamhyung Kim * in the hierarchy mode 522cb1fab91SNamhyung Kim */ 52332858480SArnaldo Carvalho de Melo printed += fprintf(fp, "%s%s", sep ?: " ", skip_spaces(buf)); 5241b2dbbf4SNamhyung Kim } 5251b2dbbf4SNamhyung Kim printed += putc('\n', fp); 526ef86d68aSNamhyung Kim 527fabd37b8SArnaldo Carvalho de Melo if (he->leaf && hist_entry__has_callchains(he) && symbol_conf.use_callchain) { 528ef86d68aSNamhyung Kim u64 total = hists__total_period(hists); 529ef86d68aSNamhyung Kim 530ef86d68aSNamhyung Kim printed += hist_entry_callchain__fprintf(he, total, 0, fp); 531ef86d68aSNamhyung Kim goto out; 532ef86d68aSNamhyung Kim } 533ef86d68aSNamhyung Kim 534ef86d68aSNamhyung Kim out: 535ef86d68aSNamhyung Kim return printed; 536ef86d68aSNamhyung Kim } 537ef86d68aSNamhyung Kim 538b10c78c5SJin Yao static int hist_entry__block_fprintf(struct hist_entry *he, 539b10c78c5SJin Yao char *bf, size_t size, 540b10c78c5SJin Yao FILE *fp) 541b10c78c5SJin Yao { 542b10c78c5SJin Yao struct block_hist *bh = container_of(he, struct block_hist, he); 543b10c78c5SJin Yao int ret = 0; 544b10c78c5SJin Yao 545b10c78c5SJin Yao for (unsigned int i = 0; i < bh->block_hists.nr_entries; i++) { 546b10c78c5SJin Yao struct perf_hpp hpp = { 547b10c78c5SJin Yao .buf = bf, 548b10c78c5SJin Yao .size = size, 549b10c78c5SJin Yao .skip = false, 550b10c78c5SJin Yao }; 551b10c78c5SJin Yao 552b10c78c5SJin Yao bh->block_idx = i; 553b10c78c5SJin Yao hist_entry__snprintf(he, &hpp); 554b10c78c5SJin Yao 555b10c78c5SJin Yao if (!hpp.skip) 556b10c78c5SJin Yao ret += fprintf(fp, "%s\n", bf); 557b10c78c5SJin Yao } 558b10c78c5SJin Yao 559b10c78c5SJin Yao return ret; 560b10c78c5SJin Yao } 561b10c78c5SJin Yao 5626f7164faSJin Yao static int hist_entry__individual_block_fprintf(struct hist_entry *he, 5636f7164faSJin Yao char *bf, size_t size, 5646f7164faSJin Yao FILE *fp) 5656f7164faSJin Yao { 5666f7164faSJin Yao int ret = 0; 5676f7164faSJin Yao 5686f7164faSJin Yao struct perf_hpp hpp = { 5696f7164faSJin Yao .buf = bf, 5706f7164faSJin Yao .size = size, 5716f7164faSJin Yao .skip = false, 5726f7164faSJin Yao }; 5736f7164faSJin Yao 5746f7164faSJin Yao hist_entry__snprintf(he, &hpp); 5756f7164faSJin Yao if (!hpp.skip) 5766f7164faSJin Yao ret += fprintf(fp, "%s\n", bf); 5776f7164faSJin Yao 5786f7164faSJin Yao return ret; 5796f7164faSJin Yao } 5806f7164faSJin Yao 581000078bcSNamhyung Kim static int hist_entry__fprintf(struct hist_entry *he, size_t size, 582d05e3aaeSJiri Olsa char *bf, size_t bfsz, FILE *fp, 583e9de7e2fSArnaldo Carvalho de Melo bool ignore_callchains) 584000078bcSNamhyung Kim { 585000078bcSNamhyung Kim int ret; 5860db64dd0SJin Yao int callchain_ret = 0; 587ea251d51SNamhyung Kim struct perf_hpp hpp = { 588ea251d51SNamhyung Kim .buf = bf, 589ea251d51SNamhyung Kim .size = size, 590ea251d51SNamhyung Kim }; 5918f1d1b44SJiri Olsa struct hists *hists = he->hists; 5927e597d32SNamhyung Kim u64 total_period = hists->stats.total_period; 593000078bcSNamhyung Kim 59499cf666cSArnaldo Carvalho de Melo if (size == 0 || size > bfsz) 59599cf666cSArnaldo Carvalho de Melo size = hpp.size = bfsz; 596000078bcSNamhyung Kim 5972dbbe9f2SNamhyung Kim if (symbol_conf.report_hierarchy) 5982dbbe9f2SNamhyung Kim return hist_entry__hierarchy_fprintf(he, &hpp, hists, fp); 599ef86d68aSNamhyung Kim 600b10c78c5SJin Yao if (symbol_conf.report_block) 601b10c78c5SJin Yao return hist_entry__block_fprintf(he, bf, size, fp); 602b10c78c5SJin Yao 6036f7164faSJin Yao if (symbol_conf.report_individual_block) 6046f7164faSJin Yao return hist_entry__individual_block_fprintf(he, bf, size, fp); 6056f7164faSJin Yao 60626d8b338SNamhyung Kim hist_entry__snprintf(he, &hpp); 607000078bcSNamhyung Kim 608000078bcSNamhyung Kim ret = fprintf(fp, "%s\n", bf); 609000078bcSNamhyung Kim 610e9de7e2fSArnaldo Carvalho de Melo if (hist_entry__has_callchains(he) && !ignore_callchains) 6110db64dd0SJin Yao callchain_ret = hist_entry_callchain__fprintf(he, total_period, 6120db64dd0SJin Yao 0, fp); 6130db64dd0SJin Yao 6140db64dd0SJin Yao ret += callchain_ret; 615000078bcSNamhyung Kim 616000078bcSNamhyung Kim return ret; 617000078bcSNamhyung Kim } 618000078bcSNamhyung Kim 6192dbbe9f2SNamhyung Kim static int print_hierarchy_indent(const char *sep, int indent, 6208e2fc44fSNamhyung Kim const char *line, FILE *fp) 6218e2fc44fSNamhyung Kim { 622b598c34fSArnaldo Carvalho de Melo int width; 623b598c34fSArnaldo Carvalho de Melo 6242dbbe9f2SNamhyung Kim if (sep != NULL || indent < 2) 6258e2fc44fSNamhyung Kim return 0; 6268e2fc44fSNamhyung Kim 627b598c34fSArnaldo Carvalho de Melo width = (indent - 2) * HIERARCHY_INDENT; 628b598c34fSArnaldo Carvalho de Melo 629b598c34fSArnaldo Carvalho de Melo return fprintf(fp, "%-*.*s", width, width, line); 6308e2fc44fSNamhyung Kim } 6318e2fc44fSNamhyung Kim 632195bc0f8SNamhyung Kim static int hists__fprintf_hierarchy_headers(struct hists *hists, 633195bc0f8SNamhyung Kim struct perf_hpp *hpp, FILE *fp) 6348e2fc44fSNamhyung Kim { 635f58c95e3SNamhyung Kim bool first_node, first_col; 6362dbbe9f2SNamhyung Kim int indent; 637cb1fab91SNamhyung Kim int depth; 6388e2fc44fSNamhyung Kim unsigned width = 0; 6398e2fc44fSNamhyung Kim unsigned header_width = 0; 6408e2fc44fSNamhyung Kim struct perf_hpp_fmt *fmt; 641f58c95e3SNamhyung Kim struct perf_hpp_list_node *fmt_node; 642195bc0f8SNamhyung Kim const char *sep = symbol_conf.field_sep; 6438e2fc44fSNamhyung Kim 6442dbbe9f2SNamhyung Kim indent = hists->nr_hpp_node; 6458e2fc44fSNamhyung Kim 6468e2fc44fSNamhyung Kim /* preserve max indent depth for column headers */ 647b598c34fSArnaldo Carvalho de Melo print_hierarchy_indent(sep, indent, " ", fp); 6488e2fc44fSNamhyung Kim 649f58c95e3SNamhyung Kim /* the first hpp_list_node is for overhead columns */ 650f58c95e3SNamhyung Kim fmt_node = list_first_entry(&hists->hpp_formats, 651f58c95e3SNamhyung Kim struct perf_hpp_list_node, list); 6528e2fc44fSNamhyung Kim 653f58c95e3SNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { 65429659ab4SJiri Olsa fmt->header(fmt, hpp, hists, 0, NULL); 655f58c95e3SNamhyung Kim fprintf(fp, "%s%s", hpp->buf, sep ?: " "); 6568e2fc44fSNamhyung Kim } 6578e2fc44fSNamhyung Kim 6588e2fc44fSNamhyung Kim /* combine sort headers with ' / ' */ 659f58c95e3SNamhyung Kim first_node = true; 660f58c95e3SNamhyung Kim list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) { 661f58c95e3SNamhyung Kim if (!first_node) 662f58c95e3SNamhyung Kim header_width += fprintf(fp, " / "); 663f58c95e3SNamhyung Kim first_node = false; 664f58c95e3SNamhyung Kim 665f58c95e3SNamhyung Kim first_col = true; 666f58c95e3SNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { 6678e2fc44fSNamhyung Kim if (perf_hpp__should_skip(fmt, hists)) 6688e2fc44fSNamhyung Kim continue; 6698e2fc44fSNamhyung Kim 670f58c95e3SNamhyung Kim if (!first_col) 671f58c95e3SNamhyung Kim header_width += fprintf(fp, "+"); 672f58c95e3SNamhyung Kim first_col = false; 6738e2fc44fSNamhyung Kim 67429659ab4SJiri Olsa fmt->header(fmt, hpp, hists, 0, NULL); 6758e2fc44fSNamhyung Kim 6763ca43b60SArnaldo Carvalho de Melo header_width += fprintf(fp, "%s", strim(hpp->buf)); 6778e2fc44fSNamhyung Kim } 678f58c95e3SNamhyung Kim } 6798e2fc44fSNamhyung Kim 6808e2fc44fSNamhyung Kim fprintf(fp, "\n# "); 6818e2fc44fSNamhyung Kim 6828e2fc44fSNamhyung Kim /* preserve max indent depth for initial dots */ 6832dbbe9f2SNamhyung Kim print_hierarchy_indent(sep, indent, dots, fp); 6848e2fc44fSNamhyung Kim 685f58c95e3SNamhyung Kim /* the first hpp_list_node is for overhead columns */ 686f58c95e3SNamhyung Kim fmt_node = list_first_entry(&hists->hpp_formats, 687f58c95e3SNamhyung Kim struct perf_hpp_list_node, list); 6888e2fc44fSNamhyung Kim 689f58c95e3SNamhyung Kim first_col = true; 690f58c95e3SNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { 691f58c95e3SNamhyung Kim if (!first_col) 692f58c95e3SNamhyung Kim fprintf(fp, "%s", sep ?: ".."); 693f58c95e3SNamhyung Kim first_col = false; 6948e2fc44fSNamhyung Kim 695da1b0407SJiri Olsa width = fmt->width(fmt, hpp, hists); 6968e2fc44fSNamhyung Kim fprintf(fp, "%.*s", width, dots); 6978e2fc44fSNamhyung Kim } 6988e2fc44fSNamhyung Kim 699cb1fab91SNamhyung Kim depth = 0; 700f58c95e3SNamhyung Kim list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) { 701f58c95e3SNamhyung Kim first_col = true; 702f58c95e3SNamhyung Kim width = depth * HIERARCHY_INDENT; 703f58c95e3SNamhyung Kim 704f58c95e3SNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { 7058e2fc44fSNamhyung Kim if (perf_hpp__should_skip(fmt, hists)) 7068e2fc44fSNamhyung Kim continue; 7078e2fc44fSNamhyung Kim 708f58c95e3SNamhyung Kim if (!first_col) 709f58c95e3SNamhyung Kim width++; /* for '+' sign between column header */ 710f58c95e3SNamhyung Kim first_col = false; 711f58c95e3SNamhyung Kim 712da1b0407SJiri Olsa width += fmt->width(fmt, hpp, hists); 713f58c95e3SNamhyung Kim } 714cb1fab91SNamhyung Kim 7158e2fc44fSNamhyung Kim if (width > header_width) 7168e2fc44fSNamhyung Kim header_width = width; 717cb1fab91SNamhyung Kim 718cb1fab91SNamhyung Kim depth++; 7198e2fc44fSNamhyung Kim } 7208e2fc44fSNamhyung Kim 7218e2fc44fSNamhyung Kim fprintf(fp, "%s%-.*s", sep ?: " ", header_width, dots); 7228e2fc44fSNamhyung Kim 7238e2fc44fSNamhyung Kim fprintf(fp, "\n#\n"); 7248e2fc44fSNamhyung Kim 7258e2fc44fSNamhyung Kim return 2; 7268e2fc44fSNamhyung Kim } 7278e2fc44fSNamhyung Kim 728f3705b06SJiri Olsa static void fprintf_line(struct hists *hists, struct perf_hpp *hpp, 729f3705b06SJiri Olsa int line, FILE *fp) 7307ccf4f90SNamhyung Kim { 7311240005eSJiri Olsa struct perf_hpp_fmt *fmt; 7327ccf4f90SNamhyung Kim const char *sep = symbol_conf.field_sep; 7335395a048SJiri Olsa bool first = true; 73429659ab4SJiri Olsa int span = 0; 7357ccf4f90SNamhyung Kim 736f0786af5SJiri Olsa hists__for_each_format(hists, fmt) { 737361459f1SNamhyung Kim if (perf_hpp__should_skip(fmt, hists)) 738e67d49a7SNamhyung Kim continue; 739e67d49a7SNamhyung Kim 74029659ab4SJiri Olsa if (!first && !span) 741ea251d51SNamhyung Kim fprintf(fp, "%s", sep ?: " "); 7425395a048SJiri Olsa else 7435395a048SJiri Olsa first = false; 7447ccf4f90SNamhyung Kim 74529659ab4SJiri Olsa fmt->header(fmt, hpp, hists, line, &span); 74629659ab4SJiri Olsa 74729659ab4SJiri Olsa if (!span) 7487a72a2e5SJiri Olsa fprintf(fp, "%s", hpp->buf); 7497ccf4f90SNamhyung Kim } 750f3705b06SJiri Olsa } 7517ccf4f90SNamhyung Kim 752f3705b06SJiri Olsa static int 753f3705b06SJiri Olsa hists__fprintf_standard_headers(struct hists *hists, 754f3705b06SJiri Olsa struct perf_hpp *hpp, 755f3705b06SJiri Olsa FILE *fp) 756f3705b06SJiri Olsa { 757f3705b06SJiri Olsa struct perf_hpp_list *hpp_list = hists->hpp_list; 758f3705b06SJiri Olsa struct perf_hpp_fmt *fmt; 759f3705b06SJiri Olsa unsigned int width; 760f3705b06SJiri Olsa const char *sep = symbol_conf.field_sep; 761f3705b06SJiri Olsa bool first = true; 762f3705b06SJiri Olsa int line; 763f3705b06SJiri Olsa 764f3705b06SJiri Olsa for (line = 0; line < hpp_list->nr_header_lines; line++) { 765f3705b06SJiri Olsa /* first # is displayed one level up */ 766f3705b06SJiri Olsa if (line) 767f3705b06SJiri Olsa fprintf(fp, "# "); 768f3705b06SJiri Olsa fprintf_line(hists, hpp, line, fp); 7697ccf4f90SNamhyung Kim fprintf(fp, "\n"); 770f3705b06SJiri Olsa } 7717ccf4f90SNamhyung Kim 7727ccf4f90SNamhyung Kim if (sep) 773f3705b06SJiri Olsa return hpp_list->nr_header_lines; 7747ccf4f90SNamhyung Kim 7755395a048SJiri Olsa first = true; 7765395a048SJiri Olsa 777ea251d51SNamhyung Kim fprintf(fp, "# "); 778ea251d51SNamhyung Kim 779f0786af5SJiri Olsa hists__for_each_format(hists, fmt) { 7801240005eSJiri Olsa unsigned int i; 781ea251d51SNamhyung Kim 782361459f1SNamhyung Kim if (perf_hpp__should_skip(fmt, hists)) 783e67d49a7SNamhyung Kim continue; 784e67d49a7SNamhyung Kim 7855395a048SJiri Olsa if (!first) 786ea251d51SNamhyung Kim fprintf(fp, "%s", sep ?: " "); 7875395a048SJiri Olsa else 7885395a048SJiri Olsa first = false; 789ea251d51SNamhyung Kim 790da1b0407SJiri Olsa width = fmt->width(fmt, hpp, hists); 791ea251d51SNamhyung Kim for (i = 0; i < width; i++) 792ea251d51SNamhyung Kim fprintf(fp, "."); 7937ccf4f90SNamhyung Kim } 794ea251d51SNamhyung Kim 7957ccf4f90SNamhyung Kim fprintf(fp, "\n"); 7967ccf4f90SNamhyung Kim fprintf(fp, "#\n"); 797f3705b06SJiri Olsa return hpp_list->nr_header_lines + 2; 79836592ebbSJiri Olsa } 79936592ebbSJiri Olsa 8002d831454SJiri Olsa int hists__fprintf_headers(struct hists *hists, FILE *fp) 8017a72a2e5SJiri Olsa { 802d5278220SJiri Olsa char bf[1024]; 8037a72a2e5SJiri Olsa struct perf_hpp dummy_hpp = { 8047a72a2e5SJiri Olsa .buf = bf, 8057a72a2e5SJiri Olsa .size = sizeof(bf), 8067a72a2e5SJiri Olsa }; 8077a72a2e5SJiri Olsa 8087a72a2e5SJiri Olsa fprintf(fp, "# "); 8097a72a2e5SJiri Olsa 8107a72a2e5SJiri Olsa if (symbol_conf.report_hierarchy) 8117a72a2e5SJiri Olsa return hists__fprintf_hierarchy_headers(hists, &dummy_hpp, fp); 8127a72a2e5SJiri Olsa else 8137a72a2e5SJiri Olsa return hists__fprintf_standard_headers(hists, &dummy_hpp, fp); 8147a72a2e5SJiri Olsa 8157a72a2e5SJiri Olsa } 8167a72a2e5SJiri Olsa 81736592ebbSJiri Olsa size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, 818d05e3aaeSJiri Olsa int max_cols, float min_pcnt, FILE *fp, 819e9de7e2fSArnaldo Carvalho de Melo bool ignore_callchains) 82036592ebbSJiri Olsa { 82136592ebbSJiri Olsa struct rb_node *nd; 82236592ebbSJiri Olsa size_t ret = 0; 82336592ebbSJiri Olsa const char *sep = symbol_conf.field_sep; 82436592ebbSJiri Olsa int nr_rows = 0; 82536592ebbSJiri Olsa size_t linesz; 82636592ebbSJiri Olsa char *line = NULL; 82736592ebbSJiri Olsa unsigned indent; 82836592ebbSJiri Olsa 82936592ebbSJiri Olsa init_rem_hits(); 83036592ebbSJiri Olsa 831e3b60bc9SNamhyung Kim hists__reset_column_width(hists); 83236592ebbSJiri Olsa 83336592ebbSJiri Olsa if (symbol_conf.col_width_list_str) 83436592ebbSJiri Olsa perf_hpp__set_user_width(symbol_conf.col_width_list_str); 83536592ebbSJiri Olsa 83636592ebbSJiri Olsa if (show_header) 83736592ebbSJiri Olsa nr_rows += hists__fprintf_headers(hists, fp); 83836592ebbSJiri Olsa 83936592ebbSJiri Olsa if (max_rows && nr_rows >= max_rows) 8407ccf4f90SNamhyung Kim goto out; 8417ccf4f90SNamhyung Kim 84299cf666cSArnaldo Carvalho de Melo linesz = hists__sort_list_width(hists) + 3 + 1; 8439754c4f9SJiri Olsa linesz += perf_hpp__color_overhead(); 84499cf666cSArnaldo Carvalho de Melo line = malloc(linesz); 84599cf666cSArnaldo Carvalho de Melo if (line == NULL) { 84699cf666cSArnaldo Carvalho de Melo ret = -1; 84799cf666cSArnaldo Carvalho de Melo goto out; 84899cf666cSArnaldo Carvalho de Melo } 84999cf666cSArnaldo Carvalho de Melo 850bd4abd39SNamhyung Kim indent = hists__overhead_width(hists) + 4; 851bd4abd39SNamhyung Kim 8522eb3d689SDavidlohr Bueso for (nd = rb_first_cached(&hists->entries); nd; 8532eb3d689SDavidlohr Bueso nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD)) { 8547ccf4f90SNamhyung Kim struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 85514135663SNamhyung Kim float percent; 8567ccf4f90SNamhyung Kim 8577ccf4f90SNamhyung Kim if (h->filtered) 8587ccf4f90SNamhyung Kim continue; 8597ccf4f90SNamhyung Kim 8600b49f836SJin Yao if (symbol_conf.report_individual_block) 8610b49f836SJin Yao percent = block_info__total_cycles_percent(h); 8620b49f836SJin Yao else 86314135663SNamhyung Kim percent = hist_entry__get_percent_limit(h); 8640b49f836SJin Yao 865064f1981SNamhyung Kim if (percent < min_pcnt) 866064f1981SNamhyung Kim continue; 867064f1981SNamhyung Kim 868e9de7e2fSArnaldo Carvalho de Melo ret += hist_entry__fprintf(h, max_cols, line, linesz, fp, ignore_callchains); 8697ccf4f90SNamhyung Kim 8707ccf4f90SNamhyung Kim if (max_rows && ++nr_rows >= max_rows) 87199cf666cSArnaldo Carvalho de Melo break; 8727ccf4f90SNamhyung Kim 873bd4abd39SNamhyung Kim /* 874bd4abd39SNamhyung Kim * If all children are filtered out or percent-limited, 875bd4abd39SNamhyung Kim * display "no entry >= x.xx%" message. 876bd4abd39SNamhyung Kim */ 877bd4abd39SNamhyung Kim if (!h->leaf && !hist_entry__has_hierarchy_children(h, min_pcnt)) { 878f58c95e3SNamhyung Kim int depth = hists->nr_hpp_node + h->depth + 1; 879bd4abd39SNamhyung Kim 880b598c34fSArnaldo Carvalho de Melo print_hierarchy_indent(sep, depth, " ", fp); 881bd4abd39SNamhyung Kim fprintf(fp, "%*sno entry >= %.2f%%\n", indent, "", min_pcnt); 882bd4abd39SNamhyung Kim 883bd4abd39SNamhyung Kim if (max_rows && ++nr_rows >= max_rows) 884bd4abd39SNamhyung Kim break; 885bd4abd39SNamhyung Kim } 886bd4abd39SNamhyung Kim 8877ccf4f90SNamhyung Kim if (h->ms.map == NULL && verbose > 1) { 888*ee84a303SIan Rogers maps__fprintf(thread__maps(h->thread), fp); 8897ccf4f90SNamhyung Kim fprintf(fp, "%.10s end\n", graph_dotted_line); 8907ccf4f90SNamhyung Kim } 8917ccf4f90SNamhyung Kim } 89299cf666cSArnaldo Carvalho de Melo 89399cf666cSArnaldo Carvalho de Melo free(line); 8947ccf4f90SNamhyung Kim out: 89574cf249dSArnaldo Carvalho de Melo zfree(&rem_sq_bracket); 8967ccf4f90SNamhyung Kim 8977ccf4f90SNamhyung Kim return ret; 8987ccf4f90SNamhyung Kim } 8997ccf4f90SNamhyung Kim 9002775de0bSNamhyung Kim size_t events_stats__fprintf(struct events_stats *stats, FILE *fp, 9012775de0bSNamhyung Kim bool skip_empty) 9027ccf4f90SNamhyung Kim { 9037ccf4f90SNamhyung Kim int i; 9047ccf4f90SNamhyung Kim size_t ret = 0; 905462f57dbSNamhyung Kim u32 total = stats->nr_events[0]; 9067ccf4f90SNamhyung Kim 9077ccf4f90SNamhyung Kim for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { 9087ccf4f90SNamhyung Kim const char *name; 9097ccf4f90SNamhyung Kim 9107ccf4f90SNamhyung Kim name = perf_event__name(i); 9117ccf4f90SNamhyung Kim if (!strcmp(name, "UNKNOWN")) 9127ccf4f90SNamhyung Kim continue; 9132775de0bSNamhyung Kim if (skip_empty && !stats->nr_events[i]) 9142775de0bSNamhyung Kim continue; 9157ccf4f90SNamhyung Kim 916462f57dbSNamhyung Kim if (i && total) { 917462f57dbSNamhyung Kim ret += fprintf(fp, "%16s events: %10d (%4.1f%%)\n", 918462f57dbSNamhyung Kim name, stats->nr_events[i], 919462f57dbSNamhyung Kim 100.0 * stats->nr_events[i] / total); 920462f57dbSNamhyung Kim } else { 921462f57dbSNamhyung Kim ret += fprintf(fp, "%16s events: %10d\n", 922462f57dbSNamhyung Kim name, stats->nr_events[i]); 923462f57dbSNamhyung Kim } 9247ccf4f90SNamhyung Kim } 9257ccf4f90SNamhyung Kim 9267ccf4f90SNamhyung Kim return ret; 9277ccf4f90SNamhyung Kim } 928