hist.c 12.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
#include <math.h>

#include "../util/hist.h"
#include "../util/util.h"
#include "../util/sort.h"


/* hist period print (hpp) functions */
static int hpp__header_overhead(struct perf_hpp *hpp)
{
11
	return scnprintf(hpp->buf, hpp->size, "Overhead");
12 13
}

14
static int hpp__width_overhead(struct perf_hpp *hpp __maybe_unused)
15 16 17 18 19 20
{
	return 8;
}

static int hpp__color_overhead(struct perf_hpp *hpp, struct hist_entry *he)
{
21
	struct hists *hists = he->hists;
22
	double percent = 100.0 * he->stat.period / hists->stats.total_period;
23

24
	return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent);
25 26 27 28
}

static int hpp__entry_overhead(struct perf_hpp *hpp, struct hist_entry *he)
{
29
	struct hists *hists = he->hists;
30
	double percent = 100.0 * he->stat.period / hists->stats.total_period;
31
	const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%";
32

33
	return scnprintf(hpp->buf, hpp->size, fmt, percent);
34 35 36 37
}

static int hpp__header_overhead_sys(struct perf_hpp *hpp)
{
38
	const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
39 40

	return scnprintf(hpp->buf, hpp->size, fmt, "sys");
41 42
}

43
static int hpp__width_overhead_sys(struct perf_hpp *hpp __maybe_unused)
44
{
45
	return 7;
46 47 48 49
}

static int hpp__color_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he)
{
50
	struct hists *hists = he->hists;
51
	double percent = 100.0 * he->stat.period_sys / hists->stats.total_period;
52

53
	return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent);
54 55 56 57
}

static int hpp__entry_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he)
{
58
	struct hists *hists = he->hists;
59
	double percent = 100.0 * he->stat.period_sys / hists->stats.total_period;
60
	const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
61 62

	return scnprintf(hpp->buf, hpp->size, fmt, percent);
63 64 65 66
}

static int hpp__header_overhead_us(struct perf_hpp *hpp)
{
67
	const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
68 69

	return scnprintf(hpp->buf, hpp->size, fmt, "user");
70 71
}

72
static int hpp__width_overhead_us(struct perf_hpp *hpp __maybe_unused)
73
{
74
	return 7;
75 76 77 78
}

static int hpp__color_overhead_us(struct perf_hpp *hpp, struct hist_entry *he)
{
79
	struct hists *hists = he->hists;
80
	double percent = 100.0 * he->stat.period_us / hists->stats.total_period;
81

82
	return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent);
83 84 85 86
}

static int hpp__entry_overhead_us(struct perf_hpp *hpp, struct hist_entry *he)
{
87
	struct hists *hists = he->hists;
88
	double percent = 100.0 * he->stat.period_us / hists->stats.total_period;
89
	const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
90 91

	return scnprintf(hpp->buf, hpp->size, fmt, percent);
92 93 94 95 96 97 98
}

static int hpp__header_overhead_guest_sys(struct perf_hpp *hpp)
{
	return scnprintf(hpp->buf, hpp->size, "guest sys");
}

99
static int hpp__width_overhead_guest_sys(struct perf_hpp *hpp __maybe_unused)
100 101 102 103 104 105 106
{
	return 9;
}

static int hpp__color_overhead_guest_sys(struct perf_hpp *hpp,
					 struct hist_entry *he)
{
107
	struct hists *hists = he->hists;
108
	double percent = 100.0 * he->stat.period_guest_sys / hists->stats.total_period;
109

110
	return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent);
111 112 113 114 115
}

static int hpp__entry_overhead_guest_sys(struct perf_hpp *hpp,
					 struct hist_entry *he)
{
116
	struct hists *hists = he->hists;
117
	double percent = 100.0 * he->stat.period_guest_sys / hists->stats.total_period;
118
	const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% ";
119 120

	return scnprintf(hpp->buf, hpp->size, fmt, percent);
121 122 123 124 125 126 127
}

static int hpp__header_overhead_guest_us(struct perf_hpp *hpp)
{
	return scnprintf(hpp->buf, hpp->size, "guest usr");
}

128
static int hpp__width_overhead_guest_us(struct perf_hpp *hpp __maybe_unused)
129 130 131 132 133 134 135
{
	return 9;
}

static int hpp__color_overhead_guest_us(struct perf_hpp *hpp,
					struct hist_entry *he)
{
136
	struct hists *hists = he->hists;
137
	double percent = 100.0 * he->stat.period_guest_us / hists->stats.total_period;
138

139
	return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent);
140 141 142 143 144
}

static int hpp__entry_overhead_guest_us(struct perf_hpp *hpp,
					struct hist_entry *he)
{
145
	struct hists *hists = he->hists;
146
	double percent = 100.0 * he->stat.period_guest_us / hists->stats.total_period;
147
	const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% ";
148 149

	return scnprintf(hpp->buf, hpp->size, fmt, percent);
150 151
}

152 153 154 155 156 157 158 159 160 161 162 163
static int hpp__header_baseline(struct perf_hpp *hpp)
{
	return scnprintf(hpp->buf, hpp->size, "Baseline");
}

static int hpp__width_baseline(struct perf_hpp *hpp __maybe_unused)
{
	return 8;
}

static double baseline_percent(struct hist_entry *he)
{
164
	struct hist_entry *pair = hist_entry__next_pair(he);
165 166 167 168 169
	struct hists *pair_hists = pair ? pair->hists : NULL;
	double percent = 0.0;

	if (pair) {
		u64 total_period = pair_hists->stats.total_period;
170
		u64 base_period  = pair->stat.period;
171 172 173 174 175 176 177 178 179 180 181

		percent = 100.0 * base_period / total_period;
	}

	return percent;
}

static int hpp__color_baseline(struct perf_hpp *hpp, struct hist_entry *he)
{
	double percent = baseline_percent(he);

182
	if (hist_entry__has_pairs(he))
183 184 185
		return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent);
	else
		return scnprintf(hpp->buf, hpp->size, "        ");
186 187 188 189 190 191 192
}

static int hpp__entry_baseline(struct perf_hpp *hpp, struct hist_entry *he)
{
	double percent = baseline_percent(he);
	const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%";

193
	if (hist_entry__has_pairs(he) || symbol_conf.field_sep)
194 195 196
		return scnprintf(hpp->buf, hpp->size, fmt, percent);
	else
		return scnprintf(hpp->buf, hpp->size, "            ");
197 198
}

199 200
static int hpp__header_samples(struct perf_hpp *hpp)
{
201 202 203
	const char *fmt = symbol_conf.field_sep ? "%s" : "%11s";

	return scnprintf(hpp->buf, hpp->size, fmt, "Samples");
204 205
}

206
static int hpp__width_samples(struct perf_hpp *hpp __maybe_unused)
207 208 209 210 211 212
{
	return 11;
}

static int hpp__entry_samples(struct perf_hpp *hpp, struct hist_entry *he)
{
213 214
	const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%11" PRIu64;

215
	return scnprintf(hpp->buf, hpp->size, fmt, he->stat.nr_events);
216 217 218 219
}

static int hpp__header_period(struct perf_hpp *hpp)
{
220 221 222
	const char *fmt = symbol_conf.field_sep ? "%s" : "%12s";

	return scnprintf(hpp->buf, hpp->size, fmt, "Period");
223 224
}

225
static int hpp__width_period(struct perf_hpp *hpp __maybe_unused)
226 227 228 229 230 231
{
	return 12;
}

static int hpp__entry_period(struct perf_hpp *hpp, struct hist_entry *he)
{
232 233
	const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64;

234
	return scnprintf(hpp->buf, hpp->size, fmt, he->stat.period);
235 236
}

237 238 239 240 241 242 243 244 245 246 247 248 249 250
static int hpp__header_period_baseline(struct perf_hpp *hpp)
{
	const char *fmt = symbol_conf.field_sep ? "%s" : "%12s";

	return scnprintf(hpp->buf, hpp->size, fmt, "Period Base");
}

static int hpp__width_period_baseline(struct perf_hpp *hpp __maybe_unused)
{
	return 12;
}

static int hpp__entry_period_baseline(struct perf_hpp *hpp, struct hist_entry *he)
{
251
	struct hist_entry *pair = hist_entry__next_pair(he);
252 253 254 255 256
	u64 period = pair ? pair->stat.period : 0;
	const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64;

	return scnprintf(hpp->buf, hpp->size, fmt, period);
}
257 258
static int hpp__header_delta(struct perf_hpp *hpp)
{
259 260 261
	const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";

	return scnprintf(hpp->buf, hpp->size, fmt, "Delta");
262 263
}

264
static int hpp__width_delta(struct perf_hpp *hpp __maybe_unused)
265 266 267 268 269 270
{
	return 7;
}

static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he)
{
271
	struct hist_entry *pair = hist_entry__next_pair(he);
272 273
	const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s";
	char buf[32] = " ";
274
	double diff = 0.0;
275

276 277 278 279 280 281 282
	if (pair) {
		if (he->diff.computed)
			diff = he->diff.period_ratio_delta;
		else
			diff = perf_diff__compute_delta(he, pair);
	} else
		diff = perf_diff__period_percent(he, he->stat.period);
283

284 285
	if (fabs(diff) >= 0.01)
		scnprintf(buf, sizeof(buf), "%+4.2F%%", diff);
286

287
	return scnprintf(hpp->buf, hpp->size, fmt, buf);
288 289
}

290 291 292 293 294 295 296 297 298 299 300 301 302 303
static int hpp__header_ratio(struct perf_hpp *hpp)
{
	const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";

	return scnprintf(hpp->buf, hpp->size, fmt, "Ratio");
}

static int hpp__width_ratio(struct perf_hpp *hpp __maybe_unused)
{
	return 14;
}

static int hpp__entry_ratio(struct perf_hpp *hpp, struct hist_entry *he)
{
304
	struct hist_entry *pair = hist_entry__next_pair(he);
305 306
	const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
	char buf[32] = " ";
307
	double ratio = 0.0;
308

309 310 311 312 313 314
	if (pair) {
		if (he->diff.computed)
			ratio = he->diff.period_ratio;
		else
			ratio = perf_diff__compute_ratio(he, pair);
	}
315 316 317 318 319 320 321

	if (ratio > 0.0)
		scnprintf(buf, sizeof(buf), "%+14.6F", ratio);

	return scnprintf(hpp->buf, hpp->size, fmt, buf);
}

322 323 324 325 326 327 328 329 330 331 332 333 334 335
static int hpp__header_wdiff(struct perf_hpp *hpp)
{
	const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";

	return scnprintf(hpp->buf, hpp->size, fmt, "Weighted diff");
}

static int hpp__width_wdiff(struct perf_hpp *hpp __maybe_unused)
{
	return 14;
}

static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he)
{
336
	struct hist_entry *pair = hist_entry__next_pair(he);
337 338
	const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
	char buf[32] = " ";
339
	s64 wdiff = 0;
340

341 342 343 344 345 346
	if (pair) {
		if (he->diff.computed)
			wdiff = he->diff.wdiff;
		else
			wdiff = perf_diff__compute_wdiff(he, pair);
	}
347 348 349 350 351 352 353

	if (wdiff != 0)
		scnprintf(buf, sizeof(buf), "%14ld", wdiff);

	return scnprintf(hpp->buf, hpp->size, fmt, buf);
}

354 355 356 357 358 359 360 361 362 363 364 365 366 367
static int hpp__header_formula(struct perf_hpp *hpp)
{
	const char *fmt = symbol_conf.field_sep ? "%s" : "%70s";

	return scnprintf(hpp->buf, hpp->size, fmt, "Formula");
}

static int hpp__width_formula(struct perf_hpp *hpp __maybe_unused)
{
	return 70;
}

static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he)
{
368
	struct hist_entry *pair = hist_entry__next_pair(he);
369 370 371
	const char *fmt = symbol_conf.field_sep ? "%s" : "%-70s";
	char buf[96] = " ";

372 373 374
	if (pair)
		perf_diff__formula(he, pair, buf, sizeof(buf));

375 376 377
	return scnprintf(hpp->buf, hpp->size, fmt, buf);
}

378 379 380 381 382 383 384
#define HPP__COLOR_PRINT_FNS(_name)			\
	{						\
		.header	= hpp__header_ ## _name,	\
		.width	= hpp__width_ ## _name,		\
		.color	= hpp__color_ ## _name,		\
		.entry	= hpp__entry_ ## _name		\
	}
385

386 387 388 389 390 391
#define HPP__PRINT_FNS(_name)				\
	{						\
		.header	= hpp__header_ ## _name,	\
		.width	= hpp__width_ ## _name,		\
		.entry	= hpp__entry_ ## _name		\
	}
392 393

struct perf_hpp_fmt perf_hpp__format[] = {
394 395 396 397 398 399 400 401 402 403 404 405 406
	HPP__COLOR_PRINT_FNS(baseline),
	HPP__COLOR_PRINT_FNS(overhead),
	HPP__COLOR_PRINT_FNS(overhead_sys),
	HPP__COLOR_PRINT_FNS(overhead_us),
	HPP__COLOR_PRINT_FNS(overhead_guest_sys),
	HPP__COLOR_PRINT_FNS(overhead_guest_us),
	HPP__PRINT_FNS(samples),
	HPP__PRINT_FNS(period),
	HPP__PRINT_FNS(period_baseline),
	HPP__PRINT_FNS(delta),
	HPP__PRINT_FNS(ratio),
	HPP__PRINT_FNS(wdiff),
	HPP__PRINT_FNS(formula)
407 408
};

409 410
LIST_HEAD(perf_hpp__list);

411 412 413
#undef HPP__COLOR_PRINT_FNS
#undef HPP__PRINT_FNS

414
void perf_hpp__init(void)
415 416
{
	if (symbol_conf.show_cpu_utilization) {
417 418
		perf_hpp__column_enable(PERF_HPP__OVERHEAD_SYS);
		perf_hpp__column_enable(PERF_HPP__OVERHEAD_US);
419 420

		if (perf_guest) {
421 422
			perf_hpp__column_enable(PERF_HPP__OVERHEAD_GUEST_SYS);
			perf_hpp__column_enable(PERF_HPP__OVERHEAD_GUEST_US);
423 424 425 426
		}
	}

	if (symbol_conf.show_nr_samples)
427
		perf_hpp__column_enable(PERF_HPP__SAMPLES);
428 429

	if (symbol_conf.show_total_period)
430
		perf_hpp__column_enable(PERF_HPP__PERIOD);
431
}
432

433 434 435 436 437 438
void perf_hpp__column_register(struct perf_hpp_fmt *format)
{
	list_add_tail(&format->list, &perf_hpp__list);
}

void perf_hpp__column_enable(unsigned col)
439 440
{
	BUG_ON(col >= PERF_HPP__MAX_INDEX);
441
	perf_hpp__column_register(&perf_hpp__format[col]);
442 443 444 445 446 447 448 449 450 451 452 453
}

static inline void advance_hpp(struct perf_hpp *hpp, int inc)
{
	hpp->buf  += inc;
	hpp->size -= inc;
}

int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
				bool color)
{
	const char *sep = symbol_conf.field_sep;
454
	struct perf_hpp_fmt *fmt;
455
	char *start = hpp->buf;
456
	int ret;
457
	bool first = true;
458 459 460 461

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

462
	perf_hpp__for_each_format(fmt) {
463 464 465 466
		/*
		 * If there's no field_sep, we still need
		 * to display initial '  '.
		 */
467
		if (!sep || !first) {
468 469
			ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: "  ");
			advance_hpp(hpp, ret);
470
		} else
471
			first = false;
472

473 474
		if (color && fmt->color)
			ret = fmt->color(hpp, he);
475
		else
476
			ret = fmt->entry(hpp, he);
477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501

		advance_hpp(hpp, ret);
	}

	return hpp->buf - start;
}

int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size,
			      struct hists *hists)
{
	const char *sep = symbol_conf.field_sep;
	struct sort_entry *se;
	int ret = 0;

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

		ret += scnprintf(s + ret, size - ret, "%s", sep ?: "  ");
		ret += se->se_snprintf(he, s + ret, size - ret,
				       hists__col_len(hists, se->se_width_idx));
	}

	return ret;
}
502 503 504 505 506 507

/*
 * See hists__fprintf to match the column widths
 */
unsigned int hists__sort_list_width(struct hists *hists)
{
508
	struct perf_hpp_fmt *fmt;
509
	struct sort_entry *se;
510
	int i = 0, ret = 0;
511

512
	perf_hpp__for_each_format(fmt) {
513 514 515
		if (i)
			ret += 2;

516
		ret += fmt->width(NULL);
517 518 519 520 521 522 523 524 525 526 527
	}

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

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

	return ret;
}