OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "TimingStateMachine.h" | 8 #include "TimingStateMachine.h" |
9 | 9 |
10 #include "SkCanvas.h" | 10 #include "SkCanvas.h" |
11 #include "SkCommandLineFlags.h" | 11 #include "SkCommandLineFlags.h" |
12 | 12 |
13 DEFINE_int32(gpuFrameLag, 5, "Overestimate of maximum number of frames GPU is al
lowed to lag."); | 13 DEFINE_int32(gpuFrameLag, 5, "Overestimate of maximum number of frames GPU is al
lowed to lag."); |
14 DEFINE_int32(frames, 5, "Number of frames of each skp to render per sample."); | 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 mi
llseconds."); | 15 DEFINE_double(loopMs, 5, "Each benchmark will be tuned until it takes loopsMs mi
llseconds."); |
16 | 16 |
17 TimingStateMachine::TimingStateMachine() | 17 TimingStateMachine::TimingStateMachine() |
18 : fCurrentFrame(0) | 18 : fCurrentFrame(0) |
19 , fLoops(1) | 19 , fLoops(1) |
20 , fLastMeasurement(0.) | 20 , fLastMeasurement(0.) |
21 , fState(kPreWarmLoopsPerCanvasPreDraw_State) { | 21 , fState(kPreWarm_State) |
| 22 , fInnerState(kTuning_InnerState) { |
22 } | 23 } |
23 | 24 |
24 TimingStateMachine::ParentEvents TimingStateMachine::nextFrame(SkCanvas* canvas, | 25 TimingStateMachine::ParentEvents TimingStateMachine::nextFrame(bool preWarmBetwe
enSamples) { |
25 Benchmark* benchm
ark) { | 26 ParentEvents parentEvent = kTiming_ParentEvents; |
26 switch (fState) { | 27 switch (fState) { |
27 case kPreWarmLoopsPerCanvasPreDraw_State: | 28 case kPreWarm_State: { |
28 return this->perCanvasPreDraw(canvas, benchmark, kPreWarmLoops_State
); | 29 if (fCurrentFrame >= FLAGS_gpuFrameLag) { |
29 case kPreWarmLoops_State: | 30 fCurrentFrame = 0; |
30 return this->preWarm(kTuneLoops_State); | 31 fTimer.start(); |
31 case kTuneLoops_State: | 32 fState = kTiming_State; |
32 return this->tuneLoops(); | 33 } else { |
33 case kPreWarmTimingPerCanvasPreDraw_State: | 34 fCurrentFrame++; |
34 return this->perCanvasPreDraw(canvas, benchmark, kPreWarmTiming_Stat
e); | 35 } |
35 case kPreWarmTiming_State: | 36 break; |
36 return this->preWarm(kTiming_State); | 37 } |
37 case kTiming_State: | 38 case kTiming_State: { |
38 return this->timing(canvas, benchmark); | 39 switch (fInnerState) { |
| 40 case kTuning_InnerState: { |
| 41 if (1 << 30 == fLoops) { |
| 42 // We're about to wrap. Something's wrong with the benc
h. |
| 43 SkDebugf("InnerLoops wrapped\n"); |
| 44 fLoops = 1; |
| 45 } else { |
| 46 double elapsedMs = this->elapsed(); |
| 47 if (elapsedMs < FLAGS_loopMs) { |
| 48 fLoops *= 2; |
| 49 } else { |
| 50 fInnerState = kTiming_InnerState; |
| 51 fState = kPreWarm_State; |
| 52 } |
| 53 this->resetTimingState(); |
| 54 parentEvent = kReset_ParentEvents; |
| 55 } |
| 56 break; |
| 57 } |
| 58 case kTiming_InnerState: { |
| 59 if (fCurrentFrame >= FLAGS_frames) { |
| 60 this->recordMeasurement(); |
| 61 this->resetTimingState(); |
| 62 parentEvent = kTimingFinished_ParentEvents; |
| 63 if (preWarmBetweenSamples) { |
| 64 fState = kPreWarm_State; |
| 65 } else { |
| 66 fTimer.start(); // start timing again, don't change
state |
| 67 } |
| 68 } else { |
| 69 fCurrentFrame++; |
| 70 } |
| 71 break; |
| 72 } |
| 73 } |
| 74 } |
| 75 break; |
39 } | 76 } |
40 SkFAIL("Incomplete switch\n"); | 77 return parentEvent; |
41 return kTiming_ParentEvents; | |
42 } | |
43 | |
44 inline void TimingStateMachine::nextState(State nextState) { | |
45 fState = nextState; | |
46 } | |
47 | |
48 TimingStateMachine::ParentEvents TimingStateMachine::perCanvasPreDraw(SkCanvas*
canvas, | |
49 Benchmark*
benchmark, | |
50 State next
State) { | |
51 benchmark->perCanvasPreDraw(canvas); | |
52 benchmark->preDraw(canvas); | |
53 fCurrentFrame = 0; | |
54 this->nextState(nextState); | |
55 return kTiming_ParentEvents; | |
56 } | |
57 | |
58 TimingStateMachine::ParentEvents TimingStateMachine::preWarm(State nextState) { | |
59 if (fCurrentFrame >= FLAGS_gpuFrameLag) { | |
60 // we currently time across all frames to make sure we capture all GPU w
ork | |
61 this->nextState(nextState); | |
62 fCurrentFrame = 0; | |
63 fTimer.start(); | |
64 } else { | |
65 fCurrentFrame++; | |
66 } | |
67 return kTiming_ParentEvents; | |
68 } | 78 } |
69 | 79 |
70 inline double TimingStateMachine::elapsed() { | 80 inline double TimingStateMachine::elapsed() { |
71 fTimer.end(); | 81 fTimer.end(); |
72 return fTimer.fWall; | 82 return fTimer.fWall; |
73 } | 83 } |
74 | 84 |
75 void TimingStateMachine::resetTimingState() { | 85 void TimingStateMachine::resetTimingState() { |
76 fCurrentFrame = 0; | 86 fCurrentFrame = 0; |
77 fTimer = WallTimer(); | 87 fTimer = WallTimer(); |
78 } | 88 } |
79 | 89 |
80 inline TimingStateMachine::ParentEvents TimingStateMachine::tuneLoops() { | |
81 if (1 << 30 == fLoops) { | |
82 // We're about to wrap. Something's wrong with the bench. | |
83 SkDebugf("InnerLoops wrapped\n"); | |
84 fLoops = 1; | |
85 return kTiming_ParentEvents; | |
86 } else { | |
87 double elapsedMs = this->elapsed(); | |
88 if (elapsedMs > FLAGS_loopMs) { | |
89 this->nextState(kPreWarmTimingPerCanvasPreDraw_State); | |
90 } else { | |
91 fLoops *= 2; | |
92 this->nextState(kPreWarmLoops_State); | |
93 } | |
94 this->resetTimingState(); | |
95 return kReset_ParentEvents; | |
96 } | |
97 } | |
98 | |
99 void TimingStateMachine::recordMeasurement() { | 90 void TimingStateMachine::recordMeasurement() { |
100 fLastMeasurement = this->elapsed() / (FLAGS_frames * fLoops); | 91 fLastMeasurement = this->elapsed() / (FLAGS_frames * fLoops); |
101 } | 92 } |
102 | 93 |
103 inline TimingStateMachine::ParentEvents TimingStateMachine::timing(SkCanvas* can
vas, | |
104 Benchmark* be
nchmark) { | |
105 if (fCurrentFrame >= FLAGS_frames) { | |
106 this->recordMeasurement(); | |
107 this->resetTimingState(); | |
108 return kTimingFinished_ParentEvents; | |
109 } else { | |
110 fCurrentFrame++; | |
111 return kTiming_ParentEvents; | |
112 } | |
113 } | |
114 | |
115 void TimingStateMachine::nextBenchmark(SkCanvas* canvas, Benchmark* benchmark) { | 94 void TimingStateMachine::nextBenchmark(SkCanvas* canvas, Benchmark* benchmark) { |
116 benchmark->postDraw(canvas); | 95 benchmark->postDraw(canvas); |
117 benchmark->perCanvasPostDraw(canvas); | 96 benchmark->perCanvasPostDraw(canvas); |
118 fLoops = 1; | 97 fLoops = 1; |
119 this->nextState(kPreWarmLoopsPerCanvasPreDraw_State); | 98 fInnerState = kTuning_InnerState; |
| 99 fState = kPreWarm_State; |
120 } | 100 } |
121 | |
122 void TimingStateMachine::nextSampleWithPrewarm() { | |
123 this->nextState(kPreWarmTimingPerCanvasPreDraw_State); | |
124 } | |
125 | |
126 void TimingStateMachine::nextSample() { | |
127 fTimer.start(); | |
128 } | |
OLD | NEW |