hist.c 24.1 KB
Newer Older
1
#include "annotate.h"
2
#include "util.h"
3
#include "build-id.h"
4
#include "hist.h"
5 6
#include "session.h"
#include "sort.h"
7
#include <math.h>
8

9 10 11 12 13 14
enum hist_filter {
	HIST_FILTER__DSO,
	HIST_FILTER__THREAD,
	HIST_FILTER__PARENT,
};

15 16
struct callchain_param	callchain_param = {
	.mode	= CHAIN_GRAPH_REL,
17 18
	.min_percent = 0.5,
	.order  = ORDER_CALLEE
19 20
};

21
u16 hists__col_len(struct hists *hists, enum hist_column col)
22
{
23
	return hists->col_len[col];
24 25
}

26
void hists__set_col_len(struct hists *hists, enum hist_column col, u16 len)
27
{
28
	hists->col_len[col] = len;
29 30
}

31
bool hists__new_col_len(struct hists *hists, enum hist_column col, u16 len)
32
{
33 34
	if (len > hists__col_len(hists, col)) {
		hists__set_col_len(hists, col, len);
35 36 37 38 39
		return true;
	}
	return false;
}

40
static void hists__reset_col_len(struct hists *hists)
41 42 43 44
{
	enum hist_column col;

	for (col = 0; col < HISTC_NR_COLS; ++col)
45
		hists__set_col_len(hists, col, 0);
46 47
}

48
static void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
49 50 51 52
{
	u16 len;

	if (h->ms.sym)
53
		hists__new_col_len(hists, HISTC_SYMBOL, h->ms.sym->namelen);
54 55 56
	else {
		const unsigned int unresolved_col_width = BITS_PER_LONG / 4;

57
		if (hists__col_len(hists, HISTC_DSO) < unresolved_col_width &&
58 59
		    !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
		    !symbol_conf.dso_list)
60
			hists__set_col_len(hists, HISTC_DSO,
61 62
					   unresolved_col_width);
	}
63 64

	len = thread__comm_len(h->thread);
65 66
	if (hists__new_col_len(hists, HISTC_COMM, len))
		hists__set_col_len(hists, HISTC_THREAD, len + 6);
67 68 69

	if (h->ms.map) {
		len = dso__name_len(h->ms.map->dso);
70
		hists__new_col_len(hists, HISTC_DSO, len);
71 72 73
	}
}

74 75
static void hist_entry__add_cpumode_period(struct hist_entry *self,
					   unsigned int cpumode, u64 period)
76
{
77
	switch (cpumode) {
78
	case PERF_RECORD_MISC_KERNEL:
79
		self->period_sys += period;
80 81
		break;
	case PERF_RECORD_MISC_USER:
82
		self->period_us += period;
83 84
		break;
	case PERF_RECORD_MISC_GUEST_KERNEL:
85
		self->period_guest_sys += period;
86 87
		break;
	case PERF_RECORD_MISC_GUEST_USER:
88
		self->period_guest_us += period;
89 90 91 92 93 94
		break;
	default:
		break;
	}
}

95
/*
96
 * histogram, sorted on item, collects periods
97 98
 */

99 100
static struct hist_entry *hist_entry__new(struct hist_entry *template)
{
101
	size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_root) : 0;
102 103 104 105
	struct hist_entry *self = malloc(sizeof(*self) + callchain_size);

	if (self != NULL) {
		*self = *template;
106
		self->nr_events = 1;
107 108
		if (self->ms.map)
			self->ms.map->referenced = true;
109 110 111 112 113 114 115
		if (symbol_conf.use_callchain)
			callchain_init(self->callchain);
	}

	return self;
}

116
static void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h)
117
{
118
	if (!h->filtered) {
119 120
		hists__calc_col_len(hists, h);
		++hists->nr_entries;
121
	}
122 123
}

124 125 126 127 128 129 130
static u8 symbol__parent_filter(const struct symbol *parent)
{
	if (symbol_conf.exclude_other && parent == NULL)
		return 1 << HIST_FILTER__PARENT;
	return 0;
}

131
struct hist_entry *__hists__add_entry(struct hists *hists,
132
				      struct addr_location *al,
133
				      struct symbol *sym_parent, u64 period)
134
{
135
	struct rb_node **p = &hists->entries.rb_node;
136 137 138
	struct rb_node *parent = NULL;
	struct hist_entry *he;
	struct hist_entry entry = {
139
		.thread	= al->thread,
140 141 142 143
		.ms = {
			.map	= al->map,
			.sym	= al->sym,
		},
A
Arun Sharma 已提交
144
		.cpu	= al->cpu,
145 146
		.ip	= al->addr,
		.level	= al->level,
147
		.period	= period,
148
		.parent = sym_parent,
149
		.filtered = symbol__parent_filter(sym_parent),
150 151 152 153 154 155 156 157 158 159
	};
	int cmp;

	while (*p != NULL) {
		parent = *p;
		he = rb_entry(parent, struct hist_entry, rb_node);

		cmp = hist_entry__cmp(&entry, he);

		if (!cmp) {
160 161
			he->period += period;
			++he->nr_events;
162
			goto out;
163 164 165 166 167 168 169 170
		}

		if (cmp < 0)
			p = &(*p)->rb_left;
		else
			p = &(*p)->rb_right;
	}

171
	he = hist_entry__new(&entry);
172 173 174
	if (!he)
		return NULL;
	rb_link_node(&he->rb_node, parent, p);
175 176
	rb_insert_color(&he->rb_node, &hists->entries);
	hists__inc_nr_entries(hists, he);
177
out:
178
	hist_entry__add_cpumode_period(he, al->cpumode, period);
179 180 181
	return he;
}

182 183 184 185 186 187 188
int64_t
hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
{
	struct sort_entry *se;
	int64_t cmp = 0;

	list_for_each_entry(se, &hist_entry__sort_list, list) {
189
		cmp = se->se_cmp(left, right);
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
		if (cmp)
			break;
	}

	return cmp;
}

int64_t
hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
{
	struct sort_entry *se;
	int64_t cmp = 0;

	list_for_each_entry(se, &hist_entry__sort_list, list) {
		int64_t (*f)(struct hist_entry *, struct hist_entry *);

206
		f = se->se_collapse ?: se->se_cmp;
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224

		cmp = f(left, right);
		if (cmp)
			break;
	}

	return cmp;
}

void hist_entry__free(struct hist_entry *he)
{
	free(he);
}

/*
 * collapse the histogram
 */

225
static bool hists__collapse_insert_entry(struct hists *hists,
226 227
					 struct rb_root *root,
					 struct hist_entry *he)
228
{
229
	struct rb_node **p = &root->rb_node;
230 231 232 233 234 235 236 237 238 239 240
	struct rb_node *parent = NULL;
	struct hist_entry *iter;
	int64_t cmp;

	while (*p != NULL) {
		parent = *p;
		iter = rb_entry(parent, struct hist_entry, rb_node);

		cmp = hist_entry__collapse(iter, he);

		if (!cmp) {
241
			iter->period += he->period;
242
			if (symbol_conf.use_callchain) {
243 244
				callchain_cursor_reset(&hists->callchain_cursor);
				callchain_merge(&hists->callchain_cursor, iter->callchain,
245 246
						he->callchain);
			}
247
			hist_entry__free(he);
248
			return false;
249 250 251 252 253 254 255 256 257
		}

		if (cmp < 0)
			p = &(*p)->rb_left;
		else
			p = &(*p)->rb_right;
	}

	rb_link_node(&he->rb_node, parent, p);
258
	rb_insert_color(&he->rb_node, root);
259
	return true;
260 261
}

262
void hists__collapse_resort(struct hists *hists)
263
{
264
	struct rb_root tmp;
265 266 267 268 269 270
	struct rb_node *next;
	struct hist_entry *n;

	if (!sort__need_collapse)
		return;

271
	tmp = RB_ROOT;
272 273 274
	next = rb_first(&hists->entries);
	hists->nr_entries = 0;
	hists__reset_col_len(hists);
275

276 277 278 279
	while (next) {
		n = rb_entry(next, struct hist_entry, rb_node);
		next = rb_next(&n->rb_node);

280 281 282
		rb_erase(&n->rb_node, &hists->entries);
		if (hists__collapse_insert_entry(hists, &tmp, n))
			hists__inc_nr_entries(hists, n);
283
	}
284

285
	hists->entries = tmp;
286 287 288
}

/*
289
 * reverse the map, sort on period.
290 291
 */

292 293 294
static void __hists__insert_output_entry(struct rb_root *entries,
					 struct hist_entry *he,
					 u64 min_callchain_hits)
295
{
296
	struct rb_node **p = &entries->rb_node;
297 298 299
	struct rb_node *parent = NULL;
	struct hist_entry *iter;

300
	if (symbol_conf.use_callchain)
301
		callchain_param.sort(&he->sorted_chain, he->callchain,
302 303 304 305 306 307
				      min_callchain_hits, &callchain_param);

	while (*p != NULL) {
		parent = *p;
		iter = rb_entry(parent, struct hist_entry, rb_node);

308
		if (he->period > iter->period)
309 310 311 312 313 314
			p = &(*p)->rb_left;
		else
			p = &(*p)->rb_right;
	}

	rb_link_node(&he->rb_node, parent, p);
315
	rb_insert_color(&he->rb_node, entries);
316 317
}

318
void hists__output_resort(struct hists *hists)
319
{
320
	struct rb_root tmp;
321 322 323 324
	struct rb_node *next;
	struct hist_entry *n;
	u64 min_callchain_hits;

325
	min_callchain_hits = hists->stats.total_period * (callchain_param.min_percent / 100);
326

327
	tmp = RB_ROOT;
328
	next = rb_first(&hists->entries);
329

330 331
	hists->nr_entries = 0;
	hists__reset_col_len(hists);
332

333 334 335 336
	while (next) {
		n = rb_entry(next, struct hist_entry, rb_node);
		next = rb_next(&n->rb_node);

337
		rb_erase(&n->rb_node, &hists->entries);
338
		__hists__insert_output_entry(&tmp, n, min_callchain_hits);
339
		hists__inc_nr_entries(hists, n);
340
	}
341

342
	hists->entries = tmp;
343
}
344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373

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;
}

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;
}

static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
374
				     int depth, int depth_mask, int period,
375
				     u64 total_samples, u64 hits,
376 377 378 379 380 381 382 383 384 385 386
				     int left_margin)
{
	int i;
	size_t ret = 0;

	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, " ");
387
		if (!period && i == depth - 1) {
388 389 390 391 392 393 394
			double percent;

			percent = hits * 100.0 / total_samples;
			ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
		} else
			ret += fprintf(fp, "%s", "          ");
	}
395 396
	if (chain->ms.sym)
		ret += fprintf(fp, "%s\n", chain->ms.sym->name);
397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414
	else
		ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);

	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, "[...]");
415
	rem_hits.ms.sym = rem_sq_bracket;
416 417 418 419 420 421 422 423 424 425 426 427 428 429
}

static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
					 u64 total_samples, int depth,
					 int depth_mask, int left_margin)
{
	struct rb_node *node, *next;
	struct callchain_node *child;
	struct callchain_list *chain;
	int new_depth_mask = depth_mask;
	u64 new_total;
	u64 remaining;
	size_t ret = 0;
	int i;
430
	uint entries_printed = 0;
431 432 433 434 435 436 437 438 439 440 441 442 443

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

	remaining = new_total;

	node = rb_first(&self->rb_root);
	while (node) {
		u64 cumul;

		child = rb_entry(node, struct callchain_node, rb_node);
444
		cumul = callchain_cumul_hits(child);
445 446 447 448 449 450 451 452 453 454 455 456 457 458
		remaining -= cumul;

		/*
		 * 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));

		/*
D
Daniel Mack 已提交
459
		 * But we keep the older depth mask for the line separator
460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476
		 * 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) {
			ret += ipchain__fprintf_graph(fp, chain, depth,
						      new_depth_mask, i++,
						      new_total,
						      cumul,
						      left_margin);
		}
		ret += __callchain__fprintf_graph(fp, child, new_total,
						  depth + 1,
						  new_depth_mask | (1 << depth),
						  left_margin);
		node = next;
477 478
		if (++entries_printed == callchain_param.print_limit)
			break;
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503
	}

	if (callchain_param.mode == CHAIN_GRAPH_REL &&
		remaining && remaining != new_total) {

		if (!rem_sq_bracket)
			return ret;

		new_depth_mask &= ~(1 << (depth - 1));

		ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
					      new_depth_mask, 0, new_total,
					      remaining, left_margin);
	}

	return ret;
}

static size_t callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
				       u64 total_samples, int left_margin)
{
	struct callchain_list *chain;
	bool printed = false;
	int i = 0;
	int ret = 0;
504
	u32 entries_printed = 0;
505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520

	list_for_each_entry(chain, &self->val, list) {
		if (!i++ && sort__first_dimension == SORT_SYM)
			continue;

		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);

521 522
		if (chain->ms.sym)
			ret += fprintf(fp, " %s\n", chain->ms.sym->name);
523 524
		else
			ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
525 526 527

		if (++entries_printed == callchain_param.print_limit)
			break;
528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549
	}

	ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin);

	return ret;
}

static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
				      u64 total_samples)
{
	struct callchain_list *chain;
	size_t ret = 0;

	if (!self)
		return 0;

	ret += callchain__fprintf_flat(fp, self->parent, total_samples);


	list_for_each_entry(chain, &self->val, list) {
		if (chain->ip >= PERF_CONTEXT_MAX)
			continue;
550 551
		if (chain->ms.sym)
			ret += fprintf(fp, "                %s\n", chain->ms.sym->name);
552 553 554 555 556 557 558 559 560 561 562 563 564 565
		else
			ret += fprintf(fp, "                %p\n",
					(void *)(long)chain->ip);
	}

	return ret;
}

static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
					    u64 total_samples, int left_margin)
{
	struct rb_node *rb_node;
	struct callchain_node *chain;
	size_t ret = 0;
566
	u32 entries_printed = 0;
567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588

	rb_node = rb_first(&self->sorted_chain);
	while (rb_node) {
		double percent;

		chain = rb_entry(rb_node, struct callchain_node, rb_node);
		percent = chain->hit * 100.0 / total_samples;
		switch (callchain_param.mode) {
		case CHAIN_FLAT:
			ret += percent_color_fprintf(fp, "           %6.2f%%\n",
						     percent);
			ret += callchain__fprintf_flat(fp, chain, total_samples);
			break;
		case CHAIN_GRAPH_ABS: /* Falldown */
		case CHAIN_GRAPH_REL:
			ret += callchain__fprintf_graph(fp, chain, total_samples,
							left_margin);
		case CHAIN_NONE:
		default:
			break;
		}
		ret += fprintf(fp, "\n");
589 590
		if (++entries_printed == callchain_param.print_limit)
			break;
591 592 593 594 595 596
		rb_node = rb_next(rb_node);
	}

	return ret;
}

597
int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
598 599 600
			 struct hists *hists, struct hists *pair_hists,
			 bool show_displacement, long displacement,
			 bool color, u64 session_total)
601 602
{
	struct sort_entry *se;
603
	u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us;
604
	u64 nr_events;
605
	const char *sep = symbol_conf.field_sep;
606
	int ret;
607 608 609 610

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

611
	if (pair_hists) {
612
		period = self->pair ? self->pair->period : 0;
613
		nr_events = self->pair ? self->pair->nr_events : 0;
614
		total = pair_hists->stats.total_period;
615 616 617 618
		period_sys = self->pair ? self->pair->period_sys : 0;
		period_us = self->pair ? self->pair->period_us : 0;
		period_guest_sys = self->pair ? self->pair->period_guest_sys : 0;
		period_guest_us = self->pair ? self->pair->period_guest_us : 0;
619
	} else {
620
		period = self->period;
621
		nr_events = self->nr_events;
622
		total = session_total;
623 624 625 626
		period_sys = self->period_sys;
		period_us = self->period_us;
		period_guest_sys = self->period_guest_sys;
		period_guest_us = self->period_guest_us;
627 628
	}

629 630 631 632
	if (total) {
		if (color)
			ret = percent_color_snprintf(s, size,
						     sep ? "%.2f" : "   %6.2f%%",
633
						     (period * 100.0) / total);
634 635
		else
			ret = snprintf(s, size, sep ? "%.2f" : "   %6.2f%%",
636
				       (period * 100.0) / total);
637 638 639
		if (symbol_conf.show_cpu_utilization) {
			ret += percent_color_snprintf(s + ret, size - ret,
					sep ? "%.2f" : "   %6.2f%%",
640
					(period_sys * 100.0) / total);
641 642
			ret += percent_color_snprintf(s + ret, size - ret,
					sep ? "%.2f" : "   %6.2f%%",
643
					(period_us * 100.0) / total);
644 645 646 647
			if (perf_guest) {
				ret += percent_color_snprintf(s + ret,
						size - ret,
						sep ? "%.2f" : "   %6.2f%%",
648
						(period_guest_sys * 100.0) /
649 650 651 652
								total);
				ret += percent_color_snprintf(s + ret,
						size - ret,
						sep ? "%.2f" : "   %6.2f%%",
653
						(period_guest_us * 100.0) /
654 655 656
								total);
			}
		}
657
	} else
658
		ret = snprintf(s, size, sep ? "%" PRIu64 : "%12" PRIu64 " ", period);
659 660

	if (symbol_conf.show_nr_samples) {
661
		if (sep)
662
			ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, nr_events);
663
		else
664
			ret += snprintf(s + ret, size - ret, "%11" PRIu64, nr_events);
665 666
	}

667 668 669 670 671 672 673
	if (symbol_conf.show_total_period) {
		if (sep)
			ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, period);
		else
			ret += snprintf(s + ret, size - ret, " %12" PRIu64, period);
	}

674
	if (pair_hists) {
675 676 677 678
		char bf[32];
		double old_percent = 0, new_percent = 0, diff;

		if (total > 0)
679
			old_percent = (period * 100.0) / total;
680
		if (session_total > 0)
681
			new_percent = (self->period * 100.0) / session_total;
682

683
		diff = new_percent - old_percent;
684

685
		if (fabs(diff) >= 0.01)
686 687 688 689 690
			snprintf(bf, sizeof(bf), "%+4.2F%%", diff);
		else
			snprintf(bf, sizeof(bf), " ");

		if (sep)
691
			ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
692
		else
693
			ret += snprintf(s + ret, size - ret, "%11.11s", bf);
694 695 696 697 698 699 700 701

		if (show_displacement) {
			if (displacement)
				snprintf(bf, sizeof(bf), "%+4ld", displacement);
			else
				snprintf(bf, sizeof(bf), " ");

			if (sep)
702
				ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
703
			else
704
				ret += snprintf(s + ret, size - ret, "%6.6s", bf);
705
		}
706 707 708 709 710 711
	}

	list_for_each_entry(se, &hist_entry__sort_list, list) {
		if (se->elide)
			continue;

712
		ret += snprintf(s + ret, size - ret, "%s", sep ?: "  ");
713
		ret += se->se_snprintf(self, s + ret, size - ret,
714
				       hists__col_len(hists, se->se_width_idx));
715 716
	}

717 718 719
	return ret;
}

720
int hist_entry__fprintf(struct hist_entry *he, size_t size, struct hists *hists,
721 722
			struct hists *pair_hists, bool show_displacement,
			long displacement, FILE *fp, u64 session_total)
723 724
{
	char bf[512];
725 726 727 728 729

	if (size == 0 || size > sizeof(bf))
		size = sizeof(bf);

	hist_entry__snprintf(he, bf, size, hists, pair_hists,
730 731 732
			     show_displacement, displacement,
			     true, session_total);
	return fprintf(fp, "%s\n", bf);
733
}
734

735 736
static size_t hist_entry__fprintf_callchain(struct hist_entry *self,
					    struct hists *hists, FILE *fp,
737 738 739
					    u64 session_total)
{
	int left_margin = 0;
740

741 742 743
	if (sort__first_dimension == SORT_COMM) {
		struct sort_entry *se = list_first_entry(&hist_entry__sort_list,
							 typeof(*se), list);
744
		left_margin = hists__col_len(hists, se->se_width_idx);
745
		left_margin -= thread__comm_len(self->thread);
746 747
	}

748 749
	return hist_entry_callchain__fprintf(fp, self, session_total,
					     left_margin);
750 751
}

752
size_t hists__fprintf(struct hists *hists, struct hists *pair,
753 754
		      bool show_displacement, bool show_header, int max_rows,
		      int max_cols, FILE *fp)
755 756 757 758
{
	struct sort_entry *se;
	struct rb_node *nd;
	size_t ret = 0;
759 760
	unsigned long position = 1;
	long displacement = 0;
761
	unsigned int width;
762
	const char *sep = symbol_conf.field_sep;
763
	const char *col_width = symbol_conf.col_width_list_str;
764
	int nr_rows = 0;
765 766 767

	init_rem_hits();

768 769 770
	if (!show_header)
		goto print_entries;

771 772
	fprintf(fp, "# %s", pair ? "Baseline" : "Overhead");

773
	if (symbol_conf.show_nr_samples) {
774 775
		if (sep)
			fprintf(fp, "%cSamples", *sep);
776 777 778
		else
			fputs("  Samples  ", fp);
	}
779

780 781 782 783 784 785 786
	if (symbol_conf.show_total_period) {
		if (sep)
			ret += fprintf(fp, "%cPeriod", *sep);
		else
			ret += fprintf(fp, "   Period    ");
	}

787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804
	if (symbol_conf.show_cpu_utilization) {
		if (sep) {
			ret += fprintf(fp, "%csys", *sep);
			ret += fprintf(fp, "%cus", *sep);
			if (perf_guest) {
				ret += fprintf(fp, "%cguest sys", *sep);
				ret += fprintf(fp, "%cguest us", *sep);
			}
		} else {
			ret += fprintf(fp, "  sys  ");
			ret += fprintf(fp, "  us  ");
			if (perf_guest) {
				ret += fprintf(fp, "  guest sys  ");
				ret += fprintf(fp, "  guest us  ");
			}
		}
	}

805 806 807 808 809 810 811 812 813 814 815 816 817 818
	if (pair) {
		if (sep)
			ret += fprintf(fp, "%cDelta", *sep);
		else
			ret += fprintf(fp, "  Delta    ");

		if (show_displacement) {
			if (sep)
				ret += fprintf(fp, "%cDisplacement", *sep);
			else
				ret += fprintf(fp, " Displ");
		}
	}

819 820 821
	list_for_each_entry(se, &hist_entry__sort_list, list) {
		if (se->elide)
			continue;
822
		if (sep) {
823
			fprintf(fp, "%c%s", *sep, se->se_header);
824 825
			continue;
		}
826
		width = strlen(se->se_header);
827 828
		if (symbol_conf.col_width_list_str) {
			if (col_width) {
829
				hists__set_col_len(hists, se->se_width_idx,
830 831 832 833
						   atoi(col_width));
				col_width = strchr(col_width, ',');
				if (col_width)
					++col_width;
834 835
			}
		}
836 837
		if (!hists__new_col_len(hists, se->se_width_idx, width))
			width = hists__col_len(hists, se->se_width_idx);
838
		fprintf(fp, "  %*s", width, se->se_header);
839
	}
840

841
	fprintf(fp, "\n");
842 843
	if (max_rows && ++nr_rows >= max_rows)
		goto out;
844

845
	if (sep)
846 847 848 849 850
		goto print_entries;

	fprintf(fp, "# ........");
	if (symbol_conf.show_nr_samples)
		fprintf(fp, " ..........");
851 852
	if (symbol_conf.show_total_period)
		fprintf(fp, " ............");
853 854 855 856 857
	if (pair) {
		fprintf(fp, " ..........");
		if (show_displacement)
			fprintf(fp, " .....");
	}
858 859 860 861 862 863 864
	list_for_each_entry(se, &hist_entry__sort_list, list) {
		unsigned int i;

		if (se->elide)
			continue;

		fprintf(fp, "  ");
865
		width = hists__col_len(hists, se->se_width_idx);
866
		if (width == 0)
867
			width = strlen(se->se_header);
868 869 870 871
		for (i = 0; i < width; i++)
			fprintf(fp, ".");
	}

872 873 874 875 876 877 878
	fprintf(fp, "\n");
	if (max_rows && ++nr_rows >= max_rows)
		goto out;

	fprintf(fp, "#\n");
	if (max_rows && ++nr_rows >= max_rows)
		goto out;
879 880

print_entries:
881
	for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
882 883
		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);

884 885 886
		if (h->filtered)
			continue;

887 888 889 890 891 892 893 894
		if (show_displacement) {
			if (h->pair != NULL)
				displacement = ((long)h->pair->position -
					        (long)position);
			else
				displacement = 0;
			++position;
		}
895
		ret += hist_entry__fprintf(h, max_cols, hists, pair, show_displacement,
896
					   displacement, fp, hists->stats.total_period);
897 898

		if (symbol_conf.use_callchain)
899 900
			ret += hist_entry__fprintf_callchain(h, hists, fp,
							     hists->stats.total_period);
901 902 903
		if (max_rows && ++nr_rows >= max_rows)
			goto out;

904
		if (h->ms.map == NULL && verbose > 1) {
905
			__map_groups__fprintf_maps(&h->thread->mg,
906
						   MAP__FUNCTION, verbose, fp);
907 908
			fprintf(fp, "%.10s end\n", graph_dotted_line);
		}
909
	}
910
out:
911 912 913 914
	free(rem_sq_bracket);

	return ret;
}
915

916 917 918
/*
 * See hists__fprintf to match the column widths
 */
919
unsigned int hists__sort_list_width(struct hists *hists)
920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935
{
	struct sort_entry *se;
	int ret = 9; /* total % */

	if (symbol_conf.show_cpu_utilization) {
		ret += 7; /* count_sys % */
		ret += 6; /* count_us % */
		if (perf_guest) {
			ret += 13; /* count_guest_sys % */
			ret += 12; /* count_guest_us % */
		}
	}

	if (symbol_conf.show_nr_samples)
		ret += 11;

936 937 938
	if (symbol_conf.show_total_period)
		ret += 13;

939 940
	list_for_each_entry(se, &hist_entry__sort_list, list)
		if (!se->elide)
941
			ret += 2 + hists__col_len(hists, se->se_width_idx);
942

943 944 945
	if (verbose) /* Addr + origin */
		ret += 3 + BITS_PER_LONG / 4;

946 947 948
	return ret;
}

949
static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h,
950 951 952 953 954 955
				       enum hist_filter filter)
{
	h->filtered &= ~(1 << filter);
	if (h->filtered)
		return;

956
	++hists->nr_entries;
957
	if (h->ms.unfolded)
958
		hists->nr_entries += h->nr_rows;
959
	h->row_offset = 0;
960 961
	hists->stats.total_period += h->period;
	hists->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events;
962

963
	hists__calc_col_len(hists, h);
964 965
}

966
void hists__filter_by_dso(struct hists *hists, const struct dso *dso)
967 968 969
{
	struct rb_node *nd;

970 971 972
	hists->nr_entries = hists->stats.total_period = 0;
	hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
	hists__reset_col_len(hists);
973

974
	for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
975 976 977 978 979 980 981 982 983 984
		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);

		if (symbol_conf.exclude_other && !h->parent)
			continue;

		if (dso != NULL && (h->ms.map == NULL || h->ms.map->dso != dso)) {
			h->filtered |= (1 << HIST_FILTER__DSO);
			continue;
		}

985
		hists__remove_entry_filter(hists, h, HIST_FILTER__DSO);
986 987 988
	}
}

989
void hists__filter_by_thread(struct hists *hists, const struct thread *thread)
990 991 992
{
	struct rb_node *nd;

993 994 995
	hists->nr_entries = hists->stats.total_period = 0;
	hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
	hists__reset_col_len(hists);
996

997
	for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
998 999 1000 1001 1002 1003
		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);

		if (thread != NULL && h->thread != thread) {
			h->filtered |= (1 << HIST_FILTER__THREAD);
			continue;
		}
1004

1005
		hists__remove_entry_filter(hists, h, HIST_FILTER__THREAD);
1006 1007
	}
}
1008

1009
int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip)
1010
{
1011
	return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip);
1012 1013
}

1014
int hist_entry__annotate(struct hist_entry *he, size_t privsize)
1015
{
1016
	return symbol__annotate(he->ms.sym, he->ms.map, privsize);
1017
}
1018

1019
void hists__inc_nr_events(struct hists *hists, u32 type)
1020
{
1021 1022
	++hists->stats.nr_events[0];
	++hists->stats.nr_events[type];
1023 1024
}

1025
size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp)
1026 1027 1028 1029 1030
{
	int i;
	size_t ret = 0;

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

1033
		if (hists->stats.nr_events[i] == 0)
1034 1035 1036
			continue;

		name = perf_event__name(i);
1037
		if (!strcmp(name, "UNKNOWN"))
1038
			continue;
1039 1040

		ret += fprintf(fp, "%16s events: %10d\n", name,
1041
			       hists->stats.nr_events[i]);
1042 1043 1044 1045
	}

	return ret;
}