hist.c 21.8 KB
Newer Older
1 2 3 4 5
#include <stdio.h>

#include "../../util/util.h"
#include "../../util/hist.h"
#include "../../util/sort.h"
6
#include "../../util/evsel.h"
7 8 9 10 11 12 13 14 15 16 17 18 19


static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
{
	int i;
	int ret = fprintf(fp, "            ");

	for (i = 0; i < left_margin; i++)
		ret += fprintf(fp, " ");

	return ret;
}

20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
static size_t inline__fprintf(struct map *map, u64 ip, int left_margin,
			      int depth, int depth_mask, FILE *fp)
{
	struct dso *dso;
	struct inline_node *node;
	struct inline_list *ilist;
	int ret = 0, i;

	if (map == NULL)
		return 0;

	dso = map->dso;
	if (dso == NULL)
		return 0;

	if (dso->kernel != DSO_TYPE_USER)
		return 0;

	node = dso__parse_addr_inlines(dso,
				       map__rip_2objdump(map, ip));
	if (node == NULL)
		return 0;

	list_for_each_entry(ilist, &node->val, list) {
		if ((ilist->filename != NULL) || (ilist->funcname != NULL)) {
			ret += callchain__fprintf_left_margin(fp, left_margin);

			for (i = 0; i < depth; i++) {
				if (depth_mask & (1 << i))
					ret += fprintf(fp, "|");
				else
					ret += fprintf(fp, " ");
				ret += fprintf(fp, "          ");
			}

			if (callchain_param.key == CCKEY_ADDRESS) {
				if (ilist->filename != NULL)
					ret += fprintf(fp, "%s:%d (inline)",
						       ilist->filename,
						       ilist->line_nr);
				else
					ret += fprintf(fp, "??");
			} else if (ilist->funcname != NULL)
				ret += fprintf(fp, "%s (inline)",
					       ilist->funcname);
			else if (ilist->filename != NULL)
				ret += fprintf(fp, "%s:%d (inline)",
					       ilist->filename,
					       ilist->line_nr);
			else
				ret += fprintf(fp, "??");

			ret += fprintf(fp, "\n");
		}
	}

	inline_node__delete(node);
	return ret;
}

80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
					  int left_margin)
{
	int i;
	size_t ret = callchain__fprintf_left_margin(fp, left_margin);

	for (i = 0; i < depth; i++)
		if (depth_mask & (1 << i))
			ret += fprintf(fp, "|          ");
		else
			ret += fprintf(fp, "           ");

	ret += fprintf(fp, "\n");

	return ret;
}

97 98
static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_node *node,
				     struct callchain_list *chain,
99
				     int depth, int depth_mask, int period,
100
				     u64 total_samples, int left_margin)
101 102 103
{
	int i;
	size_t ret = 0;
104 105 106
	char bf[1024], *alloc_str = NULL;
	char buf[64];
	const char *str;
107 108 109 110 111 112 113 114

	ret += callchain__fprintf_left_margin(fp, left_margin);
	for (i = 0; i < depth; i++) {
		if (depth_mask & (1 << i))
			ret += fprintf(fp, "|");
		else
			ret += fprintf(fp, " ");
		if (!period && i == depth - 1) {
115 116 117
			ret += fprintf(fp, "--");
			ret += callchain_node__fprintf_value(node, fp, total_samples);
			ret += fprintf(fp, "--");
118 119 120
		} else
			ret += fprintf(fp, "%s", "          ");
	}
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138

	str = callchain_list__sym_name(chain, bf, sizeof(bf), false);

	if (symbol_conf.show_branchflag_count) {
		if (!period)
			callchain_list_counts__printf_value(node, chain, NULL,
							    buf, sizeof(buf));
		else
			callchain_list_counts__printf_value(NULL, chain, NULL,
							    buf, sizeof(buf));

		if (asprintf(&alloc_str, "%s%s", str, buf) < 0)
			str = "Not enough memory!";
		else
			str = alloc_str;
	}

	fputs(str, fp);
139
	fputc('\n', fp);
140
	free(alloc_str);
141 142 143 144

	if (symbol_conf.inline_name)
		ret += inline__fprintf(chain->ms.map, chain->ip,
				       left_margin, depth, depth_mask, fp);
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
	return ret;
}

static struct symbol *rem_sq_bracket;
static struct callchain_list rem_hits;

static void init_rem_hits(void)
{
	rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
	if (!rem_sq_bracket) {
		fprintf(stderr, "Not enough memory to display remaining hits\n");
		return;
	}

	strcpy(rem_sq_bracket->name, "[...]");
	rem_hits.ms.sym = rem_sq_bracket;
}

static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root,
					 u64 total_samples, int depth,
					 int depth_mask, int left_margin)
{
	struct rb_node *node, *next;
168
	struct callchain_node *child = NULL;
169 170 171 172 173 174
	struct callchain_list *chain;
	int new_depth_mask = depth_mask;
	u64 remaining;
	size_t ret = 0;
	int i;
	uint entries_printed = 0;
175
	int cumul_count = 0;
176 177 178 179 180 181 182 183 184 185 186

	remaining = total_samples;

	node = rb_first(root);
	while (node) {
		u64 new_total;
		u64 cumul;

		child = rb_entry(node, struct callchain_node, rb_node);
		cumul = callchain_cumul_hits(child);
		remaining -= cumul;
187
		cumul_count += callchain_cumul_counts(child);
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207

		/*
		 * The depth mask manages the output of pipes that show
		 * the depth. We don't want to keep the pipes of the current
		 * level for the last child of this depth.
		 * Except if we have remaining filtered hits. They will
		 * supersede the last child
		 */
		next = rb_next(node);
		if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
			new_depth_mask &= ~(1 << (depth - 1));

		/*
		 * But we keep the older depth mask for the line separator
		 * to keep the level link until we reach the last child
		 */
		ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
						   left_margin);
		i = 0;
		list_for_each_entry(chain, &child->val, list) {
208
			ret += ipchain__fprintf_graph(fp, child, chain, depth,
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
						      new_depth_mask, i++,
						      total_samples,
						      left_margin);
		}

		if (callchain_param.mode == CHAIN_GRAPH_REL)
			new_total = child->children_hit;
		else
			new_total = total_samples;

		ret += __callchain__fprintf_graph(fp, &child->rb_root, new_total,
						  depth + 1,
						  new_depth_mask | (1 << depth),
						  left_margin);
		node = next;
		if (++entries_printed == callchain_param.print_limit)
			break;
	}

	if (callchain_param.mode == CHAIN_GRAPH_REL &&
		remaining && remaining != total_samples) {
230 231 232
		struct callchain_node rem_node = {
			.hit = remaining,
		};
233 234 235 236

		if (!rem_sq_bracket)
			return ret;

237 238 239 240 241 242
		if (callchain_param.value == CCVAL_COUNT && child && child->parent) {
			rem_node.count = child->parent->children_count - cumul_count;
			if (rem_node.count <= 0)
				return ret;
		}

243
		new_depth_mask &= ~(1 << (depth - 1));
244
		ret += ipchain__fprintf_graph(fp, &rem_node, &rem_hits, depth,
245
					      new_depth_mask, 0, total_samples,
246
					      left_margin);
247 248 249 250 251
	}

	return ret;
}

252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
/*
 * If have one single callchain root, don't bother printing
 * its percentage (100 % in fractal mode and the same percentage
 * than the hist in graph mode). This also avoid one level of column.
 *
 * However when percent-limit applied, it's possible that single callchain
 * node have different (non-100% in fractal mode) percentage.
 */
static bool need_percent_display(struct rb_node *node, u64 parent_samples)
{
	struct callchain_node *cnode;

	if (rb_next(node))
		return true;

	cnode = rb_entry(node, struct callchain_node, rb_node);
	return callchain_cumul_hits(cnode) != parent_samples;
}

271
static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
272 273
				       u64 total_samples, u64 parent_samples,
				       int left_margin)
274 275 276 277 278 279 280 281
{
	struct callchain_node *cnode;
	struct callchain_list *chain;
	u32 entries_printed = 0;
	bool printed = false;
	struct rb_node *node;
	int i = 0;
	int ret = 0;
282
	char bf[1024];
283 284

	node = rb_first(root);
285
	if (node && !need_percent_display(node, parent_samples)) {
286 287 288 289 290 291 292
		cnode = rb_entry(node, struct callchain_node, rb_node);
		list_for_each_entry(chain, &cnode->val, list) {
			/*
			 * If we sort by symbol, the first entry is the same than
			 * the symbol. No need to print it otherwise it appears as
			 * displayed twice.
			 */
293 294
			if (!i++ && field_order == NULL &&
			    sort_order && !prefixcmp(sort_order, "sym"))
295
				continue;
296

297 298 299 300 301 302 303 304 305 306
			if (!printed) {
				ret += callchain__fprintf_left_margin(fp, left_margin);
				ret += fprintf(fp, "|\n");
				ret += callchain__fprintf_left_margin(fp, left_margin);
				ret += fprintf(fp, "---");
				left_margin += 3;
				printed = true;
			} else
				ret += callchain__fprintf_left_margin(fp, left_margin);

307 308 309 310 311 312 313 314 315
			ret += fprintf(fp, "%s",
				       callchain_list__sym_name(chain, bf,
								sizeof(bf),
								false));

			if (symbol_conf.show_branchflag_count)
				ret += callchain_list_counts__printf_value(
						NULL, chain, fp, NULL, 0);
			ret += fprintf(fp, "\n");
316 317 318

			if (++entries_printed == callchain_param.print_limit)
				break;
319 320 321 322 323 324 325

			if (symbol_conf.inline_name)
				ret += inline__fprintf(chain->ms.map,
						       chain->ip,
						       left_margin,
						       0, 0,
						       fp);
326 327 328 329
		}
		root = &cnode->rb_root;
	}

330 331 332
	if (callchain_param.mode == CHAIN_GRAPH_REL)
		total_samples = parent_samples;

333 334
	ret += __callchain__fprintf_graph(fp, root, total_samples,
					  1, 1, left_margin);
335 336 337 338
	if (ret) {
		/* do not add a blank line if it printed nothing */
		ret += fprintf(fp, "\n");
	}
339 340 341 342

	return ret;
}

343
static size_t __callchain__fprintf_flat(FILE *fp, struct callchain_node *node,
344 345 346 347
					u64 total_samples)
{
	struct callchain_list *chain;
	size_t ret = 0;
348
	char bf[1024];
349

350
	if (!node)
351 352
		return 0;

353
	ret += __callchain__fprintf_flat(fp, node->parent, total_samples);
354 355


356
	list_for_each_entry(chain, &node->val, list) {
357 358
		if (chain->ip >= PERF_CONTEXT_MAX)
			continue;
359 360
		ret += fprintf(fp, "                %s\n", callchain_list__sym_name(chain,
					bf, sizeof(bf), false));
361 362 363 364 365
	}

	return ret;
}

366
static size_t callchain__fprintf_flat(FILE *fp, struct rb_root *tree,
367 368 369 370 371
				      u64 total_samples)
{
	size_t ret = 0;
	u32 entries_printed = 0;
	struct callchain_node *chain;
372
	struct rb_node *rb_node = rb_first(tree);
373 374 375 376

	while (rb_node) {
		chain = rb_entry(rb_node, struct callchain_node, rb_node);

377 378 379
		ret += fprintf(fp, "           ");
		ret += callchain_node__fprintf_value(chain, fp, total_samples);
		ret += fprintf(fp, "\n");
380 381 382 383 384 385 386 387 388 389 390
		ret += __callchain__fprintf_flat(fp, chain, total_samples);
		ret += fprintf(fp, "\n");
		if (++entries_printed == callchain_param.print_limit)
			break;

		rb_node = rb_next(rb_node);
	}

	return ret;
}

391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428
static size_t __callchain__fprintf_folded(FILE *fp, struct callchain_node *node)
{
	const char *sep = symbol_conf.field_sep ?: ";";
	struct callchain_list *chain;
	size_t ret = 0;
	char bf[1024];
	bool first;

	if (!node)
		return 0;

	ret += __callchain__fprintf_folded(fp, node->parent);

	first = (ret == 0);
	list_for_each_entry(chain, &node->val, list) {
		if (chain->ip >= PERF_CONTEXT_MAX)
			continue;
		ret += fprintf(fp, "%s%s", first ? "" : sep,
			       callchain_list__sym_name(chain,
						bf, sizeof(bf), false));
		first = false;
	}

	return ret;
}

static size_t callchain__fprintf_folded(FILE *fp, struct rb_root *tree,
					u64 total_samples)
{
	size_t ret = 0;
	u32 entries_printed = 0;
	struct callchain_node *chain;
	struct rb_node *rb_node = rb_first(tree);

	while (rb_node) {

		chain = rb_entry(rb_node, struct callchain_node, rb_node);

429 430
		ret += callchain_node__fprintf_value(chain, fp, total_samples);
		ret += fprintf(fp, " ");
431 432 433 434 435 436 437 438 439 440 441
		ret += __callchain__fprintf_folded(fp, chain);
		ret += fprintf(fp, "\n");
		if (++entries_printed == callchain_param.print_limit)
			break;

		rb_node = rb_next(rb_node);
	}

	return ret;
}

442 443 444 445
static size_t hist_entry_callchain__fprintf(struct hist_entry *he,
					    u64 total_samples, int left_margin,
					    FILE *fp)
{
446 447 448 449 450
	u64 parent_samples = he->stat.period;

	if (symbol_conf.cumulate_callchain)
		parent_samples = he->stat_acc->period;

451 452
	switch (callchain_param.mode) {
	case CHAIN_GRAPH_REL:
453 454
		return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples,
						parent_samples, left_margin);
455 456 457
		break;
	case CHAIN_GRAPH_ABS:
		return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples,
458
						parent_samples, left_margin);
459 460 461 462
		break;
	case CHAIN_FLAT:
		return callchain__fprintf_flat(fp, &he->sorted_chain, total_samples);
		break;
463 464 465
	case CHAIN_FOLDED:
		return callchain__fprintf_folded(fp, &he->sorted_chain, total_samples);
		break;
466 467 468 469 470 471 472 473 474
	case CHAIN_NONE:
		break;
	default:
		pr_err("Bad callchain mode\n");
	}

	return 0;
}

475 476
int __hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp,
			   struct perf_hpp_list *hpp_list)
477 478 479 480 481 482 483 484 485 486
{
	const char *sep = symbol_conf.field_sep;
	struct perf_hpp_fmt *fmt;
	char *start = hpp->buf;
	int ret;
	bool first = true;

	if (symbol_conf.exclude_other && !he->parent)
		return 0;

487
	perf_hpp_list__for_each_format(hpp_list, fmt) {
488
		if (perf_hpp__should_skip(fmt, he->hists))
489 490
			continue;

491 492 493 494 495 496 497 498 499 500
		/*
		 * If there's no field_sep, we still need
		 * to display initial '  '.
		 */
		if (!sep || !first) {
			ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: "  ");
			advance_hpp(hpp, ret);
		} else
			first = false;

501
		if (perf_hpp__use_color() && fmt->color)
502 503 504 505
			ret = fmt->color(fmt, hpp, he);
		else
			ret = fmt->entry(fmt, hpp, he);

506
		ret = hist_entry__snprintf_alignment(he, hpp, fmt, ret);
507 508 509 510 511 512
		advance_hpp(hpp, ret);
	}

	return hpp->buf - start;
}

513 514 515 516 517
static int hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp)
{
	return __hist_entry__snprintf(he, hpp, he->hists->hpp_list);
}

518 519
static int hist_entry__hierarchy_fprintf(struct hist_entry *he,
					 struct perf_hpp *hpp,
520
					 struct hists *hists,
521 522 523 524
					 FILE *fp)
{
	const char *sep = symbol_conf.field_sep;
	struct perf_hpp_fmt *fmt;
525
	struct perf_hpp_list_node *fmt_node;
526
	char *buf = hpp->buf;
527
	size_t size = hpp->size;
528 529 530 531 532 533 534 535 536
	int ret, printed = 0;
	bool first = true;

	if (symbol_conf.exclude_other && !he->parent)
		return 0;

	ret = scnprintf(hpp->buf, hpp->size, "%*s", he->depth * HIERARCHY_INDENT, "");
	advance_hpp(hpp, ret);

537 538 539 540
	/* the first hpp_list_node is for overhead columns */
	fmt_node = list_first_entry(&hists->hpp_formats,
				    struct perf_hpp_list_node, list);
	perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559
		/*
		 * If there's no field_sep, we still need
		 * to display initial '  '.
		 */
		if (!sep || !first) {
			ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: "  ");
			advance_hpp(hpp, ret);
		} else
			first = false;

		if (perf_hpp__use_color() && fmt->color)
			ret = fmt->color(fmt, hpp, he);
		else
			ret = fmt->entry(fmt, hpp, he);

		ret = hist_entry__snprintf_alignment(he, hpp, fmt, ret);
		advance_hpp(hpp, ret);
	}

560
	if (!sep)
561
		ret = scnprintf(hpp->buf, hpp->size, "%*s",
562
				(hists->nr_hpp_node - 2) * HIERARCHY_INDENT, "");
563 564
	advance_hpp(hpp, ret);

565 566
	printed += fprintf(fp, "%s", buf);

567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586
	perf_hpp_list__for_each_format(he->hpp_list, fmt) {
		hpp->buf  = buf;
		hpp->size = size;

		/*
		 * No need to call hist_entry__snprintf_alignment() since this
		 * fmt is always the last column in the hierarchy mode.
		 */
		if (perf_hpp__use_color() && fmt->color)
			fmt->color(fmt, hpp, he);
		else
			fmt->entry(fmt, hpp, he);

		/*
		 * dynamic entries are right-aligned but we want left-aligned
		 * in the hierarchy mode
		 */
		printed += fprintf(fp, "%s%s", sep ?: "  ", ltrim(buf));
	}
	printed += putc('\n', fp);
587 588 589 590 591 592 593 594 595 596 597 598

	if (symbol_conf.use_callchain && he->leaf) {
		u64 total = hists__total_period(hists);

		printed += hist_entry_callchain__fprintf(he, total, 0, fp);
		goto out;
	}

out:
	return printed;
}

599
static int hist_entry__fprintf(struct hist_entry *he, size_t size,
600 601
			       char *bf, size_t bfsz, FILE *fp,
			       bool use_callchain)
602 603
{
	int ret;
604 605
	int callchain_ret = 0;
	int inline_ret = 0;
606 607 608 609
	struct perf_hpp hpp = {
		.buf		= bf,
		.size		= size,
	};
610
	struct hists *hists = he->hists;
611
	u64 total_period = hists->stats.total_period;
612

613 614
	if (size == 0 || size > bfsz)
		size = hpp.size = bfsz;
615

616 617
	if (symbol_conf.report_hierarchy)
		return hist_entry__hierarchy_fprintf(he, &hpp, hists, fp);
618

619
	hist_entry__snprintf(he, &hpp);
620

621
	ret = fprintf(fp, "%s\n", bf);
622

623
	if (use_callchain)
624 625 626 627 628 629 630 631 632 633
		callchain_ret = hist_entry_callchain__fprintf(he, total_period,
							      0, fp);

	if (callchain_ret == 0 && symbol_conf.inline_name) {
		inline_ret = inline__fprintf(he->ms.map, he->ip, 0, 0, 0, fp);
		ret += inline_ret;
		if (inline_ret > 0)
			ret += fprintf(fp, "\n");
	} else
		ret += callchain_ret;
634

635
	return ret;
636 637
}

638
static int print_hierarchy_indent(const char *sep, int indent,
639 640
				  const char *line, FILE *fp)
{
641
	if (sep != NULL || indent < 2)
642 643
		return 0;

644
	return fprintf(fp, "%-.*s", (indent - 2) * HIERARCHY_INDENT, line);
645 646
}

647 648
static int hists__fprintf_hierarchy_headers(struct hists *hists,
					    struct perf_hpp *hpp, FILE *fp)
649
{
650
	bool first_node, first_col;
651
	int indent;
652
	int depth;
653 654 655
	unsigned width = 0;
	unsigned header_width = 0;
	struct perf_hpp_fmt *fmt;
656
	struct perf_hpp_list_node *fmt_node;
657
	const char *sep = symbol_conf.field_sep;
658

659
	indent = hists->nr_hpp_node;
660 661

	/* preserve max indent depth for column headers */
662
	print_hierarchy_indent(sep, indent, spaces, fp);
663

664 665 666
	/* the first hpp_list_node is for overhead columns */
	fmt_node = list_first_entry(&hists->hpp_formats,
				    struct perf_hpp_list_node, list);
667

668
	perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
669
		fmt->header(fmt, hpp, hists, 0, NULL);
670
		fprintf(fp, "%s%s", hpp->buf, sep ?: "  ");
671 672 673
	}

	/* combine sort headers with ' / ' */
674 675 676
	first_node = true;
	list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
		if (!first_node)
677
			header_width += fprintf(fp, " / ");
678
		first_node = false;
679

680 681 682 683 684 685 686 687 688
		first_col = true;
		perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
			if (perf_hpp__should_skip(fmt, hists))
				continue;

			if (!first_col)
				header_width += fprintf(fp, "+");
			first_col = false;

689
			fmt->header(fmt, hpp, hists, 0, NULL);
690

J
Jiri Olsa 已提交
691
			header_width += fprintf(fp, "%s", trim(hpp->buf));
692
		}
693 694 695 696 697
	}

	fprintf(fp, "\n# ");

	/* preserve max indent depth for initial dots */
698
	print_hierarchy_indent(sep, indent, dots, fp);
699

700 701 702
	/* the first hpp_list_node is for overhead columns */
	fmt_node = list_first_entry(&hists->hpp_formats,
				    struct perf_hpp_list_node, list);
703

704 705 706 707 708
	first_col = true;
	perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
		if (!first_col)
			fprintf(fp, "%s", sep ?: "..");
		first_col = false;
709

710
		width = fmt->width(fmt, hpp, hists);
711 712 713
		fprintf(fp, "%.*s", width, dots);
	}

714
	depth = 0;
715 716 717
	list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
		first_col = true;
		width = depth * HIERARCHY_INDENT;
718

719 720 721 722 723 724 725 726
		perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
			if (perf_hpp__should_skip(fmt, hists))
				continue;

			if (!first_col)
				width++;  /* for '+' sign between column header */
			first_col = false;

727
			width += fmt->width(fmt, hpp, hists);
728
		}
729

730 731
		if (width > header_width)
			header_width = width;
732 733

		depth++;
734 735 736 737 738 739 740 741 742
	}

	fprintf(fp, "%s%-.*s", sep ?: "  ", header_width, dots);

	fprintf(fp, "\n#\n");

	return 2;
}

743 744
static void fprintf_line(struct hists *hists, struct perf_hpp *hpp,
			 int line, FILE *fp)
745
{
746
	struct perf_hpp_fmt *fmt;
747
	const char *sep = symbol_conf.field_sep;
748
	bool first = true;
749
	int span = 0;
750

751
	hists__for_each_format(hists, fmt) {
752
		if (perf_hpp__should_skip(fmt, hists))
753 754
			continue;

755
		if (!first && !span)
756 757 758 759
			fprintf(fp, "%s", sep ?: "  ");
		else
			first = false;

760 761 762 763
		fmt->header(fmt, hpp, hists, line, &span);

		if (!span)
			fprintf(fp, "%s", hpp->buf);
764
	}
765
}
766

767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785
static int
hists__fprintf_standard_headers(struct hists *hists,
				struct perf_hpp *hpp,
				FILE *fp)
{
	struct perf_hpp_list *hpp_list = hists->hpp_list;
	struct perf_hpp_fmt *fmt;
	unsigned int width;
	const char *sep = symbol_conf.field_sep;
	bool first = true;
	int line;

	for (line = 0; line < hpp_list->nr_header_lines; line++) {
		/* first # is displayed one level up */
		if (line)
			fprintf(fp, "# ");
		fprintf_line(hists, hpp, line, fp);
		fprintf(fp, "\n");
	}
786 787

	if (sep)
788
		return hpp_list->nr_header_lines;
789

790 791
	first = true;

792 793
	fprintf(fp, "# ");

794
	hists__for_each_format(hists, fmt) {
795
		unsigned int i;
796

797
		if (perf_hpp__should_skip(fmt, hists))
798 799
			continue;

800
		if (!first)
801
			fprintf(fp, "%s", sep ?: "  ");
802 803
		else
			first = false;
804

805
		width = fmt->width(fmt, hpp, hists);
806 807
		for (i = 0; i < width; i++)
			fprintf(fp, ".");
808
	}
809

810 811
	fprintf(fp, "\n");
	fprintf(fp, "#\n");
812
	return hpp_list->nr_header_lines + 2;
J
Jiri Olsa 已提交
813 814
}

815
int hists__fprintf_headers(struct hists *hists, FILE *fp)
816
{
817
	char bf[1024];
818 819 820 821 822 823 824 825 826 827 828 829 830 831
	struct perf_hpp dummy_hpp = {
		.buf	= bf,
		.size	= sizeof(bf),
	};

	fprintf(fp, "# ");

	if (symbol_conf.report_hierarchy)
		return hists__fprintf_hierarchy_headers(hists, &dummy_hpp, fp);
	else
		return hists__fprintf_standard_headers(hists, &dummy_hpp, fp);

}

J
Jiri Olsa 已提交
832
size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
833 834
		      int max_cols, float min_pcnt, FILE *fp,
		      bool use_callchain)
J
Jiri Olsa 已提交
835 836 837 838 839 840 841 842 843 844 845
{
	struct rb_node *nd;
	size_t ret = 0;
	const char *sep = symbol_conf.field_sep;
	int nr_rows = 0;
	size_t linesz;
	char *line = NULL;
	unsigned indent;

	init_rem_hits();

846
	hists__reset_column_width(hists);
J
Jiri Olsa 已提交
847 848 849 850 851 852 853 854

	if (symbol_conf.col_width_list_str)
		perf_hpp__set_user_width(symbol_conf.col_width_list_str);

	if (show_header)
		nr_rows += hists__fprintf_headers(hists, fp);

	if (max_rows && nr_rows >= max_rows)
855 856
		goto out;

857
	linesz = hists__sort_list_width(hists) + 3 + 1;
858
	linesz += perf_hpp__color_overhead();
859 860 861 862 863 864
	line = malloc(linesz);
	if (line == NULL) {
		ret = -1;
		goto out;
	}

865 866
	indent = hists__overhead_width(hists) + 4;

867
	for (nd = rb_first(&hists->entries); nd; nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD)) {
868
		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
869
		float percent;
870 871 872 873

		if (h->filtered)
			continue;

874
		percent = hist_entry__get_percent_limit(h);
875 876 877
		if (percent < min_pcnt)
			continue;

878
		ret += hist_entry__fprintf(h, max_cols, line, linesz, fp, use_callchain);
879 880

		if (max_rows && ++nr_rows >= max_rows)
881
			break;
882

883 884 885 886 887
		/*
		 * If all children are filtered out or percent-limited,
		 * display "no entry >= x.xx%" message.
		 */
		if (!h->leaf && !hist_entry__has_hierarchy_children(h, min_pcnt)) {
888
			int depth = hists->nr_hpp_node + h->depth + 1;
889

890
			print_hierarchy_indent(sep, depth, spaces, fp);
891 892 893 894 895 896
			fprintf(fp, "%*sno entry >= %.2f%%\n", indent, "", min_pcnt);

			if (max_rows && ++nr_rows >= max_rows)
				break;
		}

897
		if (h->ms.map == NULL && verbose > 1) {
898
			__map_groups__fprintf_maps(h->thread->mg,
899
						   MAP__FUNCTION, fp);
900 901 902
			fprintf(fp, "%.10s end\n", graph_dotted_line);
		}
	}
903 904

	free(line);
905
out:
906
	zfree(&rem_sq_bracket);
907 908 909 910

	return ret;
}

911
size_t events_stats__fprintf(struct events_stats *stats, FILE *fp)
912 913 914 915 916 917 918
{
	int i;
	size_t ret = 0;

	for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
		const char *name;

919
		if (stats->nr_events[i] == 0)
920 921 922 923 924 925 926
			continue;

		name = perf_event__name(i);
		if (!strcmp(name, "UNKNOWN"))
			continue;

		ret += fprintf(fp, "%16s events: %10d\n", name,
927
			       stats->nr_events[i]);
928 929 930 931
	}

	return ret;
}