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 unsigned 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

	if (system_wide) {
111 112
		unsigned int cpu;

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

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

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

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

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

	return 0;
}

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

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

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

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

167 168
		res = read(fd[cpu][counter], single_count, nv * sizeof(u64));
		assert(res == nv * sizeof(u64));
169

170 171
		close(fd[cpu][counter]);
		fd[cpu][counter] = -1;
172 173 174 175 176 177 178 179 180 181 182

		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) {
183
			event_scaled[run_idx][counter] = -1;
184
			count[0] = 0;
185 186
			return;
		}
187

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

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

	if (!system_wide)
		nr_cpus = 1;

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 259 260
	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]);

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

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

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

	t1 = rdclock();

	walltime_nsecs[run_idx] = t1 - t0;

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

	return WEXITSTATUS(status);
}

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

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

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

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

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

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

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

313 314 315 316 317 318 319
		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 已提交
320
	}
321
	print_noise(count, noise);
I
Ingo Molnar 已提交
322 323
}

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

332 333 334
	count = event_res_avg[counter];
	noise = event_res_noise[counter];
	scaled = event_scaled_avg[counter];
335 336

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

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

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

351 352 353
	fprintf(stderr, "\n");
}

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

361
	res = (double)*val / (run_count * sqrt((double)run_count));
362

363
	*val = (u64)res;
364
}
365

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

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

380 381 382
	if (verbose > 1)
		fprintf(stderr, "\n");

383
	for (i = 0; i < run_count; i++) {
384 385 386
		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);
387 388

		for (j = 0; j < nr_counters; j++) {
389 390 391 392 393 394
			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);
395
			if (event_scaled[i][j] != (u64)-1)
I
Ingo Molnar 已提交
396 397 398 399
				update_avg("scaled", j,
					event_scaled_avg + j, event_scaled[i]+j);
			else
				event_scaled_avg[j] = -1;
400 401 402 403 404 405 406 407 408 409 410
		}
	}
	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 已提交
411

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

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

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

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

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

	calc_avg();
446 447 448 449

	fflush(stdout);

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

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

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

460 461
	for (counter = 0; counter < nr_counters; counter++)
		print_counter(counter);
462 463

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

473 474
static volatile int signr = -1;

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

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

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

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

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

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

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

525 526 527 528 529
	/* 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);
	}
530 531 532

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

I
Ingo Molnar 已提交
535 536 537 538 539 540
	/*
	 * 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:
	 */
541
	atexit(sig_atexit);
I
Ingo Molnar 已提交
542 543 544 545
	signal(SIGINT,  skip_signal);
	signal(SIGALRM, skip_signal);
	signal(SIGABRT, skip_signal);

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

	print_stat(argc, argv);

	return status;
556
}