| Index: tools/VisualBench/TimingStateMachine.cpp
|
| diff --git a/tools/VisualBench/TimingStateMachine.cpp b/tools/VisualBench/TimingStateMachine.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..c7f2f134709ea9fda4a4c171b28951989e073c0d
|
| --- /dev/null
|
| +++ b/tools/VisualBench/TimingStateMachine.cpp
|
| @@ -0,0 +1,122 @@
|
| +/*
|
| + * 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 "TimingStateMachine.h"
|
| +
|
| +#include "SkCanvas.h"
|
| +#include "SkCommandLineFlags.h"
|
| +
|
| +DEFINE_int32(gpuFrameLag, 5, "Overestimate of maximum number of frames GPU is allowed to lag.");
|
| +DEFINE_int32(frames, 5, "Number of frames of each skp to render per sample.");
|
| +DEFINE_double(loopMs, 5, "Each benchmark will be tuned until it takes loopsMs millseconds.");
|
| +
|
| +TimingStateMachine::TimingStateMachine()
|
| + : fCurrentFrame(0)
|
| + , fLoops(1)
|
| + , fLastMeasurement(0.)
|
| + , fState(kPreWarmLoopsPerCanvasPreDraw_State) {
|
| +}
|
| +
|
| +TimingStateMachine::ParentEvents TimingStateMachine::nextFrame(SkCanvas* canvas,
|
| + Benchmark* benchmark) {
|
| + 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++;
|
| + }
|
| + return kTiming_ParentEvents;
|
| +}
|
| +
|
| +inline double TimingStateMachine::elapsed() {
|
| + fTimer.end();
|
| + return fTimer.fWall;
|
| +}
|
| +
|
| +void TimingStateMachine::resetTimingState() {
|
| + fCurrentFrame = 0;
|
| + 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);
|
| +}
|
| +
|
| +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++;
|
| + return kTiming_ParentEvents;
|
| + }
|
| +}
|
| +
|
|
|