aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar joshualitt <joshualitt@chromium.org>2015-10-05 13:58:26 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2015-10-05 13:58:26 -0700
commitcb54e8ed4567adabd2ca8b49f7493effd2614158 (patch)
tree8dd6a39147cd26257d668b17269429d7ac92cf12
parent1562855b1981a57b5c2e40554d8f9641d069060b (diff)
Cleanup timing state machine
-rw-r--r--bench/Benchmark.h13
-rw-r--r--tools/VisualBench/TimingStateMachine.cpp138
-rw-r--r--tools/VisualBench/TimingStateMachine.h46
-rwxr-xr-xtools/VisualBench/VisualInteractiveModule.cpp17
-rwxr-xr-xtools/VisualBench/VisualInteractiveModule.h1
-rw-r--r--tools/VisualBench/VisualLightweightBenchModule.cpp18
-rw-r--r--tools/VisualBench/VisualLightweightBenchModule.h1
7 files changed, 105 insertions, 129 deletions
diff --git a/bench/Benchmark.h b/bench/Benchmark.h
index 00b05afa22..a403a6e318 100644
--- a/bench/Benchmark.h
+++ b/bench/Benchmark.h
@@ -111,6 +111,19 @@ public:
*/
virtual bool isVisual() { return false; }
+ /*
+ * VisualBench frequently resets the canvas. As a result we need to bulk call all of the hooks
+ */
+ void preTimingHooks(SkCanvas* canvas) {
+ this->perCanvasPreDraw(canvas);
+ this->preDraw(canvas);
+ }
+
+ void postTimingHooks(SkCanvas* canvas) {
+ this->postDraw(canvas);
+ this->perCanvasPostDraw(canvas);
+ }
+
protected:
virtual void setupPaint(SkPaint* paint);
diff --git a/tools/VisualBench/TimingStateMachine.cpp b/tools/VisualBench/TimingStateMachine.cpp
index d7e4cf4a77..acd01a1074 100644
--- a/tools/VisualBench/TimingStateMachine.cpp
+++ b/tools/VisualBench/TimingStateMachine.cpp
@@ -18,53 +18,63 @@ TimingStateMachine::TimingStateMachine()
: fCurrentFrame(0)
, fLoops(1)
, fLastMeasurement(0.)
- , fState(kPreWarmLoopsPerCanvasPreDraw_State) {
+ , fState(kPreWarm_State)
+ , fInnerState(kTuning_InnerState) {
}
-TimingStateMachine::ParentEvents TimingStateMachine::nextFrame(SkCanvas* canvas,
- Benchmark* benchmark) {
+TimingStateMachine::ParentEvents TimingStateMachine::nextFrame(bool preWarmBetweenSamples) {
+ ParentEvents parentEvent = kTiming_ParentEvents;
switch (fState) {
- case kPreWarmLoopsPerCanvasPreDraw_State:
- return this->perCanvasPreDraw(canvas, benchmark, kPreWarmLoops_State);
- case kPreWarmLoops_State:
- return this->preWarm(kTuneLoops_State);
- case kTuneLoops_State:
- return this->tuneLoops();
- case kPreWarmTimingPerCanvasPreDraw_State:
- return this->perCanvasPreDraw(canvas, benchmark, kPreWarmTiming_State);
- case kPreWarmTiming_State:
- return this->preWarm(kTiming_State);
- case kTiming_State:
- return this->timing(canvas, benchmark);
- }
- SkFAIL("Incomplete switch\n");
- return kTiming_ParentEvents;
-}
-
-inline void TimingStateMachine::nextState(State nextState) {
- fState = nextState;
-}
-
-TimingStateMachine::ParentEvents TimingStateMachine::perCanvasPreDraw(SkCanvas* canvas,
- Benchmark* benchmark,
- State nextState) {
- benchmark->perCanvasPreDraw(canvas);
- benchmark->preDraw(canvas);
- fCurrentFrame = 0;
- this->nextState(nextState);
- return kTiming_ParentEvents;
-}
-
-TimingStateMachine::ParentEvents TimingStateMachine::preWarm(State nextState) {
- if (fCurrentFrame >= FLAGS_gpuFrameLag) {
- // we currently time across all frames to make sure we capture all GPU work
- this->nextState(nextState);
- fCurrentFrame = 0;
- fTimer.start();
- } else {
- fCurrentFrame++;
+ case kPreWarm_State: {
+ if (fCurrentFrame >= FLAGS_gpuFrameLag) {
+ fCurrentFrame = 0;
+ fTimer.start();
+ fState = kTiming_State;
+ } else {
+ fCurrentFrame++;
+ }
+ break;
+ }
+ case kTiming_State: {
+ switch (fInnerState) {
+ case kTuning_InnerState: {
+ if (1 << 30 == fLoops) {
+ // We're about to wrap. Something's wrong with the bench.
+ SkDebugf("InnerLoops wrapped\n");
+ fLoops = 1;
+ } else {
+ double elapsedMs = this->elapsed();
+ if (elapsedMs < FLAGS_loopMs) {
+ fLoops *= 2;
+ } else {
+ fInnerState = kTiming_InnerState;
+ fState = kPreWarm_State;
+ }
+ this->resetTimingState();
+ parentEvent = kReset_ParentEvents;
+ }
+ break;
+ }
+ case kTiming_InnerState: {
+ if (fCurrentFrame >= FLAGS_frames) {
+ this->recordMeasurement();
+ this->resetTimingState();
+ parentEvent = kTimingFinished_ParentEvents;
+ if (preWarmBetweenSamples) {
+ fState = kPreWarm_State;
+ } else {
+ fTimer.start(); // start timing again, don't change state
+ }
+ } else {
+ fCurrentFrame++;
+ }
+ break;
+ }
+ }
+ }
+ break;
}
- return kTiming_ParentEvents;
+ return parentEvent;
}
inline double TimingStateMachine::elapsed() {
@@ -77,52 +87,14 @@ void TimingStateMachine::resetTimingState() {
fTimer = WallTimer();
}
-inline TimingStateMachine::ParentEvents TimingStateMachine::tuneLoops() {
- if (1 << 30 == fLoops) {
- // We're about to wrap. Something's wrong with the bench.
- SkDebugf("InnerLoops wrapped\n");
- fLoops = 1;
- return kTiming_ParentEvents;
- } else {
- double elapsedMs = this->elapsed();
- if (elapsedMs > FLAGS_loopMs) {
- this->nextState(kPreWarmTimingPerCanvasPreDraw_State);
- } else {
- fLoops *= 2;
- this->nextState(kPreWarmLoops_State);
- }
- this->resetTimingState();
- return kReset_ParentEvents;
- }
-}
-
void TimingStateMachine::recordMeasurement() {
fLastMeasurement = this->elapsed() / (FLAGS_frames * fLoops);
}
-inline TimingStateMachine::ParentEvents TimingStateMachine::timing(SkCanvas* canvas,
- Benchmark* benchmark) {
- if (fCurrentFrame >= FLAGS_frames) {
- this->recordMeasurement();
- this->resetTimingState();
- return kTimingFinished_ParentEvents;
- } else {
- fCurrentFrame++;
- return kTiming_ParentEvents;
- }
-}
-
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();
+ fInnerState = kTuning_InnerState;
+ fState = kPreWarm_State;
}
diff --git a/tools/VisualBench/TimingStateMachine.h b/tools/VisualBench/TimingStateMachine.h
index 5ec1313b1f..7f7a5affb5 100644
--- a/tools/VisualBench/TimingStateMachine.h
+++ b/tools/VisualBench/TimingStateMachine.h
@@ -36,13 +36,7 @@ public:
// reset
};
- ParentEvents nextFrame(SkCanvas* canvas, Benchmark* benchmark);
-
- /*
- * Before taking another sample, the owner can choose to prewarm or not
- */
- void nextSampleWithPrewarm();
- void nextSample();
+ ParentEvents nextFrame(bool preWarmBetweenSamples);
/*
* The caller should call this when they are ready to move to the next benchmark. The caller
@@ -50,7 +44,6 @@ public:
*/
void nextBenchmark(SkCanvas*, Benchmark*);
-
/*
* When TimingStateMachine returns kTimingFinished_ParentEvents, then the owner can call
* lastMeasurement() to get the time
@@ -60,43 +53,17 @@ public:
int loops() const { return fLoops; }
private:
- /*
- * The heart of the timing state machine 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
- * kPreWarmTimingPerCanvasPreDraw_State: Because reset the context after tuning loops to ensure
- * coherent state, we need to give the benchmark
- * another hook
- * kPreWarmTiming_State: We prewarm the gpu again to enter a steady state
- * kTiming_State: Finally we time the benchmark. When finished timing
- * if we have enough samples then we'll start the next
- * benchmark in the kPreWarmLoopsPerCanvasPreDraw_State.
- * otherwise, we enter the
- * kPreWarmTimingPerCanvasPreDraw_State for another sample
- * In either case we reset the context.
- */
enum State {
- kPreWarmLoopsPerCanvasPreDraw_State,
- kPreWarmLoops_State,
- kTuneLoops_State,
- kPreWarmTimingPerCanvasPreDraw_State,
- kPreWarmTiming_State,
+ kPreWarm_State,
kTiming_State,
};
+ enum InnerState {
+ kTuning_InnerState,
+ kTiming_InnerState,
+ };
- inline void nextState(State);
- ParentEvents perCanvasPreDraw(SkCanvas*, Benchmark*, State);
- ParentEvents preWarm(State nextState);
- inline ParentEvents tuneLoops();
- inline ParentEvents timing(SkCanvas*, Benchmark*);
inline double elapsed();
void resetTimingState();
- void postDraw(SkCanvas*, Benchmark*);
void recordMeasurement();
int fCurrentFrame;
@@ -104,6 +71,7 @@ private:
double fLastMeasurement;
WallTimer fTimer;
State fState;
+ InnerState fInnerState;
};
#endif
diff --git a/tools/VisualBench/VisualInteractiveModule.cpp b/tools/VisualBench/VisualInteractiveModule.cpp
index f41bcaebab..d2e5b20fa3 100755
--- a/tools/VisualBench/VisualInteractiveModule.cpp
+++ b/tools/VisualBench/VisualInteractiveModule.cpp
@@ -27,6 +27,7 @@ VisualInteractiveModule::VisualInteractiveModule(VisualBench* owner)
: fCurrentMeasurement(0)
, fBenchmark(nullptr)
, fAdvance(false)
+ , fHasBeenReset(false)
, fOwner(SkRef(owner)) {
fBenchmarkStream.reset(new VisualBenchmarkStream);
@@ -93,7 +94,7 @@ bool VisualInteractiveModule::advanceRecordIfNecessary(SkCanvas* canvas) {
fOwner->clear(canvas, SK_ColorWHITE, 2);
fBenchmark->delayedSetup();
-
+ fBenchmark->preTimingHooks(canvas);
return true;
}
#include "GrGpu.h"
@@ -104,10 +105,18 @@ void VisualInteractiveModule::draw(SkCanvas* canvas) {
fOwner->closeWindow();
return;
}
+
+ if (fHasBeenReset) {
+ fHasBeenReset = false;
+ fBenchmark->preTimingHooks(canvas);
+ }
+
this->renderFrame(canvas);
- TimingStateMachine::ParentEvents event = fTSM.nextFrame(canvas, fBenchmark);
+ TimingStateMachine::ParentEvents event = fTSM.nextFrame(false);
switch (event) {
case TimingStateMachine::kReset_ParentEvents:
+ fBenchmark->postTimingHooks(canvas);
+ fHasBeenReset = true;
fOwner->reset();
break;
case TimingStateMachine::kTiming_ParentEvents:
@@ -121,10 +130,10 @@ void VisualInteractiveModule::draw(SkCanvas* canvas) {
if (fAdvance) {
fAdvance = false;
fTSM.nextBenchmark(canvas, fBenchmark);
+ fBenchmark->postTimingHooks(canvas);
fBenchmark.reset(nullptr);
fOwner->reset();
- } else {
- fTSM.nextSample();
+ fHasBeenReset = true;
}
break;
}
diff --git a/tools/VisualBench/VisualInteractiveModule.h b/tools/VisualBench/VisualInteractiveModule.h
index 30d968a5d3..5b9ff0a340 100755
--- a/tools/VisualBench/VisualInteractiveModule.h
+++ b/tools/VisualBench/VisualInteractiveModule.h
@@ -47,6 +47,7 @@ private:
SkAutoTUnref<Benchmark> fBenchmark;
TimingStateMachine fTSM;
bool fAdvance;
+ bool fHasBeenReset;
// support framework
SkAutoTUnref<VisualBench> fOwner;
diff --git a/tools/VisualBench/VisualLightweightBenchModule.cpp b/tools/VisualBench/VisualLightweightBenchModule.cpp
index d964ae3e58..e2942d18bd 100644
--- a/tools/VisualBench/VisualLightweightBenchModule.cpp
+++ b/tools/VisualBench/VisualLightweightBenchModule.cpp
@@ -44,6 +44,7 @@ static SkString humanize(double ms) {
VisualLightweightBenchModule::VisualLightweightBenchModule(VisualBench* owner)
: fCurrentSample(0)
+ , fHasBeenReset(false)
, fOwner(SkRef(owner))
, fResults(new ResultsWriter) {
fBenchmarkStream.reset(new VisualBenchmarkStream);
@@ -132,12 +133,14 @@ bool VisualLightweightBenchModule::advanceRecordIfNecessary(SkCanvas* canvas) {
fOwner->clear(canvas, SK_ColorWHITE, 2);
- fBenchmark->delayedSetup();
fRecords.push_back();
// Log bench name
fResults->bench(fBenchmark->getUniqueName(), fBenchmark->getSize().fX,
fBenchmark->getSize().fY);
+
+ fBenchmark->delayedSetup();
+ fBenchmark->preTimingHooks(canvas);
return true;
}
@@ -147,15 +150,24 @@ void VisualLightweightBenchModule::draw(SkCanvas* canvas) {
fOwner->closeWindow();
return;
}
+
+ if (fHasBeenReset) {
+ fHasBeenReset = false;
+ fBenchmark->preTimingHooks(canvas);
+ }
+
this->renderFrame(canvas);
- TimingStateMachine::ParentEvents event = fTSM.nextFrame(canvas, fBenchmark);
+ 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) {
@@ -164,7 +176,7 @@ void VisualLightweightBenchModule::draw(SkCanvas* canvas) {
fCurrentSample = 0;
fBenchmark.reset(nullptr);
} else {
- fTSM.nextSampleWithPrewarm();
+ fHasBeenReset = true;
}
break;
}
diff --git a/tools/VisualBench/VisualLightweightBenchModule.h b/tools/VisualBench/VisualLightweightBenchModule.h
index ffa109dc49..3538a48a59 100644
--- a/tools/VisualBench/VisualLightweightBenchModule.h
+++ b/tools/VisualBench/VisualLightweightBenchModule.h
@@ -47,6 +47,7 @@ private:
SkAutoTDelete<VisualBenchmarkStream> fBenchmarkStream;
SkAutoTUnref<Benchmark> fBenchmark;
TimingStateMachine fTSM;
+ bool fHasBeenReset;
// support framework
SkAutoTUnref<VisualBench> fOwner;