blob: 5ec1313b1f65bf98f5998f487ad3240ed27493ea [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
9#ifndef TimingStateMachine_DEFINED
10#define TimingStateMachine_DEFINED
11
12#include "Benchmark.h"
13#include "SkTArray.h"
14#include "Timer.h"
15
16class SkCanvas;
17
18/*
19 * Manages a timer via a state machine. Can be used by modules to time benchmarks
20 *
21 * Clients call nextFrame, and must handle any requests from the timing state machine, specifically
22 * to reset. When kTimingFinished_ParentEvents is returned, then lastMeasurement() will return the
23 * timing and loops() will return the number of loops used to time.
24 *
25 * A client may continue timing the same benchmark indefinitely. To advance to the next
26 * benchmark, the client should call nextBenchmark.
27 */
28class TimingStateMachine {
29public:
30 TimingStateMachine();
31
32 enum ParentEvents {
33 kReset_ParentEvents,
34 kTiming_ParentEvents,
35 kTimingFinished_ParentEvents,// This implies parent can read lastMeasurement() and must
36 // reset
37 };
38
39 ParentEvents nextFrame(SkCanvas* canvas, Benchmark* benchmark);
40
41 /*
joshualittdc5db592015-10-05 13:24:55 -070042 * Before taking another sample, the owner can choose to prewarm or not
43 */
44 void nextSampleWithPrewarm();
45 void nextSample();
46
47 /*
joshualitt98d2e2f2015-10-05 07:23:30 -070048 * The caller should call this when they are ready to move to the next benchmark. The caller
49 * must call this with the *last* benchmark so post draw hooks can be invoked
50 */
51 void nextBenchmark(SkCanvas*, Benchmark*);
52
53
54 /*
55 * When TimingStateMachine returns kTimingFinished_ParentEvents, then the owner can call
56 * lastMeasurement() to get the time
57 */
58 double lastMeasurement() const { return fLastMeasurement; }
59
60 int loops() const { return fLoops; }
61
62private:
63 /*
64 * The heart of the timing state machine is an event driven timing loop.
65 * kPreWarmLoopsPerCanvasPreDraw_State: Before we begin timing, Benchmarks have a hook to
66 * access the canvas. Then we prewarm before the autotune
67 * loops step.
68 * kPreWarmLoops_State: We prewarm the gpu before auto tuning to enter a steady
69 * work state
70 * kTuneLoops_State: Then we tune the loops of the benchmark to ensure we
71 * are doing a measurable amount of work
72 * kPreWarmTimingPerCanvasPreDraw_State: Because reset the context after tuning loops to ensure
73 * coherent state, we need to give the benchmark
74 * another hook
75 * kPreWarmTiming_State: We prewarm the gpu again to enter a steady state
76 * kTiming_State: Finally we time the benchmark. When finished timing
77 * if we have enough samples then we'll start the next
78 * benchmark in the kPreWarmLoopsPerCanvasPreDraw_State.
79 * otherwise, we enter the
80 * kPreWarmTimingPerCanvasPreDraw_State for another sample
81 * In either case we reset the context.
82 */
83 enum State {
84 kPreWarmLoopsPerCanvasPreDraw_State,
85 kPreWarmLoops_State,
86 kTuneLoops_State,
87 kPreWarmTimingPerCanvasPreDraw_State,
88 kPreWarmTiming_State,
89 kTiming_State,
90 };
91
92 inline void nextState(State);
93 ParentEvents perCanvasPreDraw(SkCanvas*, Benchmark*, State);
94 ParentEvents preWarm(State nextState);
95 inline ParentEvents tuneLoops();
96 inline ParentEvents timing(SkCanvas*, Benchmark*);
97 inline double elapsed();
98 void resetTimingState();
99 void postDraw(SkCanvas*, Benchmark*);
100 void recordMeasurement();
101
102 int fCurrentFrame;
103 int fLoops;
104 double fLastMeasurement;
105 WallTimer fTimer;
106 State fState;
107};
108
109#endif