move visual bench interactive module to timing state machine

BUG=skia:

Review URL: https://codereview.chromium.org/1382883003
diff --git a/tools/VisualBench/TimingStateMachine.cpp b/tools/VisualBench/TimingStateMachine.cpp
index c7f2f13..d7e4cf4 100644
--- a/tools/VisualBench/TimingStateMachine.cpp
+++ b/tools/VisualBench/TimingStateMachine.cpp
@@ -100,19 +100,11 @@
     fLastMeasurement = this->elapsed() / (FLAGS_frames * fLoops);
 }
 
-void TimingStateMachine::nextBenchmark(SkCanvas* canvas, Benchmark* benchmark) {
-    benchmark->postDraw(canvas);
-    benchmark->perCanvasPostDraw(canvas);
-    fLoops = 1;
-    this->nextState(kPreWarmLoopsPerCanvasPreDraw_State);
-}
-
 inline TimingStateMachine::ParentEvents TimingStateMachine::timing(SkCanvas* canvas,
                                                                    Benchmark* benchmark) {
     if (fCurrentFrame >= FLAGS_frames) {
         this->recordMeasurement();
         this->resetTimingState();
-        this->nextState(kPreWarmTimingPerCanvasPreDraw_State);
         return kTimingFinished_ParentEvents;
     } else {
         fCurrentFrame++;
@@ -120,3 +112,17 @@
     }
 }
 
+void TimingStateMachine::nextBenchmark(SkCanvas* canvas, Benchmark* benchmark) {
+    benchmark->postDraw(canvas);
+    benchmark->perCanvasPostDraw(canvas);
+    fLoops = 1;
+    this->nextState(kPreWarmLoopsPerCanvasPreDraw_State);
+}
+
+void TimingStateMachine::nextSampleWithPrewarm() {
+    this->nextState(kPreWarmTimingPerCanvasPreDraw_State);
+}
+
+void TimingStateMachine::nextSample() {
+    fTimer.start();
+}
diff --git a/tools/VisualBench/TimingStateMachine.h b/tools/VisualBench/TimingStateMachine.h
index 69ea243..5ec1313 100644
--- a/tools/VisualBench/TimingStateMachine.h
+++ b/tools/VisualBench/TimingStateMachine.h
@@ -39,6 +39,12 @@
     ParentEvents nextFrame(SkCanvas* canvas, Benchmark* benchmark);
 
     /*
+     * Before taking another sample, the owner can choose to prewarm or not
+     */
+    void nextSampleWithPrewarm();
+    void nextSample();
+
+    /*
      * The caller should call this when they are ready to move to the next benchmark.  The caller
      * must call this with the *last* benchmark so post draw hooks can be invoked
      */
diff --git a/tools/VisualBench/VisualInteractiveModule.cpp b/tools/VisualBench/VisualInteractiveModule.cpp
index af922a9..f41bcae 100755
--- a/tools/VisualBench/VisualInteractiveModule.cpp
+++ b/tools/VisualBench/VisualInteractiveModule.cpp
@@ -23,16 +23,10 @@
 
 __SK_FORCE_IMAGE_DECODER_LINKING;
 
-static const int kGpuFrameLag = 5;
-static const int kFrames = 5;
-static const double kLoopMs = 5;
-
 VisualInteractiveModule::VisualInteractiveModule(VisualBench* owner)
     : fCurrentMeasurement(0)
-    , fCurrentFrame(0)
-    , fLoops(1)
-    , fState(kPreWarmLoops_State)
     , fBenchmark(nullptr)
+    , fAdvance(false)
     , fOwner(SkRef(owner)) {
     fBenchmarkStream.reset(new VisualBenchmarkStream);
 
@@ -40,7 +34,7 @@
 }
 
 inline void VisualInteractiveModule::renderFrame(SkCanvas* canvas) {
-    fBenchmark->draw(fLoops, canvas);
+    fBenchmark->draw(fTSM.loops(), canvas);
     this->drawStats(canvas);
     canvas->flush();
     fOwner->present();
@@ -102,7 +96,8 @@
 
     return true;
 }
-
+#include "GrGpu.h"
+#include "GrResourceCache.h"
 void VisualInteractiveModule::draw(SkCanvas* canvas) {
     if (!this->advanceRecordIfNecessary(canvas)) {
         SkDebugf("Exiting VisualBench successfully\n");
@@ -110,123 +105,34 @@
         return;
     }
     this->renderFrame(canvas);
-    switch (fState) {
-        case kPreWarmLoopsPerCanvasPreDraw_State: {
-            this->perCanvasPreDraw(canvas, kPreWarmLoops_State);
+    TimingStateMachine::ParentEvents event = fTSM.nextFrame(canvas, fBenchmark);
+    switch (event) {
+        case TimingStateMachine::kReset_ParentEvents:
+            fOwner->reset();
             break;
-        }
-        case kPreWarmLoops_State: {
-            this->preWarm(kTuneLoops_State);
+        case TimingStateMachine::kTiming_ParentEvents:
             break;
-        }
-        case kTuneLoops_State: {
-            this->tuneLoops(canvas);
+        case TimingStateMachine::kTimingFinished_ParentEvents:
+            // Record measurements
+            fMeasurements[fCurrentMeasurement++] = fTSM.lastMeasurement();
+            fCurrentMeasurement &= (kMeasurementCount-1);  // fast mod
+            SkASSERT(fCurrentMeasurement < kMeasurementCount);
+            this->drawStats(canvas);
+            if (fAdvance) {
+                fAdvance = false;
+                fTSM.nextBenchmark(canvas, fBenchmark);
+                fBenchmark.reset(nullptr);
+                fOwner->reset();
+            } else {
+                fTSM.nextSample();
+            }
             break;
-        }
-        case kPreTiming_State: {
-            fBenchmark->perCanvasPreDraw(canvas);
-            fBenchmark->preDraw(canvas);
-            fCurrentFrame = 0;
-            fTimer.start();
-            fState = kTiming_State;
-            // fall to next state
-        }
-        case kTiming_State: {
-            this->timing(canvas);
-            break;
-        }
-        case kAdvance_State: {
-            this->postDraw(canvas);
-            this->nextState(kPreWarmLoopsPerCanvasPreDraw_State);
-            break;
-        }
-    }
-}
-
-inline void VisualInteractiveModule::nextState(State nextState) {
-    fState = nextState;
-}
-
-void VisualInteractiveModule::perCanvasPreDraw(SkCanvas* canvas, State nextState) {
-    fBenchmark->perCanvasPreDraw(canvas);
-    fBenchmark->preDraw(canvas);
-    fCurrentFrame = 0;
-    this->nextState(nextState);
-}
-
-void VisualInteractiveModule::preWarm(State nextState) {
-    if (fCurrentFrame >= kGpuFrameLag) {
-        // we currently time across all frames to make sure we capture all GPU work
-        this->nextState(nextState);
-        fCurrentFrame = 0;
-        fTimer.start();
-    } else {
-        fCurrentFrame++;
-    }
-}
-
-inline double VisualInteractiveModule::elapsed() {
-    fTimer.end();
-    return fTimer.fWall;
-}
-
-void VisualInteractiveModule::resetTimingState() {
-    fCurrentFrame = 0;
-    fTimer = WallTimer();
-    fOwner->reset();
-}
-
-void VisualInteractiveModule::scaleLoops(double elapsedMs) {
-    // Scale back the number of loops
-    fLoops = (int)ceil(fLoops * kLoopMs / elapsedMs);
-}
-
-inline void VisualInteractiveModule::tuneLoops(SkCanvas* canvas) {
-    if (1 << 30 == fLoops) {
-        // We're about to wrap.  Something's wrong with the bench.
-        SkDebugf("InnerLoops wrapped\n");
-        fLoops = 0;
-    } else {
-        double elapsedMs = this->elapsed();
-        if (elapsedMs > kLoopMs) {
-            this->scaleLoops(elapsedMs);
-            fBenchmark->perCanvasPostDraw(canvas);
-            this->nextState(kPreTiming_State);
-        } else {
-            fLoops *= 2;
-            this->nextState(kPreWarmLoops_State);
-        }
-        this->resetTimingState();
-    }
-}
-
-void VisualInteractiveModule::recordMeasurement() {
-    double measurement = this->elapsed() / (kFrames * fLoops);
-    fMeasurements[fCurrentMeasurement++] = measurement;
-    fCurrentMeasurement &= (kMeasurementCount-1);  // fast mod
-    SkASSERT(fCurrentMeasurement < kMeasurementCount);
-}
-
-void VisualInteractiveModule::postDraw(SkCanvas* canvas) {
-    fBenchmark->postDraw(canvas);
-    fBenchmark->perCanvasPostDraw(canvas);
-    fBenchmark.reset(nullptr);
-    fLoops = 1;
-}
-
-inline void VisualInteractiveModule::timing(SkCanvas* canvas) {
-    if (fCurrentFrame >= kFrames) {
-        this->recordMeasurement();
-        fTimer.start();
-        fCurrentFrame = 0;
-    } else {
-        fCurrentFrame++;
     }
 }
 
 bool VisualInteractiveModule::onHandleChar(SkUnichar c) {
     if (' ' == c) {
-        this->nextState(kAdvance_State);
+        fAdvance = true;
     }
 
     return true;
diff --git a/tools/VisualBench/VisualInteractiveModule.h b/tools/VisualBench/VisualInteractiveModule.h
index 4ff6a36..30d968a 100755
--- a/tools/VisualBench/VisualInteractiveModule.h
+++ b/tools/VisualBench/VisualInteractiveModule.h
@@ -14,6 +14,7 @@
 #include "ResultsWriter.h"
 #include "SkPicture.h"
 #include "Timer.h"
+#include "TimingStateMachine.h"
 #include "VisualBench.h"
 #include "VisualBenchmarkStream.h"
 
@@ -31,57 +32,21 @@
     bool onHandleChar(SkUnichar unichar) override;
 
 private:
-    /*
-     * The heart of visual bench is an event driven timing loop.
-     * kPreWarmLoopsPerCanvasPreDraw_State:  Before we begin timing, Benchmarks have a hook to
-     *                                       access the canvas.  Then we prewarm before the autotune
-     *                                       loops step.
-     * kPreWarmLoops_State:                  We prewarm the gpu before auto tuning to enter a steady
-     *                                       work state
-     * kTuneLoops_State:                     Then we tune the loops of the benchmark to ensure we
-     *                                       are doing a measurable amount of work
-     * kPreTiming_State:                     Because reset the context after tuning loops to ensure
-     *                                       coherent state, we need to restart before timing
-     * kTiming_State:                        Finally we time the benchmark.  In this case we
-     *                                       continue running and displaying benchmark data
-     *                                       until we quit or switch to another benchmark
-     * kAdvance_State:                       Advance to the next benchmark in the stream
-     */
-    enum State {
-        kPreWarmLoopsPerCanvasPreDraw_State,
-        kPreWarmLoops_State,
-        kTuneLoops_State,
-        kPreTiming_State,
-        kTiming_State,
-        kAdvance_State,
-    };
     void setTitle();
     bool setupBackend();
     void setupRenderTarget();
     void drawStats(SkCanvas*);
     bool advanceRecordIfNecessary(SkCanvas*);
     inline void renderFrame(SkCanvas*);
-    inline void nextState(State);
-    void perCanvasPreDraw(SkCanvas*, State);
-    void preWarm(State nextState);
-    void scaleLoops(double elapsedMs);
-    inline void tuneLoops(SkCanvas*);
-    inline void timing(SkCanvas*);
-    inline double elapsed();
-    void resetTimingState();
-    void postDraw(SkCanvas*);
-    void recordMeasurement();
 
     static const int kMeasurementCount = 64;  // should be power of 2 for fast mod
     double fMeasurements[kMeasurementCount];
     int fCurrentMeasurement;
 
-    int fCurrentFrame;
-    int fLoops;
-    WallTimer fTimer;
-    State fState;
     SkAutoTDelete<VisualBenchmarkStream> fBenchmarkStream;
     SkAutoTUnref<Benchmark> fBenchmark;
+    TimingStateMachine fTSM;
+    bool fAdvance;
 
     // support framework
     SkAutoTUnref<VisualBench> fOwner;
diff --git a/tools/VisualBench/VisualLightweightBenchModule.cpp b/tools/VisualBench/VisualLightweightBenchModule.cpp
index fa99caa..d964ae3 100644
--- a/tools/VisualBench/VisualLightweightBenchModule.cpp
+++ b/tools/VisualBench/VisualLightweightBenchModule.cpp
@@ -163,10 +163,11 @@
                 fTSM.nextBenchmark(canvas, fBenchmark);
                 fCurrentSample = 0;
                 fBenchmark.reset(nullptr);
+            } else {
+                fTSM.nextSampleWithPrewarm();
             }
             break;
     }
-
 }
 
 bool VisualLightweightBenchModule::onHandleChar(SkUnichar c) {