joshualitt | 98d2e2f | 2015-10-05 07:23:30 -0700 | [diff] [blame] | 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 | |
| 9 | #ifndef TimingStateMachine_DEFINED |
| 10 | #define TimingStateMachine_DEFINED |
| 11 | |
| 12 | #include "Benchmark.h" |
| 13 | #include "SkTArray.h" |
| 14 | #include "Timer.h" |
| 15 | |
| 16 | class 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 | */ |
| 28 | class TimingStateMachine { |
| 29 | public: |
| 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 | /* |
joshualitt | dc5db59 | 2015-10-05 13:24:55 -0700 | [diff] [blame^] | 42 | * Before taking another sample, the owner can choose to prewarm or not |
| 43 | */ |
| 44 | void nextSampleWithPrewarm(); |
| 45 | void nextSample(); |
| 46 | |
| 47 | /* |
joshualitt | 98d2e2f | 2015-10-05 07:23:30 -0700 | [diff] [blame] | 48 | * 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 | |
| 62 | private: |
| 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 |