builtin-stat.c 13.5 KB
Newer Older
1
/*
2 3 4 5 6 7
 * builtin-stat.c
 *
 * Builtin stat command: Give a precise performance counters summary
 * overview about any workload, CPU or specific PID.
 *
 * Sample output:
8

9 10
   $ perf stat ~/hackbench 10
   Time: 0.104
11

12
    Performance counter stats for '/home/mingo/hackbench':
13

14 15 16 17 18 19 20 21
       1255.538611  task clock ticks     #      10.143 CPU utilization factor
             54011  context switches     #       0.043 M/sec
               385  CPU migrations       #       0.000 M/sec
             17755  pagefaults           #       0.014 M/sec
        3808323185  CPU cycles           #    3033.219 M/sec
        1575111190  instructions         #    1254.530 M/sec
          17367895  cache references     #      13.833 M/sec
           7674421  cache misses         #       6.112 M/sec
22

23
    Wall-clock time elapsed:   123.786620 msecs
24

25 26 27 28 29 30 31 32 33 34
 *
 * Copyright (C) 2008, Red Hat Inc, Ingo Molnar <mingo@redhat.com>
 *
 * Improvements and fixes by:
 *
 *   Arjan van de Ven <arjan@linux.intel.com>
 *   Yanmin Zhang <yanmin.zhang@intel.com>
 *   Wu Fengguang <fengguang.wu@intel.com>
 *   Mike Galbraith <efault@gmx.de>
 *   Paul Mackerras <paulus@samba.org>
35
 *   Jaswinder Singh Rajput <jaswinder@kernel.org>
36 37
 *
 * Released under the GPL v2. (and only v2, not any later version)
38 39
 */

40
#include "perf.h"
41
#include "builtin.h"
42
#include "util/util.h"
43 44
#include "util/parse-options.h"
#include "util/parse-events.h"
45 46

#include <sys/prctl.h>
47
#include <math.h>
48

49
static struct perf_counter_attr default_attrs[] = {
50

51 52 53 54 55 56 57 58 59 60
  { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK	},
  { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES},
  { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_MIGRATIONS	},
  { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS	},

  { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES	},
  { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS	},
  { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_REFERENCES},
  { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_MISSES	},

61
};
62

63 64
#define MAX_RUN			100

65
static int			system_wide			=  0;
66
static int			verbose				=  0;
67
static int			nr_cpus				=  0;
68
static int			run_idx				=  0;
69

70 71
static int			run_count			=  1;
static int			inherit				=  1;
72
static int			scale				=  1;
73
static int			target_pid			= -1;
74
static int			null_run			=  0;
75

76
static int			fd[MAX_NR_CPUS][MAX_COUNTERS];
77

78 79 80
static u64			runtime_nsecs[MAX_RUN];
static u64			walltime_nsecs[MAX_RUN];
static u64			runtime_cycles[MAX_RUN];
81

82 83 84
static u64			event_res[MAX_RUN][MAX_COUNTERS][3];
static u64			event_scaled[MAX_RUN][MAX_COUNTERS];

85 86
static u64			event_res_avg[MAX_COUNTERS][3];
static u64			event_res_noise[MAX_COUNTERS][3];
87

88
static u64			event_scaled_avg[MAX_COUNTERS];
89

90 91
static u64			runtime_nsecs_avg;
static u64			runtime_nsecs_noise;
92

93 94
static u64			walltime_nsecs_avg;
static u64			walltime_nsecs_noise;
95

96 97
static u64			runtime_cycles_avg;
static u64			runtime_cycles_noise;
98

99 100 101
#define ERR_PERF_OPEN \
"Error: counter %d, sys_perf_counter_open() syscall returned with %d (%s)\n"

102
static void create_perf_stat_counter(int counter, int pid)
103
{
104
	struct perf_counter_attr *attr = attrs + counter;
105

106
	if (scale)
107 108
		attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
				    PERF_FORMAT_TOTAL_TIME_RUNNING;
109 110 111

	if (system_wide) {
		int cpu;
112
		for (cpu = 0; cpu < nr_cpus; cpu++) {
113
			fd[cpu][counter] = sys_perf_counter_open(attr, -1, cpu, -1, 0);
114 115 116
			if (fd[cpu][counter] < 0 && verbose)
				fprintf(stderr, ERR_PERF_OPEN, counter,
					fd[cpu][counter], strerror(errno));
117 118
		}
	} else {
119 120 121
		attr->inherit	     = inherit;
		attr->disabled	     = 1;
		attr->enable_on_exec = 1;
122

123
		fd[0][counter] = sys_perf_counter_open(attr, pid, -1, -1, 0);
124 125 126
		if (fd[0][counter] < 0 && verbose)
			fprintf(stderr, ERR_PERF_OPEN, counter,
				fd[0][counter], strerror(errno));
127 128 129
	}
}

130 131 132 133 134
/*
 * Does the counter have nsecs as a unit?
 */
static inline int nsec_counter(int counter)
{
135 136 137
	if (attrs[counter].type != PERF_TYPE_SOFTWARE)
		return 0;

138
	if (attrs[counter].config == PERF_COUNT_SW_CPU_CLOCK)
139
		return 1;
140

141
	if (attrs[counter].config == PERF_COUNT_SW_TASK_CLOCK)
142 143 144 145 146 147
		return 1;

	return 0;
}

/*
148
 * Read out the results of a single counter:
149
 */
150
static void read_counter(int counter)
151
{
152
	u64 *count, single_count[3];
153 154 155 156
	ssize_t res;
	int cpu, nv;
	int scaled;

157
	count = event_res[run_idx][counter];
158

159
	count[0] = count[1] = count[2] = 0;
160

161
	nv = scale ? 3 : 1;
162
	for (cpu = 0; cpu < nr_cpus; cpu++) {
163 164 165
		if (fd[cpu][counter] < 0)
			continue;

166 167
		res = read(fd[cpu][counter], single_count, nv * sizeof(u64));
		assert(res == nv * sizeof(u64));
168 169
		close(fd[cpu][counter]);
		fd[cpu][counter] = -1;
170 171 172 173 174 175 176 177 178 179 180

		count[0] += single_count[0];
		if (scale) {
			count[1] += single_count[1];
			count[2] += single_count[2];
		}
	}

	scaled = 0;
	if (scale) {
		if (count[2] == 0) {
181
			event_scaled[run_idx][counter] = -1;
182
			count[0] = 0;
183 184
			return;
		}
185

186
		if (count[2] < count[1]) {
187
			event_scaled[run_idx][counter] = 1;
188 189 190 191
			count[0] = (unsigned long long)
				((double)count[0] * count[1] / count[2] + 0.5);
		}
	}
192 193 194
	/*
	 * Save the full runtime - to allow normalization during printout:
	 */
195
	if (attrs[counter].type == PERF_TYPE_SOFTWARE &&
196
		attrs[counter].config == PERF_COUNT_SW_TASK_CLOCK)
197
		runtime_nsecs[run_idx] = count[0];
198
	if (attrs[counter].type == PERF_TYPE_HARDWARE &&
199
		attrs[counter].config == PERF_COUNT_HW_CPU_CYCLES)
200
		runtime_cycles[run_idx] = count[0];
201 202
}

203 204 205 206 207 208
static int run_perf_stat(int argc, const char **argv)
{
	unsigned long long t0, t1;
	int status = 0;
	int counter;
	int pid;
209 210
	int child_ready_pipe[2], go_pipe[2];
	char buf;
211 212 213 214

	if (!system_wide)
		nr_cpus = 1;

215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
	if (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0) {
		perror("failed to create pipes");
		exit(1);
	}

	if ((pid = fork()) < 0)
		perror("failed to fork");

	if (!pid) {
		close(child_ready_pipe[0]);
		close(go_pipe[1]);
		fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);

		/*
		 * Do a dummy execvp to get the PLT entry resolved,
		 * so we avoid the resolver overhead on the real
		 * execvp call.
		 */
		execvp("", (char **)argv);

		/*
		 * Tell the parent we're ready to go
		 */
		close(child_ready_pipe[1]);

		/*
		 * Wait until the parent tells us to go.
		 */
		read(go_pipe[0], &buf, 1);

		execvp(argv[0], (char **)argv);

		perror(argv[0]);
		exit(-1);
	}

	/*
	 * Wait for the child to be ready to exec.
	 */
	close(child_ready_pipe[1]);
	close(go_pipe[0]);
	read(child_ready_pipe[0], &buf, 1);
	close(child_ready_pipe[0]);

259
	for (counter = 0; counter < nr_counters; counter++)
260
		create_perf_stat_counter(counter, pid);
261 262 263 264 265 266

	/*
	 * Enable counters and exec the command:
	 */
	t0 = rdclock();

267
	close(go_pipe[1]);
268 269 270 271 272 273 274 275 276 277 278 279
	wait(&status);

	t1 = rdclock();

	walltime_nsecs[run_idx] = t1 - t0;

	for (counter = 0; counter < nr_counters; counter++)
		read_counter(counter);

	return WEXITSTATUS(status);
}

280
static void print_noise(u64 *count, u64 *noise)
281 282 283 284 285 286
{
	if (run_count > 1)
		fprintf(stderr, "   ( +- %7.3f%% )",
			(double)noise[0]/(count[0]+1)*100.0);
}

287
static void nsec_printout(int counter, u64 *count, u64 *noise)
I
Ingo Molnar 已提交
288 289 290
{
	double msecs = (double)count[0] / 1000000;

291
	fprintf(stderr, " %14.6f  %-24s", msecs, event_name(counter));
I
Ingo Molnar 已提交
292 293 294 295

	if (attrs[counter].type == PERF_TYPE_SOFTWARE &&
		attrs[counter].config == PERF_COUNT_SW_TASK_CLOCK) {

296 297 298
		if (walltime_nsecs_avg)
			fprintf(stderr, " # %10.3f CPUs ",
				(double)count[0] / (double)walltime_nsecs_avg);
I
Ingo Molnar 已提交
299
	}
300
	print_noise(count, noise);
I
Ingo Molnar 已提交
301 302
}

303
static void abs_printout(int counter, u64 *count, u64 *noise)
I
Ingo Molnar 已提交
304
{
305
	fprintf(stderr, " %14Ld  %-24s", count[0], event_name(counter));
I
Ingo Molnar 已提交
306

307
	if (runtime_cycles_avg &&
I
Ingo Molnar 已提交
308 309 310
		attrs[counter].type == PERF_TYPE_HARDWARE &&
			attrs[counter].config == PERF_COUNT_HW_INSTRUCTIONS) {

311 312 313 314 315 316 317
		fprintf(stderr, " # %10.3f IPC  ",
			(double)count[0] / (double)runtime_cycles_avg);
	} else {
		if (runtime_nsecs_avg) {
			fprintf(stderr, " # %10.3f M/sec",
				(double)count[0]/runtime_nsecs_avg*1000.0);
		}
I
Ingo Molnar 已提交
318
	}
319
	print_noise(count, noise);
I
Ingo Molnar 已提交
320 321
}

322 323 324 325 326
/*
 * Print out the results of a single counter:
 */
static void print_counter(int counter)
{
327
	u64 *count, *noise;
328 329
	int scaled;

330 331 332
	count = event_res_avg[counter];
	noise = event_res_noise[counter];
	scaled = event_scaled_avg[counter];
333 334

	if (scaled == -1) {
335
		fprintf(stderr, " %14s  %-24s\n",
336 337 338
			"<not counted>", event_name(counter));
		return;
	}
339

I
Ingo Molnar 已提交
340
	if (nsec_counter(counter))
341
		nsec_printout(counter, count, noise);
I
Ingo Molnar 已提交
342
	else
343
		abs_printout(counter, count, noise);
344

345
	if (scaled)
346 347
		fprintf(stderr, "  (scaled from %.2f%%)",
			(double) count[2] / count[1] * 100);
I
Ingo Molnar 已提交
348

349 350 351
	fprintf(stderr, "\n");
}

352
/*
353
 * normalize_noise noise values down to stddev:
354
 */
355
static void normalize_noise(u64 *val)
356
{
357
	double res;
358

359
	res = (double)*val / (run_count * sqrt((double)run_count));
360

361
	*val = (u64)res;
362
}
363

364
static void update_avg(const char *name, int idx, u64 *avg, u64 *val)
365 366 367 368 369 370
{
	*avg += *val;

	if (verbose > 1)
		fprintf(stderr, "debug: %20s[%d]: %Ld\n", name, idx, *val);
}
371 372 373 374 375 376 377
/*
 * Calculate the averages and noises:
 */
static void calc_avg(void)
{
	int i, j;

378 379 380
	if (verbose > 1)
		fprintf(stderr, "\n");

381
	for (i = 0; i < run_count; i++) {
382 383 384
		update_avg("runtime", 0, &runtime_nsecs_avg, runtime_nsecs + i);
		update_avg("walltime", 0, &walltime_nsecs_avg, walltime_nsecs + i);
		update_avg("runtime_cycles", 0, &runtime_cycles_avg, runtime_cycles + i);
385 386

		for (j = 0; j < nr_counters; j++) {
387 388 389 390 391 392
			update_avg("counter/0", j,
				event_res_avg[j]+0, event_res[i][j]+0);
			update_avg("counter/1", j,
				event_res_avg[j]+1, event_res[i][j]+1);
			update_avg("counter/2", j,
				event_res_avg[j]+2, event_res[i][j]+2);
I
Ingo Molnar 已提交
393 394 395 396 397
			if (event_scaled[i][j] != -1)
				update_avg("scaled", j,
					event_scaled_avg + j, event_scaled[i]+j);
			else
				event_scaled_avg[j] = -1;
398 399 400 401 402 403 404 405 406 407 408
		}
	}
	runtime_nsecs_avg /= run_count;
	walltime_nsecs_avg /= run_count;
	runtime_cycles_avg /= run_count;

	for (j = 0; j < nr_counters; j++) {
		event_res_avg[j][0] /= run_count;
		event_res_avg[j][1] /= run_count;
		event_res_avg[j][2] /= run_count;
	}
I
Ingo Molnar 已提交
409

410 411
	for (i = 0; i < run_count; i++) {
		runtime_nsecs_noise +=
412
			abs((s64)(runtime_nsecs[i] - runtime_nsecs_avg));
413
		walltime_nsecs_noise +=
414
			abs((s64)(walltime_nsecs[i] - walltime_nsecs_avg));
415
		runtime_cycles_noise +=
416
			abs((s64)(runtime_cycles[i] - runtime_cycles_avg));
417 418 419

		for (j = 0; j < nr_counters; j++) {
			event_res_noise[j][0] +=
420
				abs((s64)(event_res[i][j][0] - event_res_avg[j][0]));
421
			event_res_noise[j][1] +=
422
				abs((s64)(event_res[i][j][1] - event_res_avg[j][1]));
423
			event_res_noise[j][2] +=
424
				abs((s64)(event_res[i][j][2] - event_res_avg[j][2]));
425 426
		}
	}
I
Ingo Molnar 已提交
427

428 429 430
	normalize_noise(&runtime_nsecs_noise);
	normalize_noise(&walltime_nsecs_noise);
	normalize_noise(&runtime_cycles_noise);
I
Ingo Molnar 已提交
431

432
	for (j = 0; j < nr_counters; j++) {
433 434 435
		normalize_noise(&event_res_noise[j][0]);
		normalize_noise(&event_res_noise[j][1]);
		normalize_noise(&event_res_noise[j][2]);
436 437 438 439 440 441 442 443
	}
}

static void print_stat(int argc, const char **argv)
{
	int i, counter;

	calc_avg();
444 445 446 447

	fflush(stdout);

	fprintf(stderr, "\n");
I
Ingo Molnar 已提交
448 449 450 451 452
	fprintf(stderr, " Performance counter stats for \'%s", argv[0]);

	for (i = 1; i < argc; i++)
		fprintf(stderr, " %s", argv[i]);

453 454 455 456
	fprintf(stderr, "\'");
	if (run_count > 1)
		fprintf(stderr, " (%d runs)", run_count);
	fprintf(stderr, ":\n\n");
457

458 459
	for (counter = 0; counter < nr_counters; counter++)
		print_counter(counter);
460 461

	fprintf(stderr, "\n");
I
Ingo Molnar 已提交
462
	fprintf(stderr, " %14.9f  seconds time elapsed",
463
			(double)walltime_nsecs_avg/1e9);
I
Ingo Molnar 已提交
464 465 466 467 468
	if (run_count > 1) {
		fprintf(stderr, "   ( +- %7.3f%% )",
			100.0*(double)walltime_nsecs_noise/(double)walltime_nsecs_avg);
	}
	fprintf(stderr, "\n\n");
469 470
}

471 472
static volatile int signr = -1;

473
static void skip_signal(int signo)
474
{
475 476 477 478 479 480 481 482 483 484
	signr = signo;
}

static void sig_atexit(void)
{
	if (signr == -1)
		return;

	signal(signr, SIG_DFL);
	kill(getpid(), signr);
485 486 487 488 489 490 491 492 493
}

static const char * const stat_usage[] = {
	"perf stat [<options>] <command>",
	NULL
};

static const struct option options[] = {
	OPT_CALLBACK('e', "event", NULL, "event",
494 495
		     "event selector. use 'perf list' to list available events",
		     parse_events),
496 497 498 499 500
	OPT_BOOLEAN('i', "inherit", &inherit,
		    "child tasks inherit counters"),
	OPT_INTEGER('p', "pid", &target_pid,
		    "stat events on existing pid"),
	OPT_BOOLEAN('a', "all-cpus", &system_wide,
501
		    "system-wide collection from all CPUs"),
502
	OPT_BOOLEAN('S', "scale", &scale,
503
		    "scale/normalize counters"),
504 505
	OPT_BOOLEAN('v', "verbose", &verbose,
		    "be more verbose (show counter open errors, etc)"),
506 507
	OPT_INTEGER('r', "repeat", &run_count,
		    "repeat command and print average + stddev (max: 100)"),
508 509
	OPT_BOOLEAN('n', "null", &null_run,
		    "null run - dont start any counters"),
510 511 512 513 514
	OPT_END()
};

int cmd_stat(int argc, const char **argv, const char *prefix)
{
515 516
	int status;

517 518 519
	argc = parse_options(argc, argv, options, stat_usage, 0);
	if (!argc)
		usage_with_options(stat_usage, options);
520 521
	if (run_count <= 0 || run_count > MAX_RUN)
		usage_with_options(stat_usage, options);
522

523 524 525 526 527
	/* Set attrs and nr_counters if no event is selected and !null_run */
	if (!null_run && !nr_counters) {
		memcpy(attrs, default_attrs, sizeof(default_attrs));
		nr_counters = ARRAY_SIZE(default_attrs);
	}
528 529 530 531 532

	nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
	assert(nr_cpus <= MAX_NR_CPUS);
	assert(nr_cpus >= 0);

I
Ingo Molnar 已提交
533 534 535 536 537 538
	/*
	 * We dont want to block the signals - that would cause
	 * child tasks to inherit that and Ctrl-C would not work.
	 * What we want is for Ctrl-C to work in the exec()-ed
	 * task, but being ignored by perf stat itself:
	 */
539
	atexit(sig_atexit);
I
Ingo Molnar 已提交
540 541 542 543
	signal(SIGINT,  skip_signal);
	signal(SIGALRM, skip_signal);
	signal(SIGABRT, skip_signal);

544 545 546
	status = 0;
	for (run_idx = 0; run_idx < run_count; run_idx++) {
		if (run_count != 1 && verbose)
547
			fprintf(stderr, "[ perf stat: executing run #%d ... ]\n", run_idx + 1);
548 549 550 551 552 553
		status = run_perf_stat(argc, argv);
	}

	print_stat(argc, argv);

	return status;
554
}