Add warmup bench to visual bench
authorjoshualitt <joshualitt@chromium.org>
Thu, 24 Sep 2015 15:08:23 +0000 (08:08 -0700)
committerCommit bot <commit-bot@chromium.org>
Thu, 24 Sep 2015 15:08:23 +0000 (08:08 -0700)
BUG=skia:

Review URL: https://codereview.chromium.org/1358373003

bench/RectBench.cpp
tools/VisualBench/VisualLightweightBenchModule.cpp
tools/VisualBench/VisualLightweightBenchModule.h

index db36395..f793c8f 100644 (file)
@@ -39,6 +39,8 @@ public:
         return fName.c_str();
     }
 
+    bool isVisual() override { return true; }
+
 protected:
     virtual void drawThisRect(SkCanvas* c, const SkRect& r, const SkPaint& p) {
         c->drawRect(r, p);
index 7b7cdbb..6f21c68 100644 (file)
@@ -26,6 +26,7 @@ __SK_FORCE_IMAGE_DECODER_LINKING;
 // Between samples we reset context
 // Between frames we swap buffers
 
+DEFINE_int32(maxWarmupFrames, 100, "maxmium frames to try and tune for sane timings");
 DEFINE_int32(gpuFrameLag, 5, "Overestimate of maximum number of frames GPU allows to lag.");
 DEFINE_int32(samples, 10, "Number of times to time each skp.");
 DEFINE_int32(frames, 5, "Number of frames of each skp to render per sample.");
@@ -46,18 +47,31 @@ static SkString humanize(double ms) {
 
 #define HUMANIZE(time) humanize(time).c_str()
 
+// A trivial bench to warm up the gpu
+class WarmupBench : public Benchmark {
+public:
+private:
+    const char* onGetName() override { return "warmupbench"; }
+    void onDraw(const int loops, SkCanvas* canvas) override {
+        for (int i = 0; i < loops; i++) {
+            sk_tool_utils::draw_checkerboard(canvas, 0xffffffff, 0xffc6c3c6, 10);
+        }
+    }
+};
+
 VisualLightweightBenchModule::VisualLightweightBenchModule(VisualBench* owner)
     : fCurrentSample(0)
     , fCurrentFrame(0)
     , fLoops(1)
-    , fState(kPreWarmLoops_State)
+    , fState(kWarmup_State)
     , fBenchmark(nullptr)
     , fOwner(SkRef(owner))
     , fResults(new ResultsWriter) {
     fBenchmarkStream.reset(new VisualBenchmarkStream);
 
     // Print header
-    SkDebugf("curr/maxrss\tloops\tflushes\tmin\tmedian\tmean\tmax\tstddev\tbench\n");
+    SkDebugf("curr/maxrss\tloops\tmin\tmedian\tmean\tmax\tstddev\t%-*s\tbench\n", FLAGS_samples,
+             "samples");
 
     // setup json logging if required
     if (!FLAGS_outResultsFile.isEmpty()) {
@@ -100,10 +114,10 @@ void VisualLightweightBenchModule::printStats() {
         configName.appendf("gpu");
     }
     fResults->config(configName.c_str());
-    fResults->configOption("name", fBenchmark->getUniqueName());
+    fResults->configOption("name", shortName);
     SkASSERT(measurements.count());
     Stats stats(measurements);
-    fResults->metric("min_ms",    stats.min);
+    fResults->metric("min_ms", stats.min);
 
     // Print output
     if (FLAGS_verbose) {
@@ -113,7 +127,7 @@ void VisualLightweightBenchModule::printStats() {
         SkDebugf("%s\n", shortName);
     } else {
         const double stdDevPercent = 100 * sqrt(stats.var) / stats.mean;
-        SkDebugf("%4d/%-4dMB\t%d\t%s\t%s\t%s\t%s\t%.0f%%\t%s\n",
+        SkDebugf("%4d/%-4dMB\t%d\t%s\t%s\t%s\t%s\t%.0f%%\t%s\t%s\n",
                  sk_tools::getCurrResidentSetSizeMB(),
                  sk_tools::getMaxResidentSetSizeMB(),
                  fLoops,
@@ -122,11 +136,17 @@ void VisualLightweightBenchModule::printStats() {
                  HUMANIZE(stats.mean),
                  HUMANIZE(stats.max),
                  stdDevPercent,
+                 stats.plot.c_str(),
                  shortName);
     }
 }
 
 bool VisualLightweightBenchModule::advanceRecordIfNecessary(SkCanvas* canvas) {
+    if (!fBenchmark && fState == kWarmup_State) {
+        fBenchmark.reset(new WarmupBench);
+        return true;
+    }
+
     if (fBenchmark) {
         return true;
     }
@@ -138,7 +158,6 @@ bool VisualLightweightBenchModule::advanceRecordIfNecessary(SkCanvas* canvas) {
 
     fOwner->clear(canvas, SK_ColorWHITE, 2);
 
-
     fBenchmark->preDraw();
     fRecords.push_back();
 
@@ -158,6 +177,27 @@ void VisualLightweightBenchModule::perCanvasPreDraw(SkCanvas* canvas, State next
     this->nextState(nextState);
 }
 
+void VisualLightweightBenchModule::warmup(SkCanvas* canvas) {
+    if (fCurrentFrame >= FLAGS_maxWarmupFrames) {
+        this->nextState(kPreWarmLoopsPerCanvasPreDraw_State);
+        fBenchmark.reset(nullptr);
+        this->resetTimingState();
+        fLoops = 1;
+    } else {
+        bool isEven = (fCurrentFrame++ % 2) == 0;
+        if (isEven) {
+            fTimer.start();
+        } else {
+            double elapsedMs = this->elapsed();
+            if (elapsedMs < FLAGS_loopMs) {
+                fLoops *= 2;
+            }
+            fTimer = WallTimer();
+            fOwner->reset();
+        }
+    }
+}
+
 void VisualLightweightBenchModule::preWarm(State nextState) {
     if (fCurrentFrame >= FLAGS_gpuFrameLag) {
         // we currently time across all frames to make sure we capture all GPU work
@@ -177,6 +217,10 @@ void VisualLightweightBenchModule::draw(SkCanvas* canvas) {
     }
     this->renderFrame(canvas);
     switch (fState) {
+        case kWarmup_State: {
+            this->warmup(canvas);
+            break;
+        }
         case kPreWarmLoopsPerCanvasPreDraw_State: {
             this->perCanvasPreDraw(canvas, kPreWarmLoops_State);
             break;
@@ -224,7 +268,7 @@ inline void VisualLightweightBenchModule::tuneLoops() {
     if (1 << 30 == fLoops) {
         // We're about to wrap.  Something's wrong with the bench.
         SkDebugf("InnerLoops wrapped\n");
-        fLoops = 0;
+        fLoops = 1;
     } else {
         double elapsedMs = this->elapsed();
         if (elapsedMs > FLAGS_loopMs) {
index 5d48692..0eb024b 100644 (file)
@@ -34,6 +34,7 @@ public:
 private:
     /*
      * The heart of visual bench is an event driven timing loop.
+     * kWarmup_State:                        We run a dummy bench to let things settle on startup
      * kPreWarmLoopsPerCanvasPreDraw_State:  Before we begin timing, Benchmarks have a hook to
      *                                       access the canvas.  Then we prewarm before the autotune
      *                                       loops step.
@@ -53,6 +54,7 @@ private:
      *                                       In either case we reset the context.
      */
     enum State {
+        kWarmup_State,
         kPreWarmLoopsPerCanvasPreDraw_State,
         kPreWarmLoops_State,
         kTuneLoops_State,
@@ -76,6 +78,7 @@ private:
     void resetTimingState();
     void postDraw(SkCanvas*);
     void recordMeasurement();
+    void warmup(SkCanvas* canvas);
 
     struct Record {
         SkTArray<double> fMeasurements;