Create VisualStreamTimingModule

BUG=skia:

Review URL: https://codereview.chromium.org/1385073002
diff --git a/tools/VisualBench/TimingStateMachine.h b/tools/VisualBench/TimingStateMachine.h
index 7f7a5af..2215059 100644
--- a/tools/VisualBench/TimingStateMachine.h
+++ b/tools/VisualBench/TimingStateMachine.h
@@ -3,7 +3,6 @@
  *
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
- *
  */
 
 #ifndef TimingStateMachine_DEFINED
diff --git a/tools/VisualBench/VisualInteractiveModule.cpp b/tools/VisualBench/VisualInteractiveModule.cpp
index d2e5b20..b597b05 100755
--- a/tools/VisualBench/VisualInteractiveModule.cpp
+++ b/tools/VisualBench/VisualInteractiveModule.cpp
@@ -3,42 +3,28 @@
  *
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
- *
  */
 
 #include "VisualInteractiveModule.h"
 
-#include "ProcStats.h"
-#include "SkApplication.h"
 #include "SkCanvas.h"
 #include "SkCommandLineFlags.h"
 #include "SkForceLinking.h"
-#include "SkGraphics.h"
-#include "SkGr.h"
 #include "SkImageDecoder.h"
-#include "SkOSFile.h"
-#include "SkStream.h"
-#include "Stats.h"
-#include "gl/GrGLInterface.h"
 
 __SK_FORCE_IMAGE_DECODER_LINKING;
 
 VisualInteractiveModule::VisualInteractiveModule(VisualBench* owner)
-    : fCurrentMeasurement(0)
-    , fBenchmark(nullptr)
-    , fAdvance(false)
-    , fHasBeenReset(false)
-    , fOwner(SkRef(owner)) {
-    fBenchmarkStream.reset(new VisualBenchmarkStream);
-
+    : INHERITED(owner, false)
+    , fCurrentMeasurement(0)
+    , fAdvance(false) {
     memset(fMeasurements, 0, sizeof(fMeasurements));
 }
 
-inline void VisualInteractiveModule::renderFrame(SkCanvas* canvas) {
-    fBenchmark->draw(fTSM.loops(), canvas);
+void VisualInteractiveModule::renderFrame(SkCanvas* canvas, Benchmark* benchmark, int loops) {
+    benchmark->draw(loops, canvas);
     this->drawStats(canvas);
     canvas->flush();
-    fOwner->present();
 }
 
 void VisualInteractiveModule::drawStats(SkCanvas* canvas) {
@@ -80,63 +66,16 @@
 
 }
 
-bool VisualInteractiveModule::advanceRecordIfNecessary(SkCanvas* canvas) {
-    if (fBenchmark) {
+bool VisualInteractiveModule::timingFinished(Benchmark* benchmark, int loops, double measurement) {
+    // Record measurements
+    fMeasurements[fCurrentMeasurement++] = measurement;
+    fCurrentMeasurement &= (kMeasurementCount-1);  // fast mod
+    SkASSERT(fCurrentMeasurement < kMeasurementCount);
+    if (fAdvance) {
+        fAdvance = false;
         return true;
     }
-
-    fBenchmark.reset(fBenchmarkStream->next());
-    if (!fBenchmark) {
-        return false;
-    }
-
-    // clear both buffers
-    fOwner->clear(canvas, SK_ColorWHITE, 2);
-
-    fBenchmark->delayedSetup();
-    fBenchmark->preTimingHooks(canvas);
-    return true;
-}
-#include "GrGpu.h"
-#include "GrResourceCache.h"
-void VisualInteractiveModule::draw(SkCanvas* canvas) {
-    if (!this->advanceRecordIfNecessary(canvas)) {
-        SkDebugf("Exiting VisualBench successfully\n");
-        fOwner->closeWindow();
-        return;
-    }
-
-    if (fHasBeenReset) {
-        fHasBeenReset = false;
-        fBenchmark->preTimingHooks(canvas);
-    }
-
-    this->renderFrame(canvas);
-    TimingStateMachine::ParentEvents event = fTSM.nextFrame(false);
-    switch (event) {
-        case TimingStateMachine::kReset_ParentEvents:
-            fBenchmark->postTimingHooks(canvas);
-            fHasBeenReset = true;
-            fOwner->reset();
-            break;
-        case TimingStateMachine::kTiming_ParentEvents:
-            break;
-        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->postTimingHooks(canvas);
-                fBenchmark.reset(nullptr);
-                fOwner->reset();
-                fHasBeenReset = true;
-            }
-            break;
-    }
+    return false;
 }
 
 bool VisualInteractiveModule::onHandleChar(SkUnichar c) {
diff --git a/tools/VisualBench/VisualInteractiveModule.h b/tools/VisualBench/VisualInteractiveModule.h
index 5b9ff0a..d4f8f69 100755
--- a/tools/VisualBench/VisualInteractiveModule.h
+++ b/tools/VisualBench/VisualInteractiveModule.h
@@ -3,56 +3,36 @@
  *
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
- *
  */
 
 #ifndef VisualInteractiveModule_DEFINED
 #define VisualInteractiveModule_DEFINED
 
-#include "VisualModule.h"
-
-#include "ResultsWriter.h"
-#include "SkPicture.h"
-#include "Timer.h"
-#include "TimingStateMachine.h"
-#include "VisualBench.h"
-#include "VisualBenchmarkStream.h"
+#include "VisualStreamTimingModule.h"
 
 class SkCanvas;
 
 /*
  * This module for VisualBench is designed to display stats data dynamically
  */
-class VisualInteractiveModule : public VisualModule {
+class VisualInteractiveModule : public VisualStreamTimingModule {
 public:
     // TODO get rid of backpointer
     VisualInteractiveModule(VisualBench* owner);
 
-    void draw(SkCanvas* canvas) override;
-    bool onHandleChar(SkUnichar unichar) override;
+    bool onHandleChar(SkUnichar c) override;
 
 private:
-    void setTitle();
-    bool setupBackend();
-    void setupRenderTarget();
     void drawStats(SkCanvas*);
-    bool advanceRecordIfNecessary(SkCanvas*);
-    inline void renderFrame(SkCanvas*);
+    void renderFrame(SkCanvas*, Benchmark*, int loops) override;
+    bool timingFinished(Benchmark*, int loops, double measurement) override;
 
     static const int kMeasurementCount = 64;  // should be power of 2 for fast mod
     double fMeasurements[kMeasurementCount];
     int fCurrentMeasurement;
-
-    SkAutoTDelete<VisualBenchmarkStream> fBenchmarkStream;
-    SkAutoTUnref<Benchmark> fBenchmark;
-    TimingStateMachine fTSM;
     bool fAdvance;
-    bool fHasBeenReset;
 
-    // support framework
-    SkAutoTUnref<VisualBench> fOwner;
-
-    typedef VisualModule INHERITED;
+    typedef VisualStreamTimingModule INHERITED;
 };
 
 #endif
diff --git a/tools/VisualBench/VisualLightweightBenchModule.cpp b/tools/VisualBench/VisualLightweightBenchModule.cpp
index e2942d1..af939ff 100644
--- a/tools/VisualBench/VisualLightweightBenchModule.cpp
+++ b/tools/VisualBench/VisualLightweightBenchModule.cpp
@@ -3,7 +3,6 @@
  *
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
- *
  */
 
 #include "VisualLightweightBenchModule.h"
@@ -43,12 +42,9 @@
 #define HUMANIZE(time) humanize(time).c_str()
 
 VisualLightweightBenchModule::VisualLightweightBenchModule(VisualBench* owner)
-    : fCurrentSample(0)
-    , fHasBeenReset(false)
-    , fOwner(SkRef(owner))
+    : INHERITED(owner, true)
+    , fCurrentSample(0)
     , fResults(new ResultsWriter) {
-    fBenchmarkStream.reset(new VisualBenchmarkStream);
-
     // Print header
     SkDebugf("curr/maxrss\tloops\tmin\tmedian\tmean\tmax\tstddev\t%-*s\tbench\n", FLAGS_samples,
              "samples");
@@ -73,17 +69,19 @@
             fResults->property(FLAGS_properties[i - 1], FLAGS_properties[i]);
         }
     }
+
+    // seed an initial record
+    fRecords.push_back();
 }
 
-inline void VisualLightweightBenchModule::renderFrame(SkCanvas* canvas) {
-    fBenchmark->draw(fTSM.loops(), canvas);
+void VisualLightweightBenchModule::renderFrame(SkCanvas* canvas, Benchmark* benchmark, int loops) {
+    benchmark->draw(loops, canvas);
     canvas->flush();
-    fOwner->present();
 }
 
-void VisualLightweightBenchModule::printStats() {
+void VisualLightweightBenchModule::printStats(Benchmark* benchmark, int loops) {
     const SkTArray<double>& measurements = fRecords.back().fMeasurements;
-    const char* shortName = fBenchmark->getUniqueName();
+    const char* shortName = benchmark->getUniqueName();
 
     // update log
     // Note: We currently log only the minimum.  It would be interesting to log more information
@@ -93,6 +91,9 @@
     } else {
         configName.appendf("gpu");
     }
+    // Log bench name
+    fResults->bench(shortName, benchmark->getSize().fX, benchmark->getSize().fY);
+
     fResults->config(configName.c_str());
     fResults->configOption("name", shortName);
     SkASSERT(measurements.count());
@@ -110,7 +111,7 @@
         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(),
-                 fTSM.loops(),
+                 loops,
                  HUMANIZE(stats.min),
                  HUMANIZE(stats.median),
                  HUMANIZE(stats.mean),
@@ -121,65 +122,16 @@
     }
 }
 
-bool VisualLightweightBenchModule::advanceRecordIfNecessary(SkCanvas* canvas) {
-    if (fBenchmark) {
+bool VisualLightweightBenchModule::timingFinished(Benchmark* benchmark, int loops,
+                                                  double measurement) {
+    fRecords.back().fMeasurements.push_back(measurement);
+    if (++fCurrentSample > FLAGS_samples) {
+        this->printStats(benchmark, loops);
+        fRecords.push_back();
+        fCurrentSample = 0;
         return true;
     }
-
-    fBenchmark.reset(fBenchmarkStream->next());
-    if (!fBenchmark) {
-        return false;
-    }
-
-    fOwner->clear(canvas, SK_ColorWHITE, 2);
-
-    fRecords.push_back();
-
-    // Log bench name
-    fResults->bench(fBenchmark->getUniqueName(), fBenchmark->getSize().fX,
-                    fBenchmark->getSize().fY);
-
-    fBenchmark->delayedSetup();
-    fBenchmark->preTimingHooks(canvas);
-    return true;
-}
-
-void VisualLightweightBenchModule::draw(SkCanvas* canvas) {
-    if (!this->advanceRecordIfNecessary(canvas)) {
-        SkDebugf("Exiting VisualBench successfully\n");
-        fOwner->closeWindow();
-        return;
-    }
-
-    if (fHasBeenReset) {
-        fHasBeenReset = false;
-        fBenchmark->preTimingHooks(canvas);
-    }
-
-    this->renderFrame(canvas);
-    TimingStateMachine::ParentEvents event = fTSM.nextFrame(true);
-    switch (event) {
-        case TimingStateMachine::kReset_ParentEvents:
-            fBenchmark->postTimingHooks(canvas);
-            fOwner->reset();
-            fHasBeenReset = true;
-            break;
-        case TimingStateMachine::kTiming_ParentEvents:
-            break;
-        case TimingStateMachine::kTimingFinished_ParentEvents:
-            fBenchmark->postTimingHooks(canvas);
-            fOwner->reset();
-            fRecords.back().fMeasurements.push_back(fTSM.lastMeasurement());
-            if (++fCurrentSample > FLAGS_samples) {
-                this->printStats();
-                fTSM.nextBenchmark(canvas, fBenchmark);
-                fCurrentSample = 0;
-                fBenchmark.reset(nullptr);
-            } else {
-                fHasBeenReset = true;
-            }
-            break;
-    }
+    return false;
 }
 
 bool VisualLightweightBenchModule::onHandleChar(SkUnichar c) {
diff --git a/tools/VisualBench/VisualLightweightBenchModule.h b/tools/VisualBench/VisualLightweightBenchModule.h
index 3538a48..7618ff2 100644
--- a/tools/VisualBench/VisualLightweightBenchModule.h
+++ b/tools/VisualBench/VisualLightweightBenchModule.h
@@ -3,57 +3,44 @@
  *
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
- *
  */
 
 #ifndef VisualLightweightBenchModule_DEFINED
 #define VisualLightweightBenchModule_DEFINED
 
-#include "VisualModule.h"
+#include "VisualStreamTimingModule.h"
 
 #include "ResultsWriter.h"
 #include "SkPicture.h"
-#include "TimingStateMachine.h"
 #include "VisualBench.h"
-#include "VisualBenchmarkStream.h"
 
 class SkCanvas;
 
 /*
  * This module is designed to be a minimal overhead timing module for VisualBench
  */
-class VisualLightweightBenchModule : public VisualModule {
+class VisualLightweightBenchModule : public VisualStreamTimingModule {
 public:
     // TODO get rid of backpointer
     VisualLightweightBenchModule(VisualBench* owner);
 
-    void draw(SkCanvas* canvas) override;
-
     bool onHandleChar(SkUnichar c) override;
 
 private:
-    void setTitle();
-    bool setupBackend();
-    void setupRenderTarget();
-    void printStats();
-    bool advanceRecordIfNecessary(SkCanvas*);
-    inline void renderFrame(SkCanvas*);
+    void renderFrame(SkCanvas*, Benchmark*, int loops) override;
+    bool timingFinished(Benchmark*, int loops, double measurement) override;
+    void printStats(Benchmark*, int loops);
 
     struct Record {
         SkTArray<double> fMeasurements;
     };
     int fCurrentSample;
     SkTArray<Record> fRecords;
-    SkAutoTDelete<VisualBenchmarkStream> fBenchmarkStream;
-    SkAutoTUnref<Benchmark> fBenchmark;
-    TimingStateMachine fTSM;
-    bool fHasBeenReset;
 
     // support framework
-    SkAutoTUnref<VisualBench> fOwner;
     SkAutoTDelete<ResultsWriter> fResults;
 
-    typedef VisualModule INHERITED;
+    typedef VisualStreamTimingModule INHERITED;
 };
 
 #endif
diff --git a/tools/VisualBench/VisualStreamTimingModule.cpp b/tools/VisualBench/VisualStreamTimingModule.cpp
new file mode 100644
index 0000000..db75890
--- /dev/null
+++ b/tools/VisualBench/VisualStreamTimingModule.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "VisualStreamTimingModule.h"
+
+#include "SkCanvas.h"
+
+VisualStreamTimingModule::VisualStreamTimingModule(VisualBench* owner, bool preWarmBeforeSample)
+    : fReinitializeBenchmark(false)
+    , fPreWarmBeforeSample(preWarmBeforeSample)
+    , fOwner(owner) {
+    fBenchmarkStream.reset(new VisualBenchmarkStream);
+}
+
+bool VisualStreamTimingModule::nextBenchmarkIfNecessary(SkCanvas* canvas) {
+    if (fBenchmark) {
+        return true;
+    }
+
+    fBenchmark.reset(fBenchmarkStream->next());
+    if (!fBenchmark) {
+        return false;
+    }
+
+    fOwner->clear(canvas, SK_ColorWHITE, 2);
+
+    fBenchmark->delayedSetup();
+    fBenchmark->preTimingHooks(canvas);
+    return true;
+}
+
+void VisualStreamTimingModule::draw(SkCanvas* canvas) {
+    if (!this->nextBenchmarkIfNecessary(canvas)) {
+        SkDebugf("Exiting VisualBench successfully\n");
+        fOwner->closeWindow();
+        return;
+    }
+
+    if (fReinitializeBenchmark) {
+        fReinitializeBenchmark = false;
+        fBenchmark->preTimingHooks(canvas);
+    }
+
+    this->renderFrame(canvas, fBenchmark, fTSM.loops());
+    fOwner->present();
+    TimingStateMachine::ParentEvents event = fTSM.nextFrame(fPreWarmBeforeSample);
+    switch (event) {
+        case TimingStateMachine::kReset_ParentEvents:
+            fBenchmark->postTimingHooks(canvas);
+            fOwner->reset();
+            fReinitializeBenchmark = true;
+            break;
+        case TimingStateMachine::kTiming_ParentEvents:
+            break;
+        case TimingStateMachine::kTimingFinished_ParentEvents:
+            fBenchmark->postTimingHooks(canvas);
+            fOwner->reset();
+            if (this->timingFinished(fBenchmark, fTSM.loops(), fTSM.lastMeasurement())) {
+                fTSM.nextBenchmark(canvas, fBenchmark);
+                fBenchmark.reset(nullptr);
+            } else {
+                fReinitializeBenchmark = true;
+            }
+            break;
+    }
+}
diff --git a/tools/VisualBench/VisualStreamTimingModule.h b/tools/VisualBench/VisualStreamTimingModule.h
new file mode 100644
index 0000000..ac06ed4
--- /dev/null
+++ b/tools/VisualBench/VisualStreamTimingModule.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef VisualStreamTimingModule_DEFINED
+#define VisualStreamTimingModule_DEFINED
+
+#include "VisualModule.h"
+
+#include "TimingStateMachine.h"
+#include "VisualBench.h"
+#include "VisualBenchmarkStream.h"
+
+/*
+ * VisualStreamTimingModule is the base class for modules which want to time a stream of Benchmarks.
+ *
+ * Subclasses should implement renderFrame, which is called for each frame, and timingFinished,
+ * which is called when a sample has finished timing.
+ */
+class VisualStreamTimingModule : public VisualModule {
+public:
+    VisualStreamTimingModule(VisualBench* owner, bool preWarmBeforeSample);
+    void draw(SkCanvas* canvas) override;
+
+private:
+    virtual void renderFrame(SkCanvas*, Benchmark*, int loops)=0;
+
+    // subclasses should return true to advance the stream
+    virtual bool timingFinished(Benchmark*, int loops, double measurement)=0;
+
+    bool nextBenchmarkIfNecessary(SkCanvas*);
+
+    TimingStateMachine fTSM;
+    SkAutoTDelete<VisualBenchmarkStream> fBenchmarkStream;
+    SkAutoTUnref<Benchmark> fBenchmark;
+    bool fReinitializeBenchmark;
+    bool fPreWarmBeforeSample;
+
+    // support framework
+    VisualBench* fOwner;
+
+    typedef VisualModule INHERITED;
+};
+
+#endif