brintos

brintos / linux-shallow public Read only

0
0
Text · 21.6 KiB · 74b2c61 Raw
927 lines · c
1// SPDX-License-Identifier: GPL-2.02#include <stdio.h>3#include <stdlib.h>4#include <linux/string.h>5 6#include "../../util/callchain.h"7#include "../../util/debug.h"8#include "../../util/event.h"9#include "../../util/hist.h"10#include "../../util/map.h"11#include "../../util/maps.h"12#include "../../util/symbol.h"13#include "../../util/sort.h"14#include "../../util/evsel.h"15#include "../../util/srcline.h"16#include "../../util/string2.h"17#include "../../util/thread.h"18#include "../../util/block-info.h"19#include <linux/ctype.h>20#include <linux/zalloc.h>21 22static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)23{24	int i;25	int ret = fprintf(fp, "            ");26 27	for (i = 0; i < left_margin; i++)28		ret += fprintf(fp, " ");29 30	return ret;31}32 33static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,34					  int left_margin)35{36	int i;37	size_t ret = callchain__fprintf_left_margin(fp, left_margin);38 39	for (i = 0; i < depth; i++)40		if (depth_mask & (1 << i))41			ret += fprintf(fp, "|          ");42		else43			ret += fprintf(fp, "           ");44 45	ret += fprintf(fp, "\n");46 47	return ret;48}49 50static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_node *node,51				     struct callchain_list *chain,52				     int depth, int depth_mask, int period,53				     u64 total_samples, int left_margin)54{55	int i;56	size_t ret = 0;57	char bf[1024], *alloc_str = NULL;58	char buf[64];59	const char *str;60 61	ret += callchain__fprintf_left_margin(fp, left_margin);62	for (i = 0; i < depth; i++) {63		if (depth_mask & (1 << i))64			ret += fprintf(fp, "|");65		else66			ret += fprintf(fp, " ");67		if (!period && i == depth - 1) {68			ret += fprintf(fp, "--");69			ret += callchain_node__fprintf_value(node, fp, total_samples);70			ret += fprintf(fp, "--");71		} else72			ret += fprintf(fp, "%s", "          ");73	}74 75	str = callchain_list__sym_name(chain, bf, sizeof(bf), false);76 77	if (symbol_conf.show_branchflag_count) {78		callchain_list_counts__printf_value(chain, NULL,79						    buf, sizeof(buf));80 81		if (asprintf(&alloc_str, "%s%s", str, buf) < 0)82			str = "Not enough memory!";83		else84			str = alloc_str;85	}86 87	fputs(str, fp);88	fputc('\n', fp);89	free(alloc_str);90 91	return ret;92}93 94static struct symbol *rem_sq_bracket;95static struct callchain_list rem_hits;96 97static void init_rem_hits(void)98{99	rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);100	if (!rem_sq_bracket) {101		fprintf(stderr, "Not enough memory to display remaining hits\n");102		return;103	}104 105	strcpy(rem_sq_bracket->name, "[...]");106	rem_hits.ms.sym = rem_sq_bracket;107}108 109static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root,110					 u64 total_samples, int depth,111					 int depth_mask, int left_margin)112{113	struct rb_node *node, *next;114	struct callchain_node *child = NULL;115	struct callchain_list *chain;116	int new_depth_mask = depth_mask;117	u64 remaining;118	size_t ret = 0;119	int i;120	uint entries_printed = 0;121	int cumul_count = 0;122 123	remaining = total_samples;124 125	node = rb_first(root);126	while (node) {127		u64 new_total;128		u64 cumul;129 130		child = rb_entry(node, struct callchain_node, rb_node);131		cumul = callchain_cumul_hits(child);132		remaining -= cumul;133		cumul_count += callchain_cumul_counts(child);134 135		/*136		 * The depth mask manages the output of pipes that show137		 * the depth. We don't want to keep the pipes of the current138		 * level for the last child of this depth.139		 * Except if we have remaining filtered hits. They will140		 * supersede the last child141		 */142		next = rb_next(node);143		if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))144			new_depth_mask &= ~(1 << (depth - 1));145 146		/*147		 * But we keep the older depth mask for the line separator148		 * to keep the level link until we reach the last child149		 */150		ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,151						   left_margin);152		i = 0;153		list_for_each_entry(chain, &child->val, list) {154			ret += ipchain__fprintf_graph(fp, child, chain, depth,155						      new_depth_mask, i++,156						      total_samples,157						      left_margin);158		}159 160		if (callchain_param.mode == CHAIN_GRAPH_REL)161			new_total = child->children_hit;162		else163			new_total = total_samples;164 165		ret += __callchain__fprintf_graph(fp, &child->rb_root, new_total,166						  depth + 1,167						  new_depth_mask | (1 << depth),168						  left_margin);169		node = next;170		if (++entries_printed == callchain_param.print_limit)171			break;172	}173 174	if (callchain_param.mode == CHAIN_GRAPH_REL &&175		remaining && remaining != total_samples) {176		struct callchain_node rem_node = {177			.hit = remaining,178		};179 180		if (!rem_sq_bracket)181			return ret;182 183		if (callchain_param.value == CCVAL_COUNT && child && child->parent) {184			rem_node.count = child->parent->children_count - cumul_count;185			if (rem_node.count <= 0)186				return ret;187		}188 189		new_depth_mask &= ~(1 << (depth - 1));190		ret += ipchain__fprintf_graph(fp, &rem_node, &rem_hits, depth,191					      new_depth_mask, 0, total_samples,192					      left_margin);193	}194 195	return ret;196}197 198/*199 * If have one single callchain root, don't bother printing200 * its percentage (100 % in fractal mode and the same percentage201 * than the hist in graph mode). This also avoid one level of column.202 *203 * However when percent-limit applied, it's possible that single callchain204 * node have different (non-100% in fractal mode) percentage.205 */206static bool need_percent_display(struct rb_node *node, u64 parent_samples)207{208	struct callchain_node *cnode;209 210	if (rb_next(node))211		return true;212 213	cnode = rb_entry(node, struct callchain_node, rb_node);214	return callchain_cumul_hits(cnode) != parent_samples;215}216 217static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,218				       u64 total_samples, u64 parent_samples,219				       int left_margin)220{221	struct callchain_node *cnode;222	struct callchain_list *chain;223	u32 entries_printed = 0;224	bool printed = false;225	struct rb_node *node;226	int i = 0;227	int ret = 0;228	char bf[1024];229 230	node = rb_first(root);231	if (node && !need_percent_display(node, parent_samples)) {232		cnode = rb_entry(node, struct callchain_node, rb_node);233		list_for_each_entry(chain, &cnode->val, list) {234			/*235			 * If we sort by symbol, the first entry is the same than236			 * the symbol. No need to print it otherwise it appears as237			 * displayed twice.238			 */239			if (!i++ && field_order == NULL &&240			    sort_order && strstarts(sort_order, "sym"))241				continue;242 243			if (!printed) {244				ret += callchain__fprintf_left_margin(fp, left_margin);245				ret += fprintf(fp, "|\n");246				ret += callchain__fprintf_left_margin(fp, left_margin);247				ret += fprintf(fp, "---");248				left_margin += 3;249				printed = true;250			} else251				ret += callchain__fprintf_left_margin(fp, left_margin);252 253			ret += fprintf(fp, "%s",254				       callchain_list__sym_name(chain, bf,255								sizeof(bf),256								false));257 258			if (symbol_conf.show_branchflag_count)259				ret += callchain_list_counts__printf_value(260						chain, fp, NULL, 0);261			ret += fprintf(fp, "\n");262 263			if (++entries_printed == callchain_param.print_limit)264				break;265		}266		root = &cnode->rb_root;267	}268 269	if (callchain_param.mode == CHAIN_GRAPH_REL)270		total_samples = parent_samples;271 272	ret += __callchain__fprintf_graph(fp, root, total_samples,273					  1, 1, left_margin);274	if (ret) {275		/* do not add a blank line if it printed nothing */276		ret += fprintf(fp, "\n");277	}278 279	return ret;280}281 282static size_t __callchain__fprintf_flat(FILE *fp, struct callchain_node *node,283					u64 total_samples)284{285	struct callchain_list *chain;286	size_t ret = 0;287	char bf[1024];288 289	if (!node)290		return 0;291 292	ret += __callchain__fprintf_flat(fp, node->parent, total_samples);293 294 295	list_for_each_entry(chain, &node->val, list) {296		if (chain->ip >= PERF_CONTEXT_MAX)297			continue;298		ret += fprintf(fp, "                %s\n", callchain_list__sym_name(chain,299					bf, sizeof(bf), false));300	}301 302	return ret;303}304 305static size_t callchain__fprintf_flat(FILE *fp, struct rb_root *tree,306				      u64 total_samples)307{308	size_t ret = 0;309	u32 entries_printed = 0;310	struct callchain_node *chain;311	struct rb_node *rb_node = rb_first(tree);312 313	while (rb_node) {314		chain = rb_entry(rb_node, struct callchain_node, rb_node);315 316		ret += fprintf(fp, "           ");317		ret += callchain_node__fprintf_value(chain, fp, total_samples);318		ret += fprintf(fp, "\n");319		ret += __callchain__fprintf_flat(fp, chain, total_samples);320		ret += fprintf(fp, "\n");321		if (++entries_printed == callchain_param.print_limit)322			break;323 324		rb_node = rb_next(rb_node);325	}326 327	return ret;328}329 330static size_t __callchain__fprintf_folded(FILE *fp, struct callchain_node *node)331{332	const char *sep = symbol_conf.field_sep ?: ";";333	struct callchain_list *chain;334	size_t ret = 0;335	char bf[1024];336	bool first;337 338	if (!node)339		return 0;340 341	ret += __callchain__fprintf_folded(fp, node->parent);342 343	first = (ret == 0);344	list_for_each_entry(chain, &node->val, list) {345		if (chain->ip >= PERF_CONTEXT_MAX)346			continue;347		ret += fprintf(fp, "%s%s", first ? "" : sep,348			       callchain_list__sym_name(chain,349						bf, sizeof(bf), false));350		first = false;351	}352 353	return ret;354}355 356static size_t callchain__fprintf_folded(FILE *fp, struct rb_root *tree,357					u64 total_samples)358{359	size_t ret = 0;360	u32 entries_printed = 0;361	struct callchain_node *chain;362	struct rb_node *rb_node = rb_first(tree);363 364	while (rb_node) {365 366		chain = rb_entry(rb_node, struct callchain_node, rb_node);367 368		ret += callchain_node__fprintf_value(chain, fp, total_samples);369		ret += fprintf(fp, " ");370		ret += __callchain__fprintf_folded(fp, chain);371		ret += fprintf(fp, "\n");372		if (++entries_printed == callchain_param.print_limit)373			break;374 375		rb_node = rb_next(rb_node);376	}377 378	return ret;379}380 381static size_t hist_entry_callchain__fprintf(struct hist_entry *he,382					    u64 total_samples, int left_margin,383					    FILE *fp)384{385	u64 parent_samples = he->stat.period;386 387	if (symbol_conf.cumulate_callchain)388		parent_samples = he->stat_acc->period;389 390	switch (callchain_param.mode) {391	case CHAIN_GRAPH_REL:392		return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples,393						parent_samples, left_margin);394		break;395	case CHAIN_GRAPH_ABS:396		return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples,397						parent_samples, left_margin);398		break;399	case CHAIN_FLAT:400		return callchain__fprintf_flat(fp, &he->sorted_chain, total_samples);401		break;402	case CHAIN_FOLDED:403		return callchain__fprintf_folded(fp, &he->sorted_chain, total_samples);404		break;405	case CHAIN_NONE:406		break;407	default:408		pr_err("Bad callchain mode\n");409	}410 411	return 0;412}413 414int __hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp,415			   struct perf_hpp_list *hpp_list)416{417	const char *sep = symbol_conf.field_sep;418	struct perf_hpp_fmt *fmt;419	char *start = hpp->buf;420	int ret;421	bool first = true;422 423	if (symbol_conf.exclude_other && !he->parent)424		return 0;425 426	perf_hpp_list__for_each_format(hpp_list, fmt) {427		if (perf_hpp__should_skip(fmt, he->hists))428			continue;429 430		/*431		 * If there's no field_sep, we still need432		 * to display initial '  '.433		 */434		if (!sep || !first) {435			ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: "  ");436			advance_hpp(hpp, ret);437		} else438			first = false;439 440		if (perf_hpp__use_color() && fmt->color)441			ret = fmt->color(fmt, hpp, he);442		else443			ret = fmt->entry(fmt, hpp, he);444 445		ret = hist_entry__snprintf_alignment(he, hpp, fmt, ret);446		advance_hpp(hpp, ret);447	}448 449	return hpp->buf - start;450}451 452static int hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp)453{454	return __hist_entry__snprintf(he, hpp, he->hists->hpp_list);455}456 457static int hist_entry__hierarchy_fprintf(struct hist_entry *he,458					 struct perf_hpp *hpp,459					 struct hists *hists,460					 FILE *fp)461{462	const char *sep = symbol_conf.field_sep;463	struct perf_hpp_fmt *fmt;464	struct perf_hpp_list_node *fmt_node;465	char *buf = hpp->buf;466	size_t size = hpp->size;467	int ret, printed = 0;468	bool first = true;469 470	if (symbol_conf.exclude_other && !he->parent)471		return 0;472 473	ret = scnprintf(hpp->buf, hpp->size, "%*s", he->depth * HIERARCHY_INDENT, "");474	advance_hpp(hpp, ret);475 476	/* the first hpp_list_node is for overhead columns */477	fmt_node = list_first_entry(&hists->hpp_formats,478				    struct perf_hpp_list_node, list);479	perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {480		/*481		 * If there's no field_sep, we still need482		 * to display initial '  '.483		 */484		if (!sep || !first) {485			ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: "  ");486			advance_hpp(hpp, ret);487		} else488			first = false;489 490		if (perf_hpp__use_color() && fmt->color)491			ret = fmt->color(fmt, hpp, he);492		else493			ret = fmt->entry(fmt, hpp, he);494 495		ret = hist_entry__snprintf_alignment(he, hpp, fmt, ret);496		advance_hpp(hpp, ret);497	}498 499	if (!sep)500		ret = scnprintf(hpp->buf, hpp->size, "%*s",501				(hists->nr_hpp_node - 2) * HIERARCHY_INDENT, "");502	advance_hpp(hpp, ret);503 504	printed += fprintf(fp, "%s", buf);505 506	perf_hpp_list__for_each_format(he->hpp_list, fmt) {507		hpp->buf  = buf;508		hpp->size = size;509 510		/*511		 * No need to call hist_entry__snprintf_alignment() since this512		 * fmt is always the last column in the hierarchy mode.513		 */514		if (perf_hpp__use_color() && fmt->color)515			fmt->color(fmt, hpp, he);516		else517			fmt->entry(fmt, hpp, he);518 519		/*520		 * dynamic entries are right-aligned but we want left-aligned521		 * in the hierarchy mode522		 */523		printed += fprintf(fp, "%s%s", sep ?: "  ", skip_spaces(buf));524	}525	printed += putc('\n', fp);526 527	if (he->leaf && hist_entry__has_callchains(he) && symbol_conf.use_callchain) {528		u64 total = hists__total_period(hists);529 530		printed += hist_entry_callchain__fprintf(he, total, 0, fp);531		goto out;532	}533 534out:535	return printed;536}537 538static int hist_entry__block_fprintf(struct hist_entry *he,539				     char *bf, size_t size,540				     FILE *fp)541{542	struct block_hist *bh = container_of(he, struct block_hist, he);543	int ret = 0;544 545	for (unsigned int i = 0; i < bh->block_hists.nr_entries; i++) {546		struct perf_hpp hpp = {547			.buf		= bf,548			.size		= size,549			.skip		= false,550		};551 552		bh->block_idx = i;553		hist_entry__snprintf(he, &hpp);554 555		if (!hpp.skip)556			ret += fprintf(fp, "%s\n", bf);557	}558 559	return ret;560}561 562static int hist_entry__individual_block_fprintf(struct hist_entry *he,563						char *bf, size_t size,564						FILE *fp)565{566	int ret = 0;567 568	struct perf_hpp hpp = {569		.buf		= bf,570		.size		= size,571		.skip		= false,572	};573 574	hist_entry__snprintf(he, &hpp);575	if (!hpp.skip)576		ret += fprintf(fp, "%s\n", bf);577 578	return ret;579}580 581static int hist_entry__fprintf(struct hist_entry *he, size_t size,582			       char *bf, size_t bfsz, FILE *fp,583			       bool ignore_callchains)584{585	int ret;586	int callchain_ret = 0;587	struct perf_hpp hpp = {588		.buf		= bf,589		.size		= size,590	};591	struct hists *hists = he->hists;592	u64 total_period = hists->stats.total_period;593 594	if (size == 0 || size > bfsz)595		size = hpp.size = bfsz;596 597	if (symbol_conf.report_hierarchy)598		return hist_entry__hierarchy_fprintf(he, &hpp, hists, fp);599 600	if (symbol_conf.report_block)601		return hist_entry__block_fprintf(he, bf, size, fp);602 603	if (symbol_conf.report_individual_block)604		return hist_entry__individual_block_fprintf(he, bf, size, fp);605 606	hist_entry__snprintf(he, &hpp);607 608	ret = fprintf(fp, "%s\n", bf);609 610	if (hist_entry__has_callchains(he) && !ignore_callchains)611		callchain_ret = hist_entry_callchain__fprintf(he, total_period,612							      0, fp);613 614	ret += callchain_ret;615 616	return ret;617}618 619static int print_hierarchy_indent(const char *sep, int indent,620				  const char *line, FILE *fp)621{622	int width;623 624	if (sep != NULL || indent < 2)625		return 0;626 627	width = (indent - 2) * HIERARCHY_INDENT;628 629	return fprintf(fp, "%-*.*s", width, width, line);630}631 632static int hists__fprintf_hierarchy_headers(struct hists *hists,633					    struct perf_hpp *hpp, FILE *fp)634{635	bool first_node, first_col;636	int indent;637	int depth;638	unsigned width = 0;639	unsigned header_width = 0;640	struct perf_hpp_fmt *fmt;641	struct perf_hpp_list_node *fmt_node;642	const char *sep = symbol_conf.field_sep;643 644	indent = hists->nr_hpp_node;645 646	/* preserve max indent depth for column headers */647	print_hierarchy_indent(sep, indent, " ", fp);648 649	/* the first hpp_list_node is for overhead columns */650	fmt_node = list_first_entry(&hists->hpp_formats,651				    struct perf_hpp_list_node, list);652 653	perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {654		fmt->header(fmt, hpp, hists, 0, NULL);655		fprintf(fp, "%s%s", hpp->buf, sep ?: "  ");656	}657 658	/* combine sort headers with ' / ' */659	first_node = true;660	list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {661		if (!first_node)662			header_width += fprintf(fp, " / ");663		first_node = false;664 665		first_col = true;666		perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {667			if (perf_hpp__should_skip(fmt, hists))668				continue;669 670			if (!first_col)671				header_width += fprintf(fp, "+");672			first_col = false;673 674			fmt->header(fmt, hpp, hists, 0, NULL);675 676			header_width += fprintf(fp, "%s", strim(hpp->buf));677		}678	}679 680	fprintf(fp, "\n# ");681 682	/* preserve max indent depth for initial dots */683	print_hierarchy_indent(sep, indent, dots, fp);684 685	/* the first hpp_list_node is for overhead columns */686	fmt_node = list_first_entry(&hists->hpp_formats,687				    struct perf_hpp_list_node, list);688 689	first_col = true;690	perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {691		if (!first_col)692			fprintf(fp, "%s", sep ?: "..");693		first_col = false;694 695		width = fmt->width(fmt, hpp, hists);696		fprintf(fp, "%.*s", width, dots);697	}698 699	depth = 0;700	list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {701		first_col = true;702		width = depth * HIERARCHY_INDENT;703 704		perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {705			if (perf_hpp__should_skip(fmt, hists))706				continue;707 708			if (!first_col)709				width++;  /* for '+' sign between column header */710			first_col = false;711 712			width += fmt->width(fmt, hpp, hists);713		}714 715		if (width > header_width)716			header_width = width;717 718		depth++;719	}720 721	fprintf(fp, "%s%-.*s", sep ?: "  ", header_width, dots);722 723	fprintf(fp, "\n#\n");724 725	return 2;726}727 728static void fprintf_line(struct hists *hists, struct perf_hpp *hpp,729			 int line, FILE *fp)730{731	struct perf_hpp_fmt *fmt;732	const char *sep = symbol_conf.field_sep;733	bool first = true;734	int span = 0;735 736	hists__for_each_format(hists, fmt) {737		if (perf_hpp__should_skip(fmt, hists))738			continue;739 740		if (!first && !span)741			fprintf(fp, "%s", sep ?: "  ");742		else743			first = false;744 745		fmt->header(fmt, hpp, hists, line, &span);746 747		if (!span)748			fprintf(fp, "%s", hpp->buf);749	}750}751 752static int753hists__fprintf_standard_headers(struct hists *hists,754				struct perf_hpp *hpp,755				FILE *fp)756{757	struct perf_hpp_list *hpp_list = hists->hpp_list;758	struct perf_hpp_fmt *fmt;759	unsigned int width;760	const char *sep = symbol_conf.field_sep;761	bool first = true;762	int line;763 764	for (line = 0; line < hpp_list->nr_header_lines; line++) {765		/* first # is displayed one level up */766		if (line)767			fprintf(fp, "# ");768		fprintf_line(hists, hpp, line, fp);769		fprintf(fp, "\n");770	}771 772	if (sep)773		return hpp_list->nr_header_lines;774 775	first = true;776 777	fprintf(fp, "# ");778 779	hists__for_each_format(hists, fmt) {780		unsigned int i;781 782		if (perf_hpp__should_skip(fmt, hists))783			continue;784 785		if (!first)786			fprintf(fp, "%s", sep ?: "  ");787		else788			first = false;789 790		width = fmt->width(fmt, hpp, hists);791		for (i = 0; i < width; i++)792			fprintf(fp, ".");793	}794 795	fprintf(fp, "\n");796	fprintf(fp, "#\n");797	return hpp_list->nr_header_lines + 2;798}799 800int hists__fprintf_headers(struct hists *hists, FILE *fp)801{802	char bf[1024];803	struct perf_hpp dummy_hpp = {804		.buf	= bf,805		.size	= sizeof(bf),806	};807 808	fprintf(fp, "# ");809 810	if (symbol_conf.report_hierarchy)811		return hists__fprintf_hierarchy_headers(hists, &dummy_hpp, fp);812	else813		return hists__fprintf_standard_headers(hists, &dummy_hpp, fp);814 815}816 817size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,818		      int max_cols, float min_pcnt, FILE *fp,819		      bool ignore_callchains)820{821	struct rb_node *nd;822	size_t ret = 0;823	const char *sep = symbol_conf.field_sep;824	int nr_rows = 0;825	size_t linesz;826	char *line = NULL;827	unsigned indent;828 829	init_rem_hits();830 831	hists__reset_column_width(hists);832 833	if (symbol_conf.col_width_list_str)834		perf_hpp__set_user_width(symbol_conf.col_width_list_str);835 836	if (show_header)837		nr_rows += hists__fprintf_headers(hists, fp);838 839	if (max_rows && nr_rows >= max_rows)840		goto out;841 842	linesz = hists__sort_list_width(hists) + 3 + 1;843	linesz += perf_hpp__color_overhead();844	line = malloc(linesz);845	if (line == NULL) {846		ret = -1;847		goto out;848	}849 850	indent = hists__overhead_width(hists) + 4;851 852	for (nd = rb_first_cached(&hists->entries); nd;853	     nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD)) {854		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);855		float percent;856 857		if (h->filtered)858			continue;859 860		if (symbol_conf.report_individual_block)861			percent = block_info__total_cycles_percent(h);862		else863			percent = hist_entry__get_percent_limit(h);864 865		if (percent < min_pcnt)866			continue;867 868		ret += hist_entry__fprintf(h, max_cols, line, linesz, fp, ignore_callchains);869 870		if (max_rows && ++nr_rows >= max_rows)871			break;872 873		/*874		 * If all children are filtered out or percent-limited,875		 * display "no entry >= x.xx%" message.876		 */877		if (!h->leaf && !hist_entry__has_hierarchy_children(h, min_pcnt)) {878			int depth = hists->nr_hpp_node + h->depth + 1;879 880			print_hierarchy_indent(sep, depth, " ", fp);881			fprintf(fp, "%*sno entry >= %.2f%%\n", indent, "", min_pcnt);882 883			if (max_rows && ++nr_rows >= max_rows)884				break;885		}886 887		if (h->ms.map == NULL && verbose > 1) {888			maps__fprintf(thread__maps(h->thread), fp);889			fprintf(fp, "%.10s end\n", graph_dotted_line);890		}891	}892 893	free(line);894out:895	zfree(&rem_sq_bracket);896 897	return ret;898}899 900size_t events_stats__fprintf(struct events_stats *stats, FILE *fp)901{902	int i;903	size_t ret = 0;904	u32 total = stats->nr_events[0];905 906	for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {907		const char *name;908 909		name = perf_event__name(i);910		if (!strcmp(name, "UNKNOWN"))911			continue;912		if (symbol_conf.skip_empty && !stats->nr_events[i])913			continue;914 915		if (i && total) {916			ret += fprintf(fp, "%20s events: %10d  (%4.1f%%)\n",917				       name, stats->nr_events[i],918				       100.0 * stats->nr_events[i] / total);919		} else {920			ret += fprintf(fp, "%20s events: %10d\n",921				       name, stats->nr_events[i]);922		}923	}924 925	return ret;926}927