hist.c 22.6 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 17 18 19
struct callchain_param	callchain_param = {
	.mode	= CHAIN_GRAPH_REL,
	.min_percent = 0.5
};

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
u16 hists__col_len(struct hists *self, enum hist_column col)
{
	return self->col_len[col];
}

void hists__set_col_len(struct hists *self, enum hist_column col, u16 len)
{
	self->col_len[col] = len;
}

bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len)
{
	if (len > hists__col_len(self, col)) {
		hists__set_col_len(self, col, len);
		return true;
	}
	return false;
}

static void hists__reset_col_len(struct hists *self)
{
	enum hist_column col;

	for (col = 0; col < HISTC_NR_COLS; ++col)
		hists__set_col_len(self, col, 0);
}

static void hists__calc_col_len(struct hists *self, struct hist_entry *h)
{
	u16 len;

	if (h->ms.sym)
		hists__new_col_len(self, HISTC_SYMBOL, h->ms.sym->namelen);

	len = thread__comm_len(h->thread);
	if (hists__new_col_len(self, HISTC_COMM, len))
		hists__set_col_len(self, HISTC_THREAD, len + 6);

	if (h->ms.map) {
		len = dso__name_len(h->ms.map->dso);
		hists__new_col_len(self, HISTC_DSO, len);
	}
}

64 65
static void hist_entry__add_cpumode_period(struct hist_entry *self,
					   unsigned int cpumode, u64 period)
66
{
67
	switch (cpumode) {
68
	case PERF_RECORD_MISC_KERNEL:
69
		self->period_sys += period;
70 71
		break;
	case PERF_RECORD_MISC_USER:
72
		self->period_us += period;
73 74
		break;
	case PERF_RECORD_MISC_GUEST_KERNEL:
75
		self->period_guest_sys += period;
76 77
		break;
	case PERF_RECORD_MISC_GUEST_USER:
78
		self->period_guest_us += period;
79 80 81 82 83 84
		break;
	default:
		break;
	}
}

85
/*
86
 * histogram, sorted on item, collects periods
87 88
 */

89 90
static struct hist_entry *hist_entry__new(struct hist_entry *template)
{
91
	size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_root) : 0;
92 93 94 95
	struct hist_entry *self = malloc(sizeof(*self) + callchain_size);

	if (self != NULL) {
		*self = *template;
96
		self->nr_events = 1;
97 98
		if (self->ms.map)
			self->ms.map->referenced = true;
99 100 101 102 103 104 105
		if (symbol_conf.use_callchain)
			callchain_init(self->callchain);
	}

	return self;
}

106
static void hists__inc_nr_entries(struct hists *self, struct hist_entry *h)
107
{
108 109 110 111
	if (!h->filtered) {
		hists__calc_col_len(self, h);
		++self->nr_entries;
	}
112 113
}

114 115 116 117 118 119 120
static u8 symbol__parent_filter(const struct symbol *parent)
{
	if (symbol_conf.exclude_other && parent == NULL)
		return 1 << HIST_FILTER__PARENT;
	return 0;
}

121 122
struct hist_entry *__hists__add_entry(struct hists *self,
				      struct addr_location *al,
123
				      struct symbol *sym_parent, u64 period)
124
{
125
	struct rb_node **p = &self->entries.rb_node;
126 127 128
	struct rb_node *parent = NULL;
	struct hist_entry *he;
	struct hist_entry entry = {
129
		.thread	= al->thread,
130 131 132 133
		.ms = {
			.map	= al->map,
			.sym	= al->sym,
		},
A
Arun Sharma 已提交
134
		.cpu	= al->cpu,
135 136
		.ip	= al->addr,
		.level	= al->level,
137
		.period	= period,
138
		.parent = sym_parent,
139
		.filtered = symbol__parent_filter(sym_parent),
140 141 142 143 144 145 146 147 148 149
	};
	int cmp;

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

		cmp = hist_entry__cmp(&entry, he);

		if (!cmp) {
150 151
			he->period += period;
			++he->nr_events;
152
			goto out;
153 154 155 156 157 158 159 160
		}

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

161
	he = hist_entry__new(&entry);
162 163 164
	if (!he)
		return NULL;
	rb_link_node(&he->rb_node, parent, p);
165
	rb_insert_color(&he->rb_node, &self->entries);
166
	hists__inc_nr_entries(self, he);
167
out:
168
	hist_entry__add_cpumode_period(he, al->cpumode, period);
169 170 171
	return he;
}

172 173 174 175 176 177 178
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) {
179
		cmp = se->se_cmp(left, right);
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
		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 *);

196
		f = se->se_collapse ?: se->se_cmp;
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214

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

	return cmp;
}

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

/*
 * collapse the histogram
 */

215 216 217
static bool hists__collapse_insert_entry(struct hists *self,
					 struct rb_root *root,
					 struct hist_entry *he)
218
{
219
	struct rb_node **p = &root->rb_node;
220 221 222 223 224 225 226 227 228 229 230
	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) {
231
			iter->period += he->period;
232 233 234 235 236
			if (symbol_conf.use_callchain) {
				callchain_cursor_reset(&self->callchain_cursor);
				callchain_merge(&self->callchain_cursor, iter->callchain,
						he->callchain);
			}
237
			hist_entry__free(he);
238
			return false;
239 240 241 242 243 244 245 246 247
		}

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

	rb_link_node(&he->rb_node, parent, p);
248
	rb_insert_color(&he->rb_node, root);
249
	return true;
250 251
}

252
void hists__collapse_resort(struct hists *self)
253
{
254
	struct rb_root tmp;
255 256 257 258 259 260
	struct rb_node *next;
	struct hist_entry *n;

	if (!sort__need_collapse)
		return;

261
	tmp = RB_ROOT;
262
	next = rb_first(&self->entries);
263
	self->nr_entries = 0;
264
	hists__reset_col_len(self);
265

266 267 268 269
	while (next) {
		n = rb_entry(next, struct hist_entry, rb_node);
		next = rb_next(&n->rb_node);

270
		rb_erase(&n->rb_node, &self->entries);
271
		if (hists__collapse_insert_entry(self, &tmp, n))
272
			hists__inc_nr_entries(self, n);
273
	}
274

275
	self->entries = tmp;
276 277 278
}

/*
279
 * reverse the map, sort on period.
280 281
 */

282 283 284
static void __hists__insert_output_entry(struct rb_root *entries,
					 struct hist_entry *he,
					 u64 min_callchain_hits)
285
{
286
	struct rb_node **p = &entries->rb_node;
287 288 289
	struct rb_node *parent = NULL;
	struct hist_entry *iter;

290
	if (symbol_conf.use_callchain)
291
		callchain_param.sort(&he->sorted_chain, he->callchain,
292 293 294 295 296 297
				      min_callchain_hits, &callchain_param);

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

298
		if (he->period > iter->period)
299 300 301 302 303 304
			p = &(*p)->rb_left;
		else
			p = &(*p)->rb_right;
	}

	rb_link_node(&he->rb_node, parent, p);
305
	rb_insert_color(&he->rb_node, entries);
306 307
}

308
void hists__output_resort(struct hists *self)
309
{
310
	struct rb_root tmp;
311 312 313 314
	struct rb_node *next;
	struct hist_entry *n;
	u64 min_callchain_hits;

315
	min_callchain_hits = self->stats.total_period * (callchain_param.min_percent / 100);
316

317
	tmp = RB_ROOT;
318
	next = rb_first(&self->entries);
319

320
	self->nr_entries = 0;
321
	hists__reset_col_len(self);
322

323 324 325 326
	while (next) {
		n = rb_entry(next, struct hist_entry, rb_node);
		next = rb_next(&n->rb_node);

327 328
		rb_erase(&n->rb_node, &self->entries);
		__hists__insert_output_entry(&tmp, n, min_callchain_hits);
329
		hists__inc_nr_entries(self, n);
330
	}
331

332
	self->entries = tmp;
333
}
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363

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,
364
				     int depth, int depth_mask, int period,
365
				     u64 total_samples, u64 hits,
366 367 368 369 370 371 372 373 374 375 376
				     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, " ");
377
		if (!period && i == depth - 1) {
378 379 380 381 382 383 384
			double percent;

			percent = hits * 100.0 / total_samples;
			ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
		} else
			ret += fprintf(fp, "%s", "          ");
	}
385 386
	if (chain->ms.sym)
		ret += fprintf(fp, "%s\n", chain->ms.sym->name);
387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404
	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, "[...]");
405
	rem_hits.ms.sym = rem_sq_bracket;
406 407 408 409 410 411 412 413 414 415 416 417 418 419
}

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;
420
	uint entries_printed = 0;
421 422 423 424 425 426 427 428 429 430 431 432 433

	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);
434
		cumul = callchain_cumul_hits(child);
435 436 437 438 439 440 441 442 443 444 445 446 447 448
		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 已提交
449
		 * But we keep the older depth mask for the line separator
450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466
		 * 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;
467 468
		if (++entries_printed == callchain_param.print_limit)
			break;
469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493
	}

	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;
494
	u32 entries_printed = 0;
495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510

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

511 512
		if (chain->ms.sym)
			ret += fprintf(fp, " %s\n", chain->ms.sym->name);
513 514
		else
			ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
515 516 517

		if (++entries_printed == callchain_param.print_limit)
			break;
518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539
	}

	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;
540 541
		if (chain->ms.sym)
			ret += fprintf(fp, "                %s\n", chain->ms.sym->name);
542 543 544 545 546 547 548 549 550 551 552 553 554 555
		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;
556
	u32 entries_printed = 0;
557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578

	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");
579 580
		if (++entries_printed == callchain_param.print_limit)
			break;
581 582 583 584 585 586
		rb_node = rb_next(rb_node);
	}

	return ret;
}

587
int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
588 589 590
			 struct hists *hists, struct hists *pair_hists,
			 bool show_displacement, long displacement,
			 bool color, u64 session_total)
591 592
{
	struct sort_entry *se;
593
	u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us;
594
	const char *sep = symbol_conf.field_sep;
595
	int ret;
596 597 598 599

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

600
	if (pair_hists) {
601
		period = self->pair ? self->pair->period : 0;
602
		total = pair_hists->stats.total_period;
603 604 605 606
		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;
607
	} else {
608
		period = self->period;
609
		total = session_total;
610 611 612 613
		period_sys = self->period_sys;
		period_us = self->period_us;
		period_guest_sys = self->period_guest_sys;
		period_guest_us = self->period_guest_us;
614 615
	}

616 617 618 619
	if (total) {
		if (color)
			ret = percent_color_snprintf(s, size,
						     sep ? "%.2f" : "   %6.2f%%",
620
						     (period * 100.0) / total);
621 622
		else
			ret = snprintf(s, size, sep ? "%.2f" : "   %6.2f%%",
623
				       (period * 100.0) / total);
624 625 626
		if (symbol_conf.show_cpu_utilization) {
			ret += percent_color_snprintf(s + ret, size - ret,
					sep ? "%.2f" : "   %6.2f%%",
627
					(period_sys * 100.0) / total);
628 629
			ret += percent_color_snprintf(s + ret, size - ret,
					sep ? "%.2f" : "   %6.2f%%",
630
					(period_us * 100.0) / total);
631 632 633 634
			if (perf_guest) {
				ret += percent_color_snprintf(s + ret,
						size - ret,
						sep ? "%.2f" : "   %6.2f%%",
635
						(period_guest_sys * 100.0) /
636 637 638 639
								total);
				ret += percent_color_snprintf(s + ret,
						size - ret,
						sep ? "%.2f" : "   %6.2f%%",
640
						(period_guest_us * 100.0) /
641 642 643
								total);
			}
		}
644
	} else
645
		ret = snprintf(s, size, sep ? "%" PRIu64 : "%12" PRIu64 " ", period);
646 647

	if (symbol_conf.show_nr_samples) {
648
		if (sep)
649
			ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, period);
650
		else
651
			ret += snprintf(s + ret, size - ret, "%11" PRIu64, period);
652 653
	}

654
	if (pair_hists) {
655 656 657 658
		char bf[32];
		double old_percent = 0, new_percent = 0, diff;

		if (total > 0)
659
			old_percent = (period * 100.0) / total;
660
		if (session_total > 0)
661
			new_percent = (self->period * 100.0) / session_total;
662

663
		diff = new_percent - old_percent;
664

665
		if (fabs(diff) >= 0.01)
666 667 668 669 670
			snprintf(bf, sizeof(bf), "%+4.2F%%", diff);
		else
			snprintf(bf, sizeof(bf), " ");

		if (sep)
671
			ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
672
		else
673
			ret += snprintf(s + ret, size - ret, "%11.11s", bf);
674 675 676 677 678 679 680 681

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

			if (sep)
682
				ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
683
			else
684
				ret += snprintf(s + ret, size - ret, "%6.6s", bf);
685
		}
686 687 688 689 690 691
	}

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

692
		ret += snprintf(s + ret, size - ret, "%s", sep ?: "  ");
693
		ret += se->se_snprintf(self, s + ret, size - ret,
694
				       hists__col_len(hists, se->se_width_idx));
695 696
	}

697 698 699
	return ret;
}

700 701 702
int hist_entry__fprintf(struct hist_entry *self, struct hists *hists,
			struct hists *pair_hists, bool show_displacement,
			long displacement, FILE *fp, u64 session_total)
703 704
{
	char bf[512];
705
	hist_entry__snprintf(self, bf, sizeof(bf), hists, pair_hists,
706 707 708
			     show_displacement, displacement,
			     true, session_total);
	return fprintf(fp, "%s\n", bf);
709
}
710

711 712
static size_t hist_entry__fprintf_callchain(struct hist_entry *self,
					    struct hists *hists, FILE *fp,
713 714 715
					    u64 session_total)
{
	int left_margin = 0;
716

717 718 719
	if (sort__first_dimension == SORT_COMM) {
		struct sort_entry *se = list_first_entry(&hist_entry__sort_list,
							 typeof(*se), list);
720
		left_margin = hists__col_len(hists, se->se_width_idx);
721
		left_margin -= thread__comm_len(self->thread);
722 723
	}

724 725
	return hist_entry_callchain__fprintf(fp, self, session_total,
					     left_margin);
726 727
}

728 729
size_t hists__fprintf(struct hists *self, struct hists *pair,
		      bool show_displacement, FILE *fp)
730 731 732 733
{
	struct sort_entry *se;
	struct rb_node *nd;
	size_t ret = 0;
734 735
	unsigned long position = 1;
	long displacement = 0;
736
	unsigned int width;
737
	const char *sep = symbol_conf.field_sep;
738
	const char *col_width = symbol_conf.col_width_list_str;
739 740 741

	init_rem_hits();

742 743
	fprintf(fp, "# %s", pair ? "Baseline" : "Overhead");

744
	if (symbol_conf.show_nr_samples) {
745 746
		if (sep)
			fprintf(fp, "%cSamples", *sep);
747 748 749
		else
			fputs("  Samples  ", fp);
	}
750

751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768
	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  ");
			}
		}
	}

769 770 771 772 773 774 775 776 777 778 779 780 781 782
	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");
		}
	}

783 784 785
	list_for_each_entry(se, &hist_entry__sort_list, list) {
		if (se->elide)
			continue;
786
		if (sep) {
787
			fprintf(fp, "%c%s", *sep, se->se_header);
788 789
			continue;
		}
790
		width = strlen(se->se_header);
791 792 793 794 795 796 797
		if (symbol_conf.col_width_list_str) {
			if (col_width) {
				hists__set_col_len(self, se->se_width_idx,
						   atoi(col_width));
				col_width = strchr(col_width, ',');
				if (col_width)
					++col_width;
798 799
			}
		}
800 801
		if (!hists__new_col_len(self, se->se_width_idx, width))
			width = hists__col_len(self, se->se_width_idx);
802
		fprintf(fp, "  %*s", width, se->se_header);
803 804 805
	}
	fprintf(fp, "\n");

806
	if (sep)
807 808 809 810 811
		goto print_entries;

	fprintf(fp, "# ........");
	if (symbol_conf.show_nr_samples)
		fprintf(fp, " ..........");
812 813 814 815 816
	if (pair) {
		fprintf(fp, " ..........");
		if (show_displacement)
			fprintf(fp, " .....");
	}
817 818 819 820 821 822 823
	list_for_each_entry(se, &hist_entry__sort_list, list) {
		unsigned int i;

		if (se->elide)
			continue;

		fprintf(fp, "  ");
824 825
		width = hists__col_len(self, se->se_width_idx);
		if (width == 0)
826
			width = strlen(se->se_header);
827 828 829 830
		for (i = 0; i < width; i++)
			fprintf(fp, ".");
	}

831
	fprintf(fp, "\n#\n");
832 833

print_entries:
834
	for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
835 836 837 838 839 840 841 842 843 844
		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);

		if (show_displacement) {
			if (h->pair != NULL)
				displacement = ((long)h->pair->position -
					        (long)position);
			else
				displacement = 0;
			++position;
		}
845
		ret += hist_entry__fprintf(h, self, pair, show_displacement,
846
					   displacement, fp, self->stats.total_period);
847 848

		if (symbol_conf.use_callchain)
849 850
			ret += hist_entry__fprintf_callchain(h, self, fp,
							     self->stats.total_period);
851
		if (h->ms.map == NULL && verbose > 1) {
852
			__map_groups__fprintf_maps(&h->thread->mg,
853
						   MAP__FUNCTION, verbose, fp);
854 855
			fprintf(fp, "%.10s end\n", graph_dotted_line);
		}
856 857 858 859 860 861
	}

	free(rem_sq_bracket);

	return ret;
}
862

863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886
/*
 * See hists__fprintf to match the column widths
 */
unsigned int hists__sort_list_width(struct hists *self)
{
	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;

	list_for_each_entry(se, &hist_entry__sort_list, list)
		if (!se->elide)
			ret += 2 + hists__col_len(self, se->se_width_idx);

887 888 889
	if (verbose) /* Addr + origin */
		ret += 3 + BITS_PER_LONG / 4;

890 891 892
	return ret;
}

893 894 895 896 897 898 899 900
static void hists__remove_entry_filter(struct hists *self, struct hist_entry *h,
				       enum hist_filter filter)
{
	h->filtered &= ~(1 << filter);
	if (h->filtered)
		return;

	++self->nr_entries;
901 902 903
	if (h->ms.unfolded)
		self->nr_entries += h->nr_rows;
	h->row_offset = 0;
904 905 906
	self->stats.total_period += h->period;
	self->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events;

907
	hists__calc_col_len(self, h);
908 909
}

910 911 912 913
void hists__filter_by_dso(struct hists *self, const struct dso *dso)
{
	struct rb_node *nd;

914
	self->nr_entries = self->stats.total_period = 0;
915
	self->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
916
	hists__reset_col_len(self);
917 918 919 920 921 922 923 924 925 926 927 928

	for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
		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;
		}

929
		hists__remove_entry_filter(self, h, HIST_FILTER__DSO);
930 931 932 933 934 935 936
	}
}

void hists__filter_by_thread(struct hists *self, const struct thread *thread)
{
	struct rb_node *nd;

937
	self->nr_entries = self->stats.total_period = 0;
938
	self->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
939
	hists__reset_col_len(self);
940 941 942 943 944 945 946 947

	for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
		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;
		}
948 949

		hists__remove_entry_filter(self, h, HIST_FILTER__THREAD);
950 951
	}
}
952

953
int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip)
954
{
955
	return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip);
956 957
}

958
int hist_entry__annotate(struct hist_entry *he, size_t privsize)
959
{
960
	return symbol__annotate(he->ms.sym, he->ms.map, privsize);
961
}
962 963 964

void hists__inc_nr_events(struct hists *self, u32 type)
{
965 966
	++self->stats.nr_events[0];
	++self->stats.nr_events[type];
967 968 969 970 971 972 973 974
}

size_t hists__fprintf_nr_events(struct hists *self, FILE *fp)
{
	int i;
	size_t ret = 0;

	for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
975
		const char *name = perf_event__name(i);
976 977

		if (!strcmp(name, "UNKNOWN"))
978
			continue;
979 980 981

		ret += fprintf(fp, "%16s events: %10d\n", name,
			       self->stats.nr_events[i]);
982 983 984 985
	}

	return ret;
}