perf stat: Fix multi-run stats
[firefly-linux-kernel-4.4.55.git] / tools / perf / builtin-stat.c
index 9eb42b1ae784d4bc8c538cb54cb6bcd9e5742ed3..52c176cc683ec4c7b5bffbec552c4460b705208f 100644 (file)
@@ -59,55 +59,44 @@ static struct perf_counter_attr default_attrs[MAX_COUNTERS] = {
 
 };
 
+#define MAX_RUN                        100
+
 static int                     system_wide                     =  0;
-static int                     inherit                         =  1;
 static int                     verbose                         =  0;
-
-static int                     fd[MAX_NR_CPUS][MAX_COUNTERS];
-
-static int                     target_pid                      = -1;
 static int                     nr_cpus                         =  0;
-static unsigned int            page_size;
+static int                     run_idx                         =  0;
 
+static int                     run_count                       =  1;
+static int                     inherit                         =  1;
 static int                     scale                           =  1;
+static int                     target_pid                      = -1;
+static int                     null_run                        =  0;
 
-static const unsigned int default_count[] = {
-       1000000,
-       1000000,
-         10000,
-         10000,
-       1000000,
-         10000,
-};
-
-#define MAX_RUN 100
-
-static int                     run_count               =  1;
-static int                     run_idx                 =  0;
-
-static __u64                   event_res[MAX_RUN][MAX_COUNTERS][3];
-static __u64                   event_scaled[MAX_RUN][MAX_COUNTERS];
+static int                     fd[MAX_NR_CPUS][MAX_COUNTERS];
 
-//static __u64                 event_hist[MAX_RUN][MAX_COUNTERS][3];
+static u64                     runtime_nsecs[MAX_RUN];
+static u64                     walltime_nsecs[MAX_RUN];
+static u64                     runtime_cycles[MAX_RUN];
 
+static u64                     event_res[MAX_RUN][MAX_COUNTERS][3];
+static u64                     event_scaled[MAX_RUN][MAX_COUNTERS];
 
-static __u64                   runtime_nsecs[MAX_RUN];
-static __u64                   walltime_nsecs[MAX_RUN];
-static __u64                   runtime_cycles[MAX_RUN];
+static u64                     event_res_avg[MAX_COUNTERS][3];
+static u64                     event_res_noise[MAX_COUNTERS][3];
 
-static __u64                   event_res_avg[MAX_COUNTERS][3];
-static __u64                   event_res_noise[MAX_COUNTERS][3];
+static u64                     event_scaled_avg[MAX_COUNTERS];
 
-static __u64                   event_scaled_avg[MAX_COUNTERS];
+static u64                     runtime_nsecs_avg;
+static u64                     runtime_nsecs_noise;
 
-static __u64                   runtime_nsecs_avg;
-static __u64                   runtime_nsecs_noise;
+static u64                     walltime_nsecs_avg;
+static u64                     walltime_nsecs_noise;
 
-static __u64                   walltime_nsecs_avg;
-static __u64                   walltime_nsecs_noise;
+static u64                     runtime_cycles_avg;
+static u64                     runtime_cycles_noise;
 
-static __u64                   runtime_cycles_avg;
-static __u64                   runtime_cycles_noise;
+#define ERR_PERF_OPEN \
+"Error: counter %d, sys_perf_counter_open() syscall returned with %d (%s)\n"
 
 static void create_perf_stat_counter(int counter)
 {
@@ -119,20 +108,20 @@ static void create_perf_stat_counter(int counter)
 
        if (system_wide) {
                int cpu;
-               for (cpu = 0; cpu < nr_cpus; cpu ++) {
+               for (cpu = 0; cpu < nr_cpus; cpu++) {
                        fd[cpu][counter] = sys_perf_counter_open(attr, -1, cpu, -1, 0);
-                       if (fd[cpu][counter] < 0 && verbose) {
-                               printf("Error: counter %d, sys_perf_counter_open() syscall returned with %d (%s)\n", counter, fd[cpu][counter], strerror(errno));
-                       }
+                       if (fd[cpu][counter] < 0 && verbose)
+                               fprintf(stderr, ERR_PERF_OPEN, counter,
+                                       fd[cpu][counter], strerror(errno));
                }
        } else {
                attr->inherit   = inherit;
                attr->disabled  = 1;
 
                fd[0][counter] = sys_perf_counter_open(attr, 0, -1, -1, 0);
-               if (fd[0][counter] < 0 && verbose) {
-                       printf("Error: counter %d, sys_perf_counter_open() syscall returned with %d (%s)\n", counter, fd[0][counter], strerror(errno));
-               }
+               if (fd[0][counter] < 0 && verbose)
+                       fprintf(stderr, ERR_PERF_OPEN, counter,
+                               fd[0][counter], strerror(errno));
        }
 }
 
@@ -158,7 +147,7 @@ static inline int nsec_counter(int counter)
  */
 static void read_counter(int counter)
 {
-       __u64 *count, single_count[3];
+       u64 *count, single_count[3];
        ssize_t res;
        int cpu, nv;
        int scaled;
@@ -168,12 +157,12 @@ static void read_counter(int counter)
        count[0] = count[1] = count[2] = 0;
 
        nv = scale ? 3 : 1;
-       for (cpu = 0; cpu < nr_cpus; cpu ++) {
+       for (cpu = 0; cpu < nr_cpus; cpu++) {
                if (fd[cpu][counter] < 0)
                        continue;
 
-               res = read(fd[cpu][counter], single_count, nv * sizeof(__u64));
-               assert(res == nv * sizeof(__u64));
+               res = read(fd[cpu][counter], single_count, nv * sizeof(u64));
+               assert(res == nv * sizeof(u64));
                close(fd[cpu][counter]);
                fd[cpu][counter] = -1;
 
@@ -251,14 +240,14 @@ static int run_perf_stat(int argc, const char **argv)
        return WEXITSTATUS(status);
 }
 
-static void print_noise(__u64 *count, __u64 *noise)
+static void print_noise(u64 *count, u64 *noise)
 {
        if (run_count > 1)
                fprintf(stderr, "   ( +- %7.3f%% )",
                        (double)noise[0]/(count[0]+1)*100.0);
 }
 
-static void nsec_printout(int counter, __u64 *count, __u64 *noise)
+static void nsec_printout(int counter, u64 *count, u64 *noise)
 {
        double msecs = (double)count[0] / 1000000;
 
@@ -274,7 +263,7 @@ static void nsec_printout(int counter, __u64 *count, __u64 *noise)
        print_noise(count, noise);
 }
 
-static void abs_printout(int counter, __u64 *count, __u64 *noise)
+static void abs_printout(int counter, u64 *count, u64 *noise)
 {
        fprintf(stderr, " %14Ld  %-20s", count[0], event_name(counter));
 
@@ -298,7 +287,7 @@ static void abs_printout(int counter, __u64 *count, __u64 *noise)
  */
 static void print_counter(int counter)
 {
-       __u64 *count, *noise;
+       u64 *count, *noise;
        int scaled;
 
        count = event_res_avg[counter];
@@ -324,17 +313,24 @@ static void print_counter(int counter)
 }
 
 /*
- * Normalize noise values down to stddev:
+ * normalize_noise noise values down to stddev:
  */
-static void normalize(__u64 *val)
+static void normalize_noise(u64 *val)
 {
        double res;
 
        res = (double)*val / (run_count * sqrt((double)run_count));
 
-       *val = (__u64)res;
+       *val = (u64)res;
 }
 
+static void update_avg(const char *name, int idx, u64 *avg, u64 *val)
+{
+       *avg += *val;
+
+       if (verbose > 1)
+               fprintf(stderr, "debug: %20s[%d]: %Ld\n", name, idx, *val);
+}
 /*
  * Calculate the averages and noises:
  */
@@ -342,16 +338,26 @@ static void calc_avg(void)
 {
        int i, j;
 
+       if (verbose > 1)
+               fprintf(stderr, "\n");
+
        for (i = 0; i < run_count; i++) {
-               runtime_nsecs_avg += runtime_nsecs[i];
-               walltime_nsecs_avg += walltime_nsecs[i];
-               runtime_cycles_avg += runtime_cycles[i];
+               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);
 
                for (j = 0; j < nr_counters; j++) {
-                       event_res_avg[j][0] += event_res[i][j][0];
-                       event_res_avg[j][1] += event_res[i][j][1];
-                       event_res_avg[j][2] += event_res[i][j][2];
-                       event_scaled_avg[j] += event_scaled[i][j];
+                       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);
+                       if (event_scaled[i][j] != -1)
+                               update_avg("scaled", j,
+                                       event_scaled_avg + j, event_scaled[i]+j);
+                       else
+                               event_scaled_avg[j] = -1;
                }
        }
        runtime_nsecs_avg /= run_count;
@@ -366,30 +372,30 @@ static void calc_avg(void)
 
        for (i = 0; i < run_count; i++) {
                runtime_nsecs_noise +=
-                       abs((__s64)(runtime_nsecs[i] - runtime_nsecs_avg));
+                       abs((s64)(runtime_nsecs[i] - runtime_nsecs_avg));
                walltime_nsecs_noise +=
-                       abs((__s64)(walltime_nsecs[i] - walltime_nsecs_avg));
+                       abs((s64)(walltime_nsecs[i] - walltime_nsecs_avg));
                runtime_cycles_noise +=
-                       abs((__s64)(runtime_cycles[i] - runtime_cycles_avg));
+                       abs((s64)(runtime_cycles[i] - runtime_cycles_avg));
 
                for (j = 0; j < nr_counters; j++) {
                        event_res_noise[j][0] +=
-                               abs((__s64)(event_res[i][j][0] - event_res_avg[j][0]));
+                               abs((s64)(event_res[i][j][0] - event_res_avg[j][0]));
                        event_res_noise[j][1] +=
-                               abs((__s64)(event_res[i][j][1] - event_res_avg[j][1]));
+                               abs((s64)(event_res[i][j][1] - event_res_avg[j][1]));
                        event_res_noise[j][2] +=
-                               abs((__s64)(event_res[i][j][2] - event_res_avg[j][2]));
+                               abs((s64)(event_res[i][j][2] - event_res_avg[j][2]));
                }
        }
 
-       normalize(&runtime_nsecs_noise);
-       normalize(&walltime_nsecs_noise);
-       normalize(&runtime_cycles_noise);
+       normalize_noise(&runtime_nsecs_noise);
+       normalize_noise(&walltime_nsecs_noise);
+       normalize_noise(&runtime_cycles_noise);
 
        for (j = 0; j < nr_counters; j++) {
-               normalize(&event_res_noise[j][0]);
-               normalize(&event_res_noise[j][1]);
-               normalize(&event_res_noise[j][2]);
+               normalize_noise(&event_res_noise[j][0]);
+               normalize_noise(&event_res_noise[j][1]);
+               normalize_noise(&event_res_noise[j][2]);
        }
 }
 
@@ -399,8 +405,6 @@ static void print_stat(int argc, const char **argv)
 
        calc_avg();
 
-       run_idx = 0;
-
        fflush(stdout);
 
        fprintf(stderr, "\n");
@@ -419,9 +423,13 @@ static void print_stat(int argc, const char **argv)
 
 
        fprintf(stderr, "\n");
-       fprintf(stderr, " %14.9f  seconds time elapsed.\n",
+       fprintf(stderr, " %14.9f  seconds time elapsed",
                        (double)walltime_nsecs_avg/1e9);
-       fprintf(stderr, "\n");
+       if (run_count > 1) {
+               fprintf(stderr, "   ( +- %7.3f%% )",
+                       100.0*(double)walltime_nsecs_noise/(double)walltime_nsecs_avg);
+       }
+       fprintf(stderr, "\n\n");
 }
 
 static volatile int signr = -1;
@@ -454,13 +462,15 @@ static const struct option options[] = {
        OPT_INTEGER('p', "pid", &target_pid,
                    "stat events on existing pid"),
        OPT_BOOLEAN('a', "all-cpus", &system_wide,
-                           "system-wide collection from all CPUs"),
+                   "system-wide collection from all CPUs"),
        OPT_BOOLEAN('S', "scale", &scale,
-                           "scale/normalize counters"),
+                   "scale/normalize counters"),
        OPT_BOOLEAN('v', "verbose", &verbose,
                    "be more verbose (show counter open errors, etc)"),
        OPT_INTEGER('r', "repeat", &run_count,
                    "repeat command and print average + stddev (max: 100)"),
+       OPT_BOOLEAN('n', "null", &null_run,
+                   "null run - dont start any counters"),
        OPT_END()
 };
 
@@ -468,8 +478,6 @@ int cmd_stat(int argc, const char **argv, const char *prefix)
 {
        int status;
 
-       page_size = sysconf(_SC_PAGE_SIZE);
-
        memcpy(attrs, default_attrs, sizeof(attrs));
 
        argc = parse_options(argc, argv, options, stat_usage, 0);
@@ -478,7 +486,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix)
        if (run_count <= 0 || run_count > MAX_RUN)
                usage_with_options(stat_usage, options);
 
-       if (!nr_counters)
+       if (!null_run && !nr_counters)
                nr_counters = 8;
 
        nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
@@ -499,7 +507,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix)
        status = 0;
        for (run_idx = 0; run_idx < run_count; run_idx++) {
                if (run_count != 1 && verbose)
-                       fprintf(stderr, "[ perf stat: executing run #%d ... ]\n", run_idx+1);
+                       fprintf(stderr, "[ perf stat: executing run #%d ... ]\n", run_idx + 1);
                status = run_perf_stat(argc, argv);
        }