/* * 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."); static double now_ms() { return SkTime::GetNSecs() * 1e-6; } TimingStateMachine::TimingStateMachine() : fCurrentFrame(0) , fLoops(1) , fLastMeasurement(0.) , fState(kPreWarm_State) , fInnerState(kTuning_InnerState) { } TimingStateMachine::ParentEvents TimingStateMachine::nextFrame(bool preWarmBetweenSamples) { ParentEvents parentEvent = kTiming_ParentEvents; switch (fState) { case kPreWarm_State: { if (fCurrentFrame >= FLAGS_gpuFrameLag) { fCurrentFrame = 0; fStartTime = now_ms(); 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 = now_ms() - fStartTime; if (elapsedMs < FLAGS_loopMs) { fLoops *= 2; } else { fInnerState = kTiming_InnerState; } fState = kPreWarm_State; fCurrentFrame = 0; parentEvent = kReset_ParentEvents; } break; } case kTiming_InnerState: { if (fCurrentFrame >= FLAGS_frames) { double now = now_ms(); fLastMeasurement = (now - fStartTime) / (FLAGS_frames * fLoops); fCurrentFrame = 0; parentEvent = kTimingFinished_ParentEvents; if (preWarmBetweenSamples) { fState = kPreWarm_State; } else { fStartTime = now; } } else { fCurrentFrame++; } break; } } } break; } return parentEvent; } void TimingStateMachine::nextBenchmark() { fLoops = 1; fInnerState = kTuning_InnerState; fState = kPreWarm_State; }