blob: d7e4cf4a77a409e7cef1b028efa91df94d81ccef [file] [log] [blame]
joshualitt98d2e2f2015-10-05 07:23:30 -07001/*
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
13DEFINE_int32(gpuFrameLag, 5, "Overestimate of maximum number of frames GPU is allowed to lag.");
14DEFINE_int32(frames, 5, "Number of frames of each skp to render per sample.");
15DEFINE_double(loopMs, 5, "Each benchmark will be tuned until it takes loopsMs millseconds.");
16
17TimingStateMachine::TimingStateMachine()
18 : fCurrentFrame(0)
19 , fLoops(1)
20 , fLastMeasurement(0.)
21 , fState(kPreWarmLoopsPerCanvasPreDraw_State) {
22}
23
24TimingStateMachine::ParentEvents TimingStateMachine::nextFrame(SkCanvas* canvas,
25 Benchmark* benchmark) {
26 switch (fState) {
27 case kPreWarmLoopsPerCanvasPreDraw_State:
28 return this->perCanvasPreDraw(canvas, benchmark, kPreWarmLoops_State);
29 case kPreWarmLoops_State:
30 return this->preWarm(kTuneLoops_State);
31 case kTuneLoops_State:
32 return this->tuneLoops();
33 case kPreWarmTimingPerCanvasPreDraw_State:
34 return this->perCanvasPreDraw(canvas, benchmark, kPreWarmTiming_State);
35 case kPreWarmTiming_State:
36 return this->preWarm(kTiming_State);
37 case kTiming_State:
38 return this->timing(canvas, benchmark);
39 }
40 SkFAIL("Incomplete switch\n");
41 return kTiming_ParentEvents;
42}
43
44inline void TimingStateMachine::nextState(State nextState) {
45 fState = nextState;
46}
47
48TimingStateMachine::ParentEvents TimingStateMachine::perCanvasPreDraw(SkCanvas* canvas,
49 Benchmark* benchmark,
50 State nextState) {
51 benchmark->perCanvasPreDraw(canvas);
52 benchmark->preDraw(canvas);
53 fCurrentFrame = 0;
54 this->nextState(nextState);
55 return kTiming_ParentEvents;
56}
57
58TimingStateMachine::ParentEvents TimingStateMachine::preWarm(State nextState) {
59 if (fCurrentFrame >= FLAGS_gpuFrameLag) {
60 // we currently time across all frames to make sure we capture all GPU work
61 this->nextState(nextState);
62 fCurrentFrame = 0;
63 fTimer.start();
64 } else {
65 fCurrentFrame++;
66 }
67 return kTiming_ParentEvents;
68}
69
70inline double TimingStateMachine::elapsed() {
71 fTimer.end();
72 return fTimer.fWall;
73}
74
75void TimingStateMachine::resetTimingState() {
76 fCurrentFrame = 0;
77 fTimer = WallTimer();
78}
79
80inline 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
99void TimingStateMachine::recordMeasurement() {
100 fLastMeasurement = this->elapsed() / (FLAGS_frames * fLoops);
101}
102
joshualitt98d2e2f2015-10-05 07:23:30 -0700103inline TimingStateMachine::ParentEvents TimingStateMachine::timing(SkCanvas* canvas,
104 Benchmark* benchmark) {
105 if (fCurrentFrame >= FLAGS_frames) {
106 this->recordMeasurement();
107 this->resetTimingState();
joshualitt98d2e2f2015-10-05 07:23:30 -0700108 return kTimingFinished_ParentEvents;
109 } else {
110 fCurrentFrame++;
111 return kTiming_ParentEvents;
112 }
113}
114
joshualittdc5db592015-10-05 13:24:55 -0700115void TimingStateMachine::nextBenchmark(SkCanvas* canvas, Benchmark* benchmark) {
116 benchmark->postDraw(canvas);
117 benchmark->perCanvasPostDraw(canvas);
118 fLoops = 1;
119 this->nextState(kPreWarmLoopsPerCanvasPreDraw_State);
120}
121
122void TimingStateMachine::nextSampleWithPrewarm() {
123 this->nextState(kPreWarmTimingPerCanvasPreDraw_State);
124}
125
126void TimingStateMachine::nextSample() {
127 fTimer.start();
128}