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 |
robertphillips
2015/10/05 18:37:37
Why isn't preWarmBetweenSamples a member variable
| |
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(kTuning_State) |
22 , fInnerState(kPreWarm_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 (fInnerState) { |
27 case kPreWarmLoopsPerCanvasPreDraw_State: | 28 case kPreWarm_InnerState: { |
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(); |
robertphillips
2015/10/05 18:37:37
Why not just set fInnerState to kTiming_InnerState
| |
31 case kTuneLoops_State: | 32 this->nextState(preWarmBetweenSamples); |
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_InnerState: { |
38 return this->timing(canvas, benchmark); | 39 switch (fState) { |
40 case kTuning_State: { | |
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 this->nextState(preWarmBetweenSamples); | |
51 } | |
52 this->resetTimingState(); | |
53 parentEvent = kReset_ParentEvents; | |
54 } | |
55 } | |
56 case kTiming_State: { | |
57 if (fCurrentFrame >= FLAGS_frames) { | |
58 this->recordMeasurement(); | |
59 this->resetTimingState(); | |
60 parentEvent = kTimingFinished_ParentEvents; | |
61 this->nextState(preWarmBetweenSamples); | |
62 } else { | |
63 fCurrentFrame++; | |
64 } | |
65 } | |
66 } | |
67 } | |
39 } | 68 } |
40 SkFAIL("Incomplete switch\n"); | 69 return parentEvent; |
41 return kTiming_ParentEvents; | |
42 } | 70 } |
43 | 71 |
robertphillips
2015/10/05 18:37:37
Would it be cleaner to fold this into nextFrame (n
| |
44 inline void TimingStateMachine::nextState(State nextState) { | 72 inline void TimingStateMachine::nextState(bool preWarmBetweenSamples) { |
45 fState = nextState; | 73 switch (fInnerState) { |
46 } | 74 case kPreWarm_InnerState: { |
47 | 75 fInnerState = kTiming_InnerState; |
48 TimingStateMachine::ParentEvents TimingStateMachine::perCanvasPreDraw(SkCanvas* canvas, | 76 break; |
49 Benchmark* benchmark, | 77 } |
50 State next State) { | 78 case kTiming_InnerState: { |
51 benchmark->perCanvasPreDraw(canvas); | 79 switch (fState) { |
52 benchmark->preDraw(canvas); | 80 case kTuning_State: { |
53 fCurrentFrame = 0; | 81 fState = kTiming_State; |
54 this->nextState(nextState); | 82 fInnerState = kPreWarm_InnerState; |
55 return kTiming_ParentEvents; | 83 break; |
56 } | 84 } |
57 | 85 case kTiming_State: { |
58 TimingStateMachine::ParentEvents TimingStateMachine::preWarm(State nextState) { | 86 if (preWarmBetweenSamples) { |
59 if (fCurrentFrame >= FLAGS_gpuFrameLag) { | 87 fInnerState = kPreWarm_InnerState; |
60 // we currently time across all frames to make sure we capture all GPU w ork | 88 } else { |
61 this->nextState(nextState); | 89 fTimer.start(); // start timing again, don't change stat e |
62 fCurrentFrame = 0; | 90 } |
63 fTimer.start(); | 91 } |
64 } else { | 92 } |
65 fCurrentFrame++; | 93 } |
66 } | 94 } |
67 return kTiming_ParentEvents; | |
68 } | 95 } |
69 | 96 |
70 inline double TimingStateMachine::elapsed() { | 97 inline double TimingStateMachine::elapsed() { |
71 fTimer.end(); | 98 fTimer.end(); |
72 return fTimer.fWall; | 99 return fTimer.fWall; |
73 } | 100 } |
74 | 101 |
75 void TimingStateMachine::resetTimingState() { | 102 void TimingStateMachine::resetTimingState() { |
76 fCurrentFrame = 0; | 103 fCurrentFrame = 0; |
77 fTimer = WallTimer(); | 104 fTimer = WallTimer(); |
78 } | 105 } |
79 | 106 |
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() { | 107 void TimingStateMachine::recordMeasurement() { |
100 fLastMeasurement = this->elapsed() / (FLAGS_frames * fLoops); | 108 fLastMeasurement = this->elapsed() / (FLAGS_frames * fLoops); |
101 } | 109 } |
102 | 110 |
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) { | 111 void TimingStateMachine::nextBenchmark(SkCanvas* canvas, Benchmark* benchmark) { |
116 benchmark->postDraw(canvas); | 112 benchmark->postDraw(canvas); |
117 benchmark->perCanvasPostDraw(canvas); | 113 benchmark->perCanvasPostDraw(canvas); |
118 fLoops = 1; | 114 fLoops = 1; |
119 this->nextState(kPreWarmLoopsPerCanvasPreDraw_State); | 115 fState = kTuning_State; |
116 fInnerState = kPreWarm_InnerState; | |
120 } | 117 } |
121 | |
122 void TimingStateMachine::nextSampleWithPrewarm() { | |
123 this->nextState(kPreWarmTimingPerCanvasPreDraw_State); | |
124 } | |
125 | |
126 void TimingStateMachine::nextSample() { | |
127 fTimer.start(); | |
128 } | |
OLD | NEW |