hist.c 26.7 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 97 98 99 100 101 102
static void hist_entry__decay(struct hist_entry *he)
{
	he->period = (he->period * 7) / 8;
	he->nr_events = (he->nr_events * 7) / 8;
}

static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
{
103 104
	if (he->period == 0)
		return true;
105 106 107 108 109 110 111 112 113 114 115 116 117 118
	hists->stats.total_period -= he->period;
	hist_entry__decay(he);
	hists->stats.total_period += he->period;
	return he->period == 0;
}

void hists__decay_entries(struct hists *hists)
{
	struct rb_node *next = rb_first(&hists->entries);
	struct hist_entry *n;

	while (next) {
		n = rb_entry(next, struct hist_entry, rb_node);
		next = rb_next(&n->rb_node);
119 120 121 122 123 124
		/*
		 * We may be annotating this, for instance, so keep it here in
		 * case some it gets new samples, we'll eventually free it when
		 * the user stops browsing and it agains gets fully decayed.
		 */
		if (hists__decay_entry(hists, n) && !n->used) {
125 126 127 128 129 130 131 132 133 134 135
			rb_erase(&n->rb_node, &hists->entries);

			if (sort__need_collapse)
				rb_erase(&n->rb_node_in, &hists->entries_collapsed);

			hist_entry__free(n);
			--hists->nr_entries;
		}
	}
}

136
/*
137
 * histogram, sorted on item, collects periods
138 139
 */

140 141
static struct hist_entry *hist_entry__new(struct hist_entry *template)
{
142
	size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_root) : 0;
143 144 145 146
	struct hist_entry *self = malloc(sizeof(*self) + callchain_size);

	if (self != NULL) {
		*self = *template;
147
		self->nr_events = 1;
148 149
		if (self->ms.map)
			self->ms.map->referenced = true;
150 151 152 153 154 155 156
		if (symbol_conf.use_callchain)
			callchain_init(self->callchain);
	}

	return self;
}

157
static void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h)
158
{
159
	if (!h->filtered) {
160 161
		hists__calc_col_len(hists, h);
		++hists->nr_entries;
162
		hists->stats.total_period += h->period;
163
	}
164 165
}

166 167 168 169 170 171 172
static u8 symbol__parent_filter(const struct symbol *parent)
{
	if (symbol_conf.exclude_other && parent == NULL)
		return 1 << HIST_FILTER__PARENT;
	return 0;
}

173
struct hist_entry *__hists__add_entry(struct hists *hists,
174
				      struct addr_location *al,
175
				      struct symbol *sym_parent, u64 period)
176
{
177
	struct rb_node **p;
178 179 180
	struct rb_node *parent = NULL;
	struct hist_entry *he;
	struct hist_entry entry = {
181
		.thread	= al->thread,
182 183 184 185
		.ms = {
			.map	= al->map,
			.sym	= al->sym,
		},
A
Arun Sharma 已提交
186
		.cpu	= al->cpu,
187 188
		.ip	= al->addr,
		.level	= al->level,
189
		.period	= period,
190
		.parent = sym_parent,
191
		.filtered = symbol__parent_filter(sym_parent),
192 193 194
	};
	int cmp;

195 196 197 198
	pthread_mutex_lock(&hists->lock);

	p = &hists->entries_in->rb_node;

199 200
	while (*p != NULL) {
		parent = *p;
201
		he = rb_entry(parent, struct hist_entry, rb_node_in);
202 203 204 205

		cmp = hist_entry__cmp(&entry, he);

		if (!cmp) {
206 207
			he->period += period;
			++he->nr_events;
208
			goto out;
209 210 211 212 213 214 215 216
		}

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

217
	he = hist_entry__new(&entry);
218
	if (!he)
219 220 221 222
		goto out_unlock;

	rb_link_node(&he->rb_node_in, parent, p);
	rb_insert_color(&he->rb_node_in, hists->entries_in);
223
out:
224
	hist_entry__add_cpumode_period(he, al->cpumode, period);
225 226
out_unlock:
	pthread_mutex_unlock(&hists->lock);
227 228 229
	return he;
}

230 231 232 233 234 235 236
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) {
237
		cmp = se->se_cmp(left, right);
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
		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 *);

254
		f = se->se_collapse ?: se->se_cmp;
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272

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

	return cmp;
}

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

/*
 * collapse the histogram
 */

273
static bool hists__collapse_insert_entry(struct hists *hists,
274 275
					 struct rb_root *root,
					 struct hist_entry *he)
276
{
277
	struct rb_node **p = &root->rb_node;
278 279 280 281 282 283
	struct rb_node *parent = NULL;
	struct hist_entry *iter;
	int64_t cmp;

	while (*p != NULL) {
		parent = *p;
284
		iter = rb_entry(parent, struct hist_entry, rb_node_in);
285 286 287 288

		cmp = hist_entry__collapse(iter, he);

		if (!cmp) {
289
			iter->period += he->period;
290
			iter->nr_events += he->nr_events;
291
			if (symbol_conf.use_callchain) {
292 293
				callchain_cursor_reset(&hists->callchain_cursor);
				callchain_merge(&hists->callchain_cursor, iter->callchain,
294 295
						he->callchain);
			}
296
			hist_entry__free(he);
297
			return false;
298 299 300 301 302 303 304 305
		}

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

306 307
	rb_link_node(&he->rb_node_in, parent, p);
	rb_insert_color(&he->rb_node_in, root);
308
	return true;
309 310
}

311
static struct rb_root *hists__get_rotate_entries_in(struct hists *hists)
312
{
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
	struct rb_root *root;

	pthread_mutex_lock(&hists->lock);

	root = hists->entries_in;
	if (++hists->entries_in > &hists->entries_in_array[1])
		hists->entries_in = &hists->entries_in_array[0];

	pthread_mutex_unlock(&hists->lock);

	return root;
}

static void __hists__collapse_resort(struct hists *hists, bool threaded)
{
	struct rb_root *root;
329 330 331
	struct rb_node *next;
	struct hist_entry *n;

332
	if (!sort__need_collapse && !threaded)
333 334
		return;

335 336 337
	root = hists__get_rotate_entries_in(hists);
	next = rb_first(root);
	hists->stats.total_period = 0;
338

339
	while (next) {
340 341
		n = rb_entry(next, struct hist_entry, rb_node_in);
		next = rb_next(&n->rb_node_in);
342

343 344
		rb_erase(&n->rb_node_in, root);
		if (hists__collapse_insert_entry(hists, &hists->entries_collapsed, n))
345
			hists__inc_nr_entries(hists, n);
346
	}
347
}
348

349 350 351 352 353 354 355 356
void hists__collapse_resort(struct hists *hists)
{
	return __hists__collapse_resort(hists, false);
}

void hists__collapse_resort_threaded(struct hists *hists)
{
	return __hists__collapse_resort(hists, true);
357 358 359
}

/*
360
 * reverse the map, sort on period.
361 362
 */

363 364 365
static void __hists__insert_output_entry(struct rb_root *entries,
					 struct hist_entry *he,
					 u64 min_callchain_hits)
366
{
367
	struct rb_node **p = &entries->rb_node;
368 369 370
	struct rb_node *parent = NULL;
	struct hist_entry *iter;

371
	if (symbol_conf.use_callchain)
372
		callchain_param.sort(&he->sorted_chain, he->callchain,
373 374 375 376 377 378
				      min_callchain_hits, &callchain_param);

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

379
		if (he->period > iter->period)
380 381 382 383 384 385
			p = &(*p)->rb_left;
		else
			p = &(*p)->rb_right;
	}

	rb_link_node(&he->rb_node, parent, p);
386
	rb_insert_color(&he->rb_node, entries);
387 388
}

389
static void __hists__output_resort(struct hists *hists, bool threaded)
390
{
391
	struct rb_root *root;
392 393 394 395
	struct rb_node *next;
	struct hist_entry *n;
	u64 min_callchain_hits;

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

398 399 400 401 402 403 404
	if (sort__need_collapse || threaded)
		root = &hists->entries_collapsed;
	else
		root = hists->entries_in;

	next = rb_first(root);
	hists->entries = RB_ROOT;
405

406 407
	hists->nr_entries = 0;
	hists__reset_col_len(hists);
408

409
	while (next) {
410 411
		n = rb_entry(next, struct hist_entry, rb_node_in);
		next = rb_next(&n->rb_node_in);
412

413
		__hists__insert_output_entry(&hists->entries, n, min_callchain_hits);
414
		hists__inc_nr_entries(hists, n);
415
	}
416
}
417

418 419 420 421 422 423 424 425
void hists__output_resort(struct hists *hists)
{
	return __hists__output_resort(hists, false);
}

void hists__output_resort_threaded(struct hists *hists)
{
	return __hists__output_resort(hists, true);
426
}
427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456

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,
457
				     int depth, int depth_mask, int period,
458
				     u64 total_samples, u64 hits,
459 460 461 462 463 464 465 466 467 468 469
				     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, " ");
470
		if (!period && i == depth - 1) {
471 472 473 474 475 476 477
			double percent;

			percent = hits * 100.0 / total_samples;
			ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
		} else
			ret += fprintf(fp, "%s", "          ");
	}
478 479
	if (chain->ms.sym)
		ret += fprintf(fp, "%s\n", chain->ms.sym->name);
480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497
	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, "[...]");
498
	rem_hits.ms.sym = rem_sq_bracket;
499 500 501 502 503 504 505 506 507 508 509 510 511 512
}

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;
513
	uint entries_printed = 0;
514 515 516 517 518 519 520 521 522 523 524 525 526

	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);
527
		cumul = callchain_cumul_hits(child);
528 529 530 531 532 533 534 535 536 537 538 539 540 541
		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 已提交
542
		 * But we keep the older depth mask for the line separator
543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559
		 * 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;
560 561
		if (++entries_printed == callchain_param.print_limit)
			break;
562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586
	}

	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;
587
	u32 entries_printed = 0;
588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603

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

604 605
		if (chain->ms.sym)
			ret += fprintf(fp, " %s\n", chain->ms.sym->name);
606 607
		else
			ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
608 609 610

		if (++entries_printed == callchain_param.print_limit)
			break;
611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632
	}

	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;
633 634
		if (chain->ms.sym)
			ret += fprintf(fp, "                %s\n", chain->ms.sym->name);
635 636 637 638 639 640 641 642 643 644 645 646 647 648
		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;
649
	u32 entries_printed = 0;
650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671

	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");
672 673
		if (++entries_printed == callchain_param.print_limit)
			break;
674 675 676 677 678 679
		rb_node = rb_next(rb_node);
	}

	return ret;
}

680 681 682 683 684 685 686 687 688 689 690 691 692 693 694
void hists__output_recalc_col_len(struct hists *hists, int max_rows)
{
	struct rb_node *next = rb_first(&hists->entries);
	struct hist_entry *n;
	int row = 0;

	hists__reset_col_len(hists);

	while (next && row++ < max_rows) {
		n = rb_entry(next, struct hist_entry, rb_node);
		hists__calc_col_len(hists, n);
		next = rb_next(&n->rb_node);
	}
}

695
int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
696 697 698
			 struct hists *hists, struct hists *pair_hists,
			 bool show_displacement, long displacement,
			 bool color, u64 session_total)
699 700
{
	struct sort_entry *se;
701
	u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us;
702
	u64 nr_events;
703
	const char *sep = symbol_conf.field_sep;
704
	int ret;
705 706 707 708

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

709
	if (pair_hists) {
710
		period = self->pair ? self->pair->period : 0;
711
		nr_events = self->pair ? self->pair->nr_events : 0;
712
		total = pair_hists->stats.total_period;
713 714 715 716
		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;
717
	} else {
718
		period = self->period;
719
		nr_events = self->nr_events;
720
		total = session_total;
721 722 723 724
		period_sys = self->period_sys;
		period_us = self->period_us;
		period_guest_sys = self->period_guest_sys;
		period_guest_us = self->period_guest_us;
725 726
	}

727 728 729 730
	if (total) {
		if (color)
			ret = percent_color_snprintf(s, size,
						     sep ? "%.2f" : "   %6.2f%%",
731
						     (period * 100.0) / total);
732 733
		else
			ret = snprintf(s, size, sep ? "%.2f" : "   %6.2f%%",
734
				       (period * 100.0) / total);
735 736 737
		if (symbol_conf.show_cpu_utilization) {
			ret += percent_color_snprintf(s + ret, size - ret,
					sep ? "%.2f" : "   %6.2f%%",
738
					(period_sys * 100.0) / total);
739 740
			ret += percent_color_snprintf(s + ret, size - ret,
					sep ? "%.2f" : "   %6.2f%%",
741
					(period_us * 100.0) / total);
742 743 744 745
			if (perf_guest) {
				ret += percent_color_snprintf(s + ret,
						size - ret,
						sep ? "%.2f" : "   %6.2f%%",
746
						(period_guest_sys * 100.0) /
747 748 749 750
								total);
				ret += percent_color_snprintf(s + ret,
						size - ret,
						sep ? "%.2f" : "   %6.2f%%",
751
						(period_guest_us * 100.0) /
752 753 754
								total);
			}
		}
755
	} else
756
		ret = snprintf(s, size, sep ? "%" PRIu64 : "%12" PRIu64 " ", period);
757 758

	if (symbol_conf.show_nr_samples) {
759
		if (sep)
760
			ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, nr_events);
761
		else
762
			ret += snprintf(s + ret, size - ret, "%11" PRIu64, nr_events);
763 764
	}

765 766 767 768 769 770 771
	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);
	}

772
	if (pair_hists) {
773 774 775 776
		char bf[32];
		double old_percent = 0, new_percent = 0, diff;

		if (total > 0)
777
			old_percent = (period * 100.0) / total;
778
		if (session_total > 0)
779
			new_percent = (self->period * 100.0) / session_total;
780

781
		diff = new_percent - old_percent;
782

783
		if (fabs(diff) >= 0.01)
784 785 786 787 788
			snprintf(bf, sizeof(bf), "%+4.2F%%", diff);
		else
			snprintf(bf, sizeof(bf), " ");

		if (sep)
789
			ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
790
		else
791
			ret += snprintf(s + ret, size - ret, "%11.11s", bf);
792 793 794 795 796 797 798 799

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

			if (sep)
800
				ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
801
			else
802
				ret += snprintf(s + ret, size - ret, "%6.6s", bf);
803
		}
804 805 806 807 808 809
	}

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

810
		ret += snprintf(s + ret, size - ret, "%s", sep ?: "  ");
811
		ret += se->se_snprintf(self, s + ret, size - ret,
812
				       hists__col_len(hists, se->se_width_idx));
813 814
	}

815 816 817
	return ret;
}

818
int hist_entry__fprintf(struct hist_entry *he, size_t size, struct hists *hists,
819 820
			struct hists *pair_hists, bool show_displacement,
			long displacement, FILE *fp, u64 session_total)
821 822
{
	char bf[512];
823 824 825 826 827

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

	hist_entry__snprintf(he, bf, size, hists, pair_hists,
828 829 830
			     show_displacement, displacement,
			     true, session_total);
	return fprintf(fp, "%s\n", bf);
831
}
832

833 834
static size_t hist_entry__fprintf_callchain(struct hist_entry *self,
					    struct hists *hists, FILE *fp,
835 836 837
					    u64 session_total)
{
	int left_margin = 0;
838

839 840 841
	if (sort__first_dimension == SORT_COMM) {
		struct sort_entry *se = list_first_entry(&hist_entry__sort_list,
							 typeof(*se), list);
842
		left_margin = hists__col_len(hists, se->se_width_idx);
843
		left_margin -= thread__comm_len(self->thread);
844 845
	}

846 847
	return hist_entry_callchain__fprintf(fp, self, session_total,
					     left_margin);
848 849
}

850
size_t hists__fprintf(struct hists *hists, struct hists *pair,
851 852
		      bool show_displacement, bool show_header, int max_rows,
		      int max_cols, FILE *fp)
853 854 855 856
{
	struct sort_entry *se;
	struct rb_node *nd;
	size_t ret = 0;
857 858
	unsigned long position = 1;
	long displacement = 0;
859
	unsigned int width;
860
	const char *sep = symbol_conf.field_sep;
861
	const char *col_width = symbol_conf.col_width_list_str;
862
	int nr_rows = 0;
863 864 865

	init_rem_hits();

866 867 868
	if (!show_header)
		goto print_entries;

869 870
	fprintf(fp, "# %s", pair ? "Baseline" : "Overhead");

871
	if (symbol_conf.show_nr_samples) {
872 873
		if (sep)
			fprintf(fp, "%cSamples", *sep);
874 875 876
		else
			fputs("  Samples  ", fp);
	}
877

878 879 880 881 882 883 884
	if (symbol_conf.show_total_period) {
		if (sep)
			ret += fprintf(fp, "%cPeriod", *sep);
		else
			ret += fprintf(fp, "   Period    ");
	}

885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902
	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  ");
			}
		}
	}

903 904 905 906 907 908 909 910 911 912 913 914 915 916
	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");
		}
	}

917 918 919
	list_for_each_entry(se, &hist_entry__sort_list, list) {
		if (se->elide)
			continue;
920
		if (sep) {
921
			fprintf(fp, "%c%s", *sep, se->se_header);
922 923
			continue;
		}
924
		width = strlen(se->se_header);
925 926
		if (symbol_conf.col_width_list_str) {
			if (col_width) {
927
				hists__set_col_len(hists, se->se_width_idx,
928 929 930 931
						   atoi(col_width));
				col_width = strchr(col_width, ',');
				if (col_width)
					++col_width;
932 933
			}
		}
934 935
		if (!hists__new_col_len(hists, se->se_width_idx, width))
			width = hists__col_len(hists, se->se_width_idx);
936
		fprintf(fp, "  %*s", width, se->se_header);
937
	}
938

939
	fprintf(fp, "\n");
940 941
	if (max_rows && ++nr_rows >= max_rows)
		goto out;
942

943
	if (sep)
944 945 946 947 948
		goto print_entries;

	fprintf(fp, "# ........");
	if (symbol_conf.show_nr_samples)
		fprintf(fp, " ..........");
949 950
	if (symbol_conf.show_total_period)
		fprintf(fp, " ............");
951 952 953 954 955
	if (pair) {
		fprintf(fp, " ..........");
		if (show_displacement)
			fprintf(fp, " .....");
	}
956 957 958 959 960 961 962
	list_for_each_entry(se, &hist_entry__sort_list, list) {
		unsigned int i;

		if (se->elide)
			continue;

		fprintf(fp, "  ");
963
		width = hists__col_len(hists, se->se_width_idx);
964
		if (width == 0)
965
			width = strlen(se->se_header);
966 967 968 969
		for (i = 0; i < width; i++)
			fprintf(fp, ".");
	}

970 971 972 973 974 975 976
	fprintf(fp, "\n");
	if (max_rows && ++nr_rows >= max_rows)
		goto out;

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

print_entries:
979
	for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
980 981
		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);

982 983 984
		if (h->filtered)
			continue;

985 986 987 988 989 990 991 992
		if (show_displacement) {
			if (h->pair != NULL)
				displacement = ((long)h->pair->position -
					        (long)position);
			else
				displacement = 0;
			++position;
		}
993
		ret += hist_entry__fprintf(h, max_cols, hists, pair, show_displacement,
994
					   displacement, fp, hists->stats.total_period);
995 996

		if (symbol_conf.use_callchain)
997 998
			ret += hist_entry__fprintf_callchain(h, hists, fp,
							     hists->stats.total_period);
999 1000 1001
		if (max_rows && ++nr_rows >= max_rows)
			goto out;

1002
		if (h->ms.map == NULL && verbose > 1) {
1003
			__map_groups__fprintf_maps(&h->thread->mg,
1004
						   MAP__FUNCTION, verbose, fp);
1005 1006
			fprintf(fp, "%.10s end\n", graph_dotted_line);
		}
1007
	}
1008
out:
1009 1010 1011 1012
	free(rem_sq_bracket);

	return ret;
}
1013

1014 1015 1016
/*
 * See hists__fprintf to match the column widths
 */
1017
unsigned int hists__sort_list_width(struct hists *hists)
1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033
{
	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;

1034 1035 1036
	if (symbol_conf.show_total_period)
		ret += 13;

1037 1038
	list_for_each_entry(se, &hist_entry__sort_list, list)
		if (!se->elide)
1039
			ret += 2 + hists__col_len(hists, se->se_width_idx);
1040

1041 1042 1043
	if (verbose) /* Addr + origin */
		ret += 3 + BITS_PER_LONG / 4;

1044 1045 1046
	return ret;
}

1047
static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h,
1048 1049 1050 1051 1052 1053
				       enum hist_filter filter)
{
	h->filtered &= ~(1 << filter);
	if (h->filtered)
		return;

1054
	++hists->nr_entries;
1055
	if (h->ms.unfolded)
1056
		hists->nr_entries += h->nr_rows;
1057
	h->row_offset = 0;
1058 1059
	hists->stats.total_period += h->period;
	hists->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events;
1060

1061
	hists__calc_col_len(hists, h);
1062 1063
}

1064
void hists__filter_by_dso(struct hists *hists, const struct dso *dso)
1065 1066 1067
{
	struct rb_node *nd;

1068 1069 1070
	hists->nr_entries = hists->stats.total_period = 0;
	hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
	hists__reset_col_len(hists);
1071

1072
	for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
1073 1074 1075 1076 1077 1078 1079 1080 1081 1082
		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;
		}

1083
		hists__remove_entry_filter(hists, h, HIST_FILTER__DSO);
1084 1085 1086
	}
}

1087
void hists__filter_by_thread(struct hists *hists, const struct thread *thread)
1088 1089 1090
{
	struct rb_node *nd;

1091 1092 1093
	hists->nr_entries = hists->stats.total_period = 0;
	hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
	hists__reset_col_len(hists);
1094

1095
	for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
1096 1097 1098 1099 1100 1101
		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;
		}
1102

1103
		hists__remove_entry_filter(hists, h, HIST_FILTER__THREAD);
1104 1105
	}
}
1106

1107
int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip)
1108
{
1109
	return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip);
1110 1111
}

1112
int hist_entry__annotate(struct hist_entry *he, size_t privsize)
1113
{
1114
	return symbol__annotate(he->ms.sym, he->ms.map, privsize);
1115
}
1116

1117
void hists__inc_nr_events(struct hists *hists, u32 type)
1118
{
1119 1120
	++hists->stats.nr_events[0];
	++hists->stats.nr_events[type];
1121 1122
}

1123
size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp)
1124 1125 1126 1127 1128
{
	int i;
	size_t ret = 0;

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

1131
		if (hists->stats.nr_events[i] == 0)
1132 1133 1134
			continue;

		name = perf_event__name(i);
1135
		if (!strcmp(name, "UNKNOWN"))
1136
			continue;
1137 1138

		ret += fprintf(fp, "%16s events: %10d\n", name,
1139
			       hists->stats.nr_events[i]);
1140 1141 1142 1143
	}

	return ret;
}
1144 1145 1146 1147 1148 1149 1150 1151 1152 1153

void hists__init(struct hists *hists)
{
	memset(hists, 0, sizeof(*hists));
	hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT;
	hists->entries_in = &hists->entries_in_array[0];
	hists->entries_collapsed = RB_ROOT;
	hists->entries = RB_ROOT;
	pthread_mutex_init(&hists->lock, NULL);
}