aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-stat.c
diff options
context:
space:
mode:
authorPeter Zijlstra <a.p.zijlstra@chello.nl>2009-09-04 09:36:12 -0400
committerIngo Molnar <mingo@elte.hu>2009-09-04 10:33:07 -0400
commit506d4bc8d5dab20d84624aa07cdc6dcd77915d52 (patch)
tree48036f6ace4d499a772f172a2dfcea69ffb79fc1 /tools/perf/builtin-stat.c
parent1653192f510bd8114b7b133d7289e6e5c3e95046 (diff)
perf stat: Change noise calculation to use stddev
The current noise computation does: \Sum abs(n_i - avg(n)) * N^-1.5 Which is (afaik) not a regular noise function, and needs the complete sample set available to post-process. Change this to use a regular stddev computation which can be done by keeping a two sums: stddev = sqrt( 1/N (\Sum n_i^2) - avg(n)^2 ) For which we only need to keep \Sum n_i and \Sum n_i^2. Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: <stable@kernel.org> LKML-Reference: <new-submission> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/builtin-stat.c')
-rw-r--r--tools/perf/builtin-stat.c170
1 files changed, 69 insertions, 101 deletions
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 1a2626230660..31ffc4d3ba60 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -83,19 +83,32 @@ static u64 runtime_cycles[MAX_RUN];
83static u64 event_res[MAX_RUN][MAX_COUNTERS][3]; 83static u64 event_res[MAX_RUN][MAX_COUNTERS][3];
84static u64 event_scaled[MAX_RUN][MAX_COUNTERS]; 84static u64 event_scaled[MAX_RUN][MAX_COUNTERS];
85 85
86static u64 event_res_avg[MAX_COUNTERS][3]; 86struct stats
87static u64 event_res_noise[MAX_COUNTERS][3]; 87{
88 double sum;
89 double sum_sq;
90};
88 91
89static u64 event_scaled_avg[MAX_COUNTERS]; 92static double avg_stats(struct stats *stats)
93{
94 return stats->sum / run_count;
95}
90 96
91static u64 runtime_nsecs_avg; 97/*
92static u64 runtime_nsecs_noise; 98 * stddev = sqrt(1/N (\Sum n_i^2) - avg(n)^2)
99 */
100static double stddev_stats(struct stats *stats)
101{
102 double avg = stats->sum / run_count;
93 103
94static u64 walltime_nsecs_avg; 104 return sqrt(stats->sum_sq/run_count - avg*avg);
95static u64 walltime_nsecs_noise; 105}
96 106
97static u64 runtime_cycles_avg; 107struct stats event_res_stats[MAX_COUNTERS][3];
98static u64 runtime_cycles_noise; 108struct stats event_scaled_stats[MAX_COUNTERS];
109struct stats runtime_nsecs_stats;
110struct stats walltime_nsecs_stats;
111struct stats runtime_cycles_stats;
99 112
100#define MATCH_EVENT(t, c, counter) \ 113#define MATCH_EVENT(t, c, counter) \
101 (attrs[counter].type == PERF_TYPE_##t && \ 114 (attrs[counter].type == PERF_TYPE_##t && \
@@ -279,42 +292,37 @@ static int run_perf_stat(int argc __used, const char **argv)
279 return WEXITSTATUS(status); 292 return WEXITSTATUS(status);
280} 293}
281 294
282static void print_noise(u64 *count, u64 *noise) 295static void print_noise(double avg, double stddev)
283{ 296{
284 if (run_count > 1) 297 if (run_count > 1)
285 fprintf(stderr, " ( +- %7.3f%% )", 298 fprintf(stderr, " ( +- %7.3f%% )", 100*stddev / avg);
286 (double)noise[0]/(count[0]+1)*100.0);
287} 299}
288 300
289static void nsec_printout(int counter, u64 *count, u64 *noise) 301static void nsec_printout(int counter, double avg, double stddev)
290{ 302{
291 double msecs = (double)count[0] / 1000000; 303 double msecs = avg / 1e6;
292 304
293 fprintf(stderr, " %14.6f %-24s", msecs, event_name(counter)); 305 fprintf(stderr, " %14.6f %-24s", msecs, event_name(counter));
294 306
295 if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) { 307 if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) {
296 if (walltime_nsecs_avg) 308 fprintf(stderr, " # %10.3f CPUs ",
297 fprintf(stderr, " # %10.3f CPUs ", 309 avg / avg_stats(&walltime_nsecs_stats));
298 (double)count[0] / (double)walltime_nsecs_avg);
299 } 310 }
300 print_noise(count, noise); 311 print_noise(avg, stddev);
301} 312}
302 313
303static void abs_printout(int counter, u64 *count, u64 *noise) 314static void abs_printout(int counter, double avg, double stddev)
304{ 315{
305 fprintf(stderr, " %14Ld %-24s", count[0], event_name(counter)); 316 fprintf(stderr, " %14.0f %-24s", avg, event_name(counter));
306 317
307 if (runtime_cycles_avg && 318 if (MATCH_EVENT(HARDWARE, HW_INSTRUCTIONS, counter)) {
308 MATCH_EVENT(HARDWARE, HW_INSTRUCTIONS, counter)) {
309 fprintf(stderr, " # %10.3f IPC ", 319 fprintf(stderr, " # %10.3f IPC ",
310 (double)count[0] / (double)runtime_cycles_avg); 320 avg / avg_stats(&runtime_cycles_stats));
311 } else { 321 } else {
312 if (runtime_nsecs_avg) { 322 fprintf(stderr, " # %10.3f M/sec",
313 fprintf(stderr, " # %10.3f M/sec", 323 1000.0 * avg / avg_stats(&runtime_nsecs_stats));
314 (double)count[0]/runtime_nsecs_avg*1000.0);
315 }
316 } 324 }
317 print_noise(count, noise); 325 print_noise(avg, stddev);
318} 326}
319 327
320/* 328/*
@@ -322,12 +330,12 @@ static void abs_printout(int counter, u64 *count, u64 *noise)
322 */ 330 */
323static void print_counter(int counter) 331static void print_counter(int counter)
324{ 332{
325 u64 *count, *noise; 333 double avg, stddev;
326 int scaled; 334 int scaled;
327 335
328 count = event_res_avg[counter]; 336 avg = avg_stats(&event_res_stats[counter][0]);
329 noise = event_res_noise[counter]; 337 stddev = stddev_stats(&event_res_stats[counter][0]);
330 scaled = event_scaled_avg[counter]; 338 scaled = avg_stats(&event_scaled_stats[counter]);
331 339
332 if (scaled == -1) { 340 if (scaled == -1) {
333 fprintf(stderr, " %14s %-24s\n", 341 fprintf(stderr, " %14s %-24s\n",
@@ -336,36 +344,34 @@ static void print_counter(int counter)
336 } 344 }
337 345
338 if (nsec_counter(counter)) 346 if (nsec_counter(counter))
339 nsec_printout(counter, count, noise); 347 nsec_printout(counter, avg, stddev);
340 else 348 else
341 abs_printout(counter, count, noise); 349 abs_printout(counter, avg, stddev);
350
351 if (scaled) {
352 double avg_enabled, avg_running;
353
354 avg_enabled = avg_stats(&event_res_stats[counter][1]);
355 avg_running = avg_stats(&event_res_stats[counter][2]);
342 356
343 if (scaled)
344 fprintf(stderr, " (scaled from %.2f%%)", 357 fprintf(stderr, " (scaled from %.2f%%)",
345 (double) count[2] / count[1] * 100); 358 100 * avg_running / avg_enabled);
359 }
346 360
347 fprintf(stderr, "\n"); 361 fprintf(stderr, "\n");
348} 362}
349 363
350/* 364static void update_stats(const char *name, int idx, struct stats *stats, u64 *val)
351 * normalize_noise noise values down to stddev:
352 */
353static void normalize_noise(u64 *val)
354{ 365{
355 double res; 366 double sq = *val;
356 367
357 res = (double)*val / (run_count * sqrt((double)run_count)); 368 stats->sum += *val;
358 369 stats->sum_sq += sq * sq;
359 *val = (u64)res;
360}
361
362static void update_avg(const char *name, int idx, u64 *avg, u64 *val)
363{
364 *avg += *val;
365 370
366 if (verbose > 1) 371 if (verbose > 1)
367 fprintf(stderr, "debug: %20s[%d]: %Ld\n", name, idx, *val); 372 fprintf(stderr, "debug: %20s[%d]: %Ld\n", name, idx, *val);
368} 373}
374
369/* 375/*
370 * Calculate the averages and noises: 376 * Calculate the averages and noises:
371 */ 377 */
@@ -377,61 +383,22 @@ static void calc_avg(void)
377 fprintf(stderr, "\n"); 383 fprintf(stderr, "\n");
378 384
379 for (i = 0; i < run_count; i++) { 385 for (i = 0; i < run_count; i++) {
380 update_avg("runtime", 0, &runtime_nsecs_avg, runtime_nsecs + i); 386 update_stats("runtime", 0, &runtime_nsecs_stats, runtime_nsecs + i);
381 update_avg("walltime", 0, &walltime_nsecs_avg, walltime_nsecs + i); 387 update_stats("walltime", 0, &walltime_nsecs_stats, walltime_nsecs + i);
382 update_avg("runtime_cycles", 0, &runtime_cycles_avg, runtime_cycles + i); 388 update_stats("runtime_cycles", 0, &runtime_cycles_stats, runtime_cycles + i);
383 389
384 for (j = 0; j < nr_counters; j++) { 390 for (j = 0; j < nr_counters; j++) {
385 update_avg("counter/0", j, 391 update_stats("counter/0", j,
386 event_res_avg[j]+0, event_res[i][j]+0); 392 event_res_stats[j]+0, event_res[i][j]+0);
387 update_avg("counter/1", j, 393 update_stats("counter/1", j,
388 event_res_avg[j]+1, event_res[i][j]+1); 394 event_res_stats[j]+1, event_res[i][j]+1);
389 update_avg("counter/2", j, 395 update_stats("counter/2", j,
390 event_res_avg[j]+2, event_res[i][j]+2); 396 event_res_stats[j]+2, event_res[i][j]+2);
391 if (event_scaled[i][j] != (u64)-1) 397 if (event_scaled[i][j] != (u64)-1)
392 update_avg("scaled", j, 398 update_stats("scaled", j,
393 event_scaled_avg + j, event_scaled[i]+j); 399 event_scaled_stats + j, event_scaled[i]+j);
394 else
395 event_scaled_avg[j] = -1;
396 } 400 }
397 } 401 }
398 runtime_nsecs_avg /= run_count;
399 walltime_nsecs_avg /= run_count;
400 runtime_cycles_avg /= run_count;
401
402 for (j = 0; j < nr_counters; j++) {
403 event_res_avg[j][0] /= run_count;
404 event_res_avg[j][1] /= run_count;
405 event_res_avg[j][2] /= run_count;
406 }
407
408 for (i = 0; i < run_count; i++) {
409 runtime_nsecs_noise +=
410 abs((s64)(runtime_nsecs[i] - runtime_nsecs_avg));
411 walltime_nsecs_noise +=
412 abs((s64)(walltime_nsecs[i] - walltime_nsecs_avg));
413 runtime_cycles_noise +=
414 abs((s64)(runtime_cycles[i] - runtime_cycles_avg));
415
416 for (j = 0; j < nr_counters; j++) {
417 event_res_noise[j][0] +=
418 abs((s64)(event_res[i][j][0] - event_res_avg[j][0]));
419 event_res_noise[j][1] +=
420 abs((s64)(event_res[i][j][1] - event_res_avg[j][1]));
421 event_res_noise[j][2] +=
422 abs((s64)(event_res[i][j][2] - event_res_avg[j][2]));
423 }
424 }
425
426 normalize_noise(&runtime_nsecs_noise);
427 normalize_noise(&walltime_nsecs_noise);
428 normalize_noise(&runtime_cycles_noise);
429
430 for (j = 0; j < nr_counters; j++) {
431 normalize_noise(&event_res_noise[j][0]);
432 normalize_noise(&event_res_noise[j][1]);
433 normalize_noise(&event_res_noise[j][2]);
434 }
435} 402}
436 403
437static void print_stat(int argc, const char **argv) 404static void print_stat(int argc, const char **argv)
@@ -458,10 +425,11 @@ static void print_stat(int argc, const char **argv)
458 425
459 fprintf(stderr, "\n"); 426 fprintf(stderr, "\n");
460 fprintf(stderr, " %14.9f seconds time elapsed", 427 fprintf(stderr, " %14.9f seconds time elapsed",
461 (double)walltime_nsecs_avg/1e9); 428 avg_stats(&walltime_nsecs_stats)/1e9);
462 if (run_count > 1) { 429 if (run_count > 1) {
463 fprintf(stderr, " ( +- %7.3f%% )", 430 fprintf(stderr, " ( +- %7.3f%% )",
464 100.0*(double)walltime_nsecs_noise/(double)walltime_nsecs_avg); 431 100*stddev_stats(&walltime_nsecs_stats) /
432 avg_stats(&walltime_nsecs_stats));
465 } 433 }
466 fprintf(stderr, "\n\n"); 434 fprintf(stderr, "\n\n");
467} 435}