nanobench: add median and --cpu/--gpu

BUG=skia:
R=krajcevski@google.com, mtklein@google.com

Author: mtklein@chromium.org

Review URL: https://codereview.chromium.org/377283002
diff --git a/bench/nanobench.cpp b/bench/nanobench.cpp
index 0a374ca..71a412d 100644
--- a/bench/nanobench.cpp
+++ b/bench/nanobench.cpp
@@ -38,6 +38,9 @@
 DEFINE_double(gpuMs, 5, "Target bench time in millseconds for GPU.");
 DEFINE_int32(gpuFrameLag, 5, "Overestimate of maximum number of frames GPU allows to lag.");
 
+DEFINE_bool(cpu, true, "Master switch for CPU-bound work.");
+DEFINE_bool(gpu, true, "Master switch for GPU-bound work.");
+
 
 static SkString humanize(double ms) {
     if (ms > 1e+3) return SkStringPrintf("%.3gs",  ms/1e3);
@@ -193,9 +196,11 @@
             t->surface.reset(code);                                        \
             targets->push(t);                                              \
         }
-    CPU_TARGET(nonrendering, kNonRendering_Backend, NULL)
-    CPU_TARGET(8888, kRaster_Backend, SkSurface::NewRaster(_8888))
-    CPU_TARGET(565,  kRaster_Backend, SkSurface::NewRaster(_565))
+    if (FLAGS_cpu) {
+        CPU_TARGET(nonrendering, kNonRendering_Backend, NULL)
+        CPU_TARGET(8888, kRaster_Backend, SkSurface::NewRaster(_8888))
+        CPU_TARGET(565,  kRaster_Backend, SkSurface::NewRaster(_565))
+    }
 
 #if SK_SUPPORT_GPU
     #define GPU_TARGET(config, ctxType, info, samples)                                            \
@@ -204,16 +209,18 @@
             t->gl = gGrFactory.getGLContext(ctxType);                                             \
             targets->push(t);                                                                     \
         }
-    GPU_TARGET(gpu,      GrContextFactory::kNative_GLContextType, _8888, 0)
-    GPU_TARGET(msaa4,    GrContextFactory::kNative_GLContextType, _8888, 4)
-    GPU_TARGET(msaa16,   GrContextFactory::kNative_GLContextType, _8888, 16)
-    GPU_TARGET(nvprmsaa4,  GrContextFactory::kNVPR_GLContextType, _8888, 4)
-    GPU_TARGET(nvprmsaa16, GrContextFactory::kNVPR_GLContextType, _8888, 16)
-    GPU_TARGET(debug,     GrContextFactory::kDebug_GLContextType, _8888, 0)
-    GPU_TARGET(nullgpu,    GrContextFactory::kNull_GLContextType, _8888, 0)
-    #if SK_ANGLE
-        GPU_TARGET(angle, GrContextFactory::kANGLE_GLContextType, _8888, 0)
-    #endif
+    if (FLAGS_gpu) {
+        GPU_TARGET(gpu,      GrContextFactory::kNative_GLContextType, _8888, 0)
+        GPU_TARGET(msaa4,    GrContextFactory::kNative_GLContextType, _8888, 4)
+        GPU_TARGET(msaa16,   GrContextFactory::kNative_GLContextType, _8888, 16)
+        GPU_TARGET(nvprmsaa4,  GrContextFactory::kNVPR_GLContextType, _8888, 4)
+        GPU_TARGET(nvprmsaa16, GrContextFactory::kNVPR_GLContextType, _8888, 16)
+        GPU_TARGET(debug,     GrContextFactory::kDebug_GLContextType, _8888, 0)
+        GPU_TARGET(nullgpu,    GrContextFactory::kNull_GLContextType, _8888, 0)
+        #if SK_ANGLE
+            GPU_TARGET(angle, GrContextFactory::kANGLE_GLContextType, _8888, 0)
+        #endif
+    }
 #endif
 }
 
@@ -226,14 +233,12 @@
     const double overhead = estimate_timer_overhead();
     SkAutoTMalloc<double> samples(FLAGS_samples);
 
-    // TODO: display add median, use it in --quiet mode
-
     if (FLAGS_verbose) {
         // No header.
     } else if (FLAGS_quiet) {
-        SkDebugf("min\tbench\tconfig\n");
+        SkDebugf("median\tbench\tconfig\n");
     } else {
-        SkDebugf("loops\tmin\tmean\tmax\tstddev\tconfig\tbench\n");
+        SkDebugf("loops\tmin\tmedian\tmean\tmax\tstddev\tconfig\tbench\n");
     }
 
     for (const BenchRegistry* r = BenchRegistry::Head(); r != NULL; r = r->next()) {
@@ -269,12 +274,13 @@
                 if (targets.count() == 1) {
                     config = ""; // Only print the config if we run the same bench on more than one.
                 }
-                SkDebugf("%s\t%s\t%s\n", humanize(stats.min).c_str(), bench->getName(), config);
+                SkDebugf("%s\t%s\t%s\n", humanize(stats.median).c_str(), bench->getName(), config);
             } else {
                 const double stddev_percent = 100 * sqrt(stats.var) / stats.mean;
-                SkDebugf("%d\t%s\t%s\t%s\t%.0f%%\t%s\t%s\n"
+                SkDebugf("%d\t%s\t%s\t%s\t%s\t%.0f%%\t%s\t%s\n"
                         , loops
                         , humanize(stats.min).c_str()
+                        , humanize(stats.median).c_str()
                         , humanize(stats.mean).c_str()
                         , humanize(stats.max).c_str()
                         , stddev_percent
diff --git a/tools/Stats.h b/tools/Stats.h
index 2370084..5128897 100644
--- a/tools/Stats.h
+++ b/tools/Stats.h
@@ -1,6 +1,8 @@
 #ifndef Stats_DEFINED
 #define Stats_DEFINED
 
+#include "SkTSort.h"
+
 struct Stats {
     Stats(const double samples[], int n) {
         min = samples[0];
@@ -21,12 +23,18 @@
             err += (samples[i] - mean) * (samples[i] - mean);
         }
         var = err / (n-1);
+
+        SkAutoTMalloc<double> sorted(n);
+        memcpy(sorted.get(), samples, n * sizeof(double));
+        SkTQSort(sorted.get(), sorted.get() + n - 1);
+        median = sorted[n/2];
     }
 
     double min;
     double max;
     double mean;  // Estimate of population mean.
     double var;   // Estimate of population variance.
+    double median;
 };
 
 #endif//Stats_DEFINED