xref: /linux/tools/perf/ui/stdio/hist.c (revision b10ba7f1a278ce04d272b2b662f231552ab000ee)
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