1 /*
2  * Copyright 2015 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "TimingStateMachine.h"
9 
10 #include "SkCanvas.h"
11 #include "SkCommandLineFlags.h"
12 
13 DEFINE_int32(gpuFrameLag, 5, "Overestimate of maximum number of frames GPU is allowed to lag.");
14 DEFINE_int32(frames, 5, "Number of frames of each skp to render per sample.");
15 DEFINE_double(loopMs, 5, "Each benchmark will be tuned until it takes loopsMs millseconds.");
16 
now_ms()17 static double now_ms() { return SkTime::GetNSecs() * 1e-6; }
18 
TimingStateMachine()19 TimingStateMachine::TimingStateMachine()
20     : fCurrentFrame(0)
21     , fLoops(1)
22     , fLastMeasurement(0.)
23     , fState(kPreWarm_State)
24     , fInnerState(kTuning_InnerState) {
25 }
26 
nextFrame(bool preWarmBetweenSamples)27 TimingStateMachine::ParentEvents TimingStateMachine::nextFrame(bool preWarmBetweenSamples) {
28     ParentEvents parentEvent = kTiming_ParentEvents;
29     switch (fState) {
30         case kPreWarm_State: {
31             if (fCurrentFrame >= FLAGS_gpuFrameLag) {
32                 fCurrentFrame = 0;
33                 fStartTime = now_ms();
34                 fState = kTiming_State;
35             } else {
36                 fCurrentFrame++;
37             }
38             break;
39         }
40         case kTiming_State: {
41             switch (fInnerState) {
42                 case kTuning_InnerState: {
43                     if (1 << 30 == fLoops) {
44                         // We're about to wrap.  Something's wrong with the bench.
45                         SkDebugf("InnerLoops wrapped\n");
46                         fLoops = 1;
47                     } else {
48                         double elapsedMs = now_ms() - fStartTime;
49                         if (elapsedMs < FLAGS_loopMs) {
50                             fLoops *= 2;
51                         } else {
52                             fInnerState = kTiming_InnerState;
53                         }
54                         fState = kPreWarm_State;
55                         fCurrentFrame = 0;
56                         parentEvent = kReset_ParentEvents;
57                     }
58                     break;
59                 }
60                 case kTiming_InnerState: {
61                     if (fCurrentFrame >= FLAGS_frames) {
62                         double now = now_ms();
63                         fLastMeasurement = (now - fStartTime) / (FLAGS_frames * fLoops);
64                         fCurrentFrame = 0;
65                         parentEvent = kTimingFinished_ParentEvents;
66                         if (preWarmBetweenSamples) {
67                             fState = kPreWarm_State;
68                         } else {
69                             fStartTime = now;
70                         }
71                     } else {
72                         fCurrentFrame++;
73                     }
74                     break;
75                 }
76             }
77         }
78         break;
79     }
80     return parentEvent;
81 }
82 
nextBenchmark()83 void TimingStateMachine::nextBenchmark() {
84     fLoops = 1;
85     fInnerState = kTuning_InnerState;
86     fState = kPreWarm_State;
87 }
88