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 | 8 |
9 #include "VisualBench.h" | 9 #include "VisualBench.h" |
10 | 10 |
11 #include "ProcStats.h" | 11 #include "ProcStats.h" |
12 #include "SkApplication.h" | 12 #include "SkApplication.h" |
13 #include "SkCanvas.h" | 13 #include "SkCanvas.h" |
14 #include "SkCommandLineFlags.h" | 14 #include "SkCommandLineFlags.h" |
15 #include "SkCommonFlags.h" | 15 #include "SkCommonFlags.h" |
16 #include "SkForceLinking.h" | 16 #include "SkForceLinking.h" |
17 #include "SkGraphics.h" | 17 #include "SkGraphics.h" |
18 #include "SkGr.h" | 18 #include "SkGr.h" |
19 #include "SkImageDecoder.h" | 19 #include "SkImageDecoder.h" |
20 #include "SkOSFile.h" | 20 #include "SkOSFile.h" |
21 #include "SkStream.h" | 21 #include "SkStream.h" |
22 #include "Stats.h" | 22 #include "Stats.h" |
23 #include "gl/GrGLInterface.h" | 23 #include "gl/GrGLInterface.h" |
24 | 24 |
25 __SK_FORCE_IMAGE_DECODER_LINKING; | 25 __SK_FORCE_IMAGE_DECODER_LINKING; |
26 | 26 |
| 27 // Between samples we reset context |
| 28 // Between frames we swap buffers |
| 29 // Between flushes we call flush on GrContext |
| 30 |
27 DEFINE_int32(gpuFrameLag, 5, "Overestimate of maximum number of frames GPU allow
s to lag."); | 31 DEFINE_int32(gpuFrameLag, 5, "Overestimate of maximum number of frames GPU allow
s to lag."); |
28 DEFINE_int32(samples, 10, "Number of times to render each skp."); | 32 DEFINE_int32(samples, 10, "Number of times to time each skp."); |
29 DEFINE_int32(loops, 5, "Number of times to time."); | 33 DEFINE_int32(frames, 5, "Number of frames of each skp to render per sample."); |
| 34 DEFINE_double(flushMs, 20, "Target flush time in millseconds."); |
| 35 DEFINE_double(loopMs, 5, "Target loop time in millseconds."); |
30 DEFINE_int32(msaa, 0, "Number of msaa samples."); | 36 DEFINE_int32(msaa, 0, "Number of msaa samples."); |
31 DEFINE_bool2(fullscreen, f, true, "Run fullscreen."); | 37 DEFINE_bool2(fullscreen, f, true, "Run fullscreen."); |
32 | 38 |
33 static SkString humanize(double ms) { | 39 static SkString humanize(double ms) { |
34 if (FLAGS_verbose) { | 40 if (FLAGS_verbose) { |
35 return SkStringPrintf("%llu", (uint64_t)(ms*1e6)); | 41 return SkStringPrintf("%llu", (uint64_t)(ms*1e6)); |
36 } | 42 } |
37 return HumanizeMs(ms); | 43 return HumanizeMs(ms); |
38 } | 44 } |
39 | 45 |
40 #define HUMANIZE(time) humanize(time).c_str() | 46 #define HUMANIZE(time) humanize(time).c_str() |
41 | 47 |
42 VisualBench::VisualBench(void* hwnd, int argc, char** argv) | 48 VisualBench::VisualBench(void* hwnd, int argc, char** argv) |
43 : INHERITED(hwnd) | 49 : INHERITED(hwnd) |
44 , fLoop(0) | |
45 , fCurrentPictureIdx(-1) | 50 , fCurrentPictureIdx(-1) |
46 , fCurrentSample(0) | 51 , fCurrentSample(0) |
47 , fState(kPreWarm_State) { | 52 , fCurrentFrame(0) |
| 53 , fFlushes(1) |
| 54 , fLoops(1) |
| 55 , fState(kPreWarmLoops_State) { |
48 SkCommandLineFlags::Parse(argc, argv); | 56 SkCommandLineFlags::Parse(argc, argv); |
49 | 57 |
50 // read all the skp file names. | 58 // read all the skp file names. |
51 for (int i = 0; i < FLAGS_skps.count(); i++) { | 59 for (int i = 0; i < FLAGS_skps.count(); i++) { |
52 if (SkStrEndsWith(FLAGS_skps[i], ".skp")) { | 60 if (SkStrEndsWith(FLAGS_skps[i], ".skp")) { |
53 fRecords.push_back().fFilename = FLAGS_skps[i]; | 61 fRecords.push_back().fFilename = FLAGS_skps[i]; |
54 } else { | 62 } else { |
55 SkOSFile::Iter it(FLAGS_skps[i], ".skp"); | 63 SkOSFile::Iter it(FLAGS_skps[i], ".skp"); |
56 SkString path; | 64 SkString path; |
57 while (it.next(&path)) { | 65 while (it.next(&path)) { |
58 fRecords.push_back().fFilename = SkOSPath::Join(FLAGS_skps[i], p
ath.c_str());; | 66 fRecords.push_back().fFilename = SkOSPath::Join(FLAGS_skps[i], p
ath.c_str());; |
59 } | 67 } |
60 } | 68 } |
61 } | 69 } |
62 | 70 |
63 if (fRecords.empty()) { | 71 if (fRecords.empty()) { |
64 SkDebugf("no valid skps found\n"); | 72 SkDebugf("no valid skps found\n"); |
65 } | 73 } |
66 | 74 |
67 this->setTitle(); | 75 this->setTitle(); |
68 this->setupBackend(); | 76 this->setupBackend(); |
| 77 |
| 78 // Print header |
| 79 SkDebugf("curr/maxrss\tloops\tflushes\tmin\tmedian\tmean\tmax\tstddev\tbench
\n"); |
69 } | 80 } |
70 | 81 |
71 VisualBench::~VisualBench() { | 82 VisualBench::~VisualBench() { |
72 INHERITED::detach(); | 83 INHERITED::detach(); |
73 } | 84 } |
74 | 85 |
75 void VisualBench::setTitle() { | 86 void VisualBench::setTitle() { |
76 SkString title("VisualBench"); | 87 SkString title("VisualBench"); |
77 INHERITED::setTitle(title.c_str()); | 88 INHERITED::setTitle(title.c_str()); |
78 } | 89 } |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
115 this->setupRenderTarget(); | 126 this->setupRenderTarget(); |
116 } | 127 } |
117 | 128 |
118 void VisualBench::setupRenderTarget() { | 129 void VisualBench::setupRenderTarget() { |
119 if (fContext) { | 130 if (fContext) { |
120 fRenderTarget.reset(this->renderTarget(fAttachmentInfo, fInterface, fCon
text)); | 131 fRenderTarget.reset(this->renderTarget(fAttachmentInfo, fInterface, fCon
text)); |
121 } | 132 } |
122 } | 133 } |
123 | 134 |
124 inline void VisualBench::renderFrame(SkCanvas* canvas) { | 135 inline void VisualBench::renderFrame(SkCanvas* canvas) { |
125 canvas->drawPicture(fPicture); | 136 for (int flush = 0; flush < fFlushes; flush++) { |
126 canvas->flush(); | 137 for (int loop = 0; loop < fLoops; loop++) { |
| 138 canvas->drawPicture(fPicture); |
| 139 } |
| 140 canvas->flush(); |
| 141 } |
127 INHERITED::present(); | 142 INHERITED::present(); |
128 } | 143 } |
129 | 144 |
130 void VisualBench::printStats() { | 145 void VisualBench::printStats() { |
131 const SkTArray<double>& measurements = fRecords[fCurrentPictureIdx].fMeasure
ments; | 146 const SkTArray<double>& measurements = fRecords[fCurrentPictureIdx].fMeasure
ments; |
132 SkString shortName = SkOSPath::Basename(fRecords[fCurrentPictureIdx].fFilena
me.c_str()); | 147 SkString shortName = SkOSPath::Basename(fRecords[fCurrentPictureIdx].fFilena
me.c_str()); |
133 if (FLAGS_verbose) { | 148 if (FLAGS_verbose) { |
134 for (int i = 0; i < measurements.count(); i++) { | 149 for (int i = 0; i < measurements.count(); i++) { |
135 SkDebugf("%s ", HUMANIZE(measurements[i])); | 150 SkDebugf("%s ", HUMANIZE(measurements[i])); |
136 } | 151 } |
137 SkDebugf("%s\n", shortName.c_str()); | 152 SkDebugf("%s\n", shortName.c_str()); |
138 } else { | 153 } else { |
139 SkASSERT(measurements.count()); | 154 SkASSERT(measurements.count()); |
140 Stats stats(measurements.begin(), measurements.count()); | 155 Stats stats(measurements.begin(), measurements.count()); |
141 const double stdDevPercent = 100 * sqrt(stats.var) / stats.mean; | 156 const double stdDevPercent = 100 * sqrt(stats.var) / stats.mean; |
142 SkDebugf("%4d/%-4dMB\t%s\t%s\t%s\t%s\t%.0f%%\t%s\n", | 157 SkDebugf("%4d/%-4dMB\t%d\t%d\t%s\t%s\t%s\t%s\t%.0f%%\t%s\n", |
143 sk_tools::getCurrResidentSetSizeMB(), | 158 sk_tools::getCurrResidentSetSizeMB(), |
144 sk_tools::getMaxResidentSetSizeMB(), | 159 sk_tools::getMaxResidentSetSizeMB(), |
| 160 fLoops, |
| 161 fFlushes, |
145 HUMANIZE(stats.min), | 162 HUMANIZE(stats.min), |
146 HUMANIZE(stats.median), | 163 HUMANIZE(stats.median), |
147 HUMANIZE(stats.mean), | 164 HUMANIZE(stats.mean), |
148 HUMANIZE(stats.max), | 165 HUMANIZE(stats.max), |
149 stdDevPercent, | 166 stdDevPercent, |
150 shortName.c_str()); | 167 shortName.c_str()); |
151 } | 168 } |
152 } | 169 } |
153 | 170 |
154 bool VisualBench::advanceRecordIfNecessary() { | 171 bool VisualBench::advanceRecordIfNecessary() { |
(...skipping 18 matching lines...) Expand all Loading... |
173 if (stream.isValid()) { | 190 if (stream.isValid()) { |
174 fPicture.reset(SkPicture::CreateFromStream(&stream)); | 191 fPicture.reset(SkPicture::CreateFromStream(&stream)); |
175 if (SkToBool(fPicture)) { | 192 if (SkToBool(fPicture)) { |
176 return true; | 193 return true; |
177 } | 194 } |
178 } | 195 } |
179 SkDebugf("couldn't load picture at \"%s\"\n", fileName); | 196 SkDebugf("couldn't load picture at \"%s\"\n", fileName); |
180 return false; | 197 return false; |
181 } | 198 } |
182 | 199 |
| 200 void VisualBench::preWarm(State nextState) { |
| 201 if (fCurrentFrame >= FLAGS_gpuFrameLag) { |
| 202 // we currently time across all frames to make sure we capture all GPU w
ork |
| 203 fState = nextState; |
| 204 fCurrentFrame = 0; |
| 205 fTimer.start(); |
| 206 } else { |
| 207 fCurrentFrame++; |
| 208 } |
| 209 } |
| 210 |
183 void VisualBench::draw(SkCanvas* canvas) { | 211 void VisualBench::draw(SkCanvas* canvas) { |
184 if (!this->advanceRecordIfNecessary()) { | 212 if (!this->advanceRecordIfNecessary()) { |
185 this->closeWindow(); | 213 this->closeWindow(); |
186 return; | 214 return; |
187 } | 215 } |
188 this->renderFrame(canvas); | 216 this->renderFrame(canvas); |
189 switch (fState) { | 217 switch (fState) { |
190 case kPreWarm_State: { | 218 case kPreWarmLoops_State: { |
191 if (fCurrentSample >= FLAGS_gpuFrameLag) { | 219 this->preWarm(kTuneLoops_State); |
192 // TODO we currently time across all frames to make sure we capt
ure all GPU work | 220 break; |
193 // We should also rendering an empty SKP to get a baseline to su
btract from | 221 } |
194 // our timing | 222 case kTuneLoops_State: { |
195 fState = kTiming_State; | 223 if (1 << 30 == fLoops) { |
196 fCurrentSample -= FLAGS_gpuFrameLag; | 224 // We're about to wrap. Something's wrong with the bench. |
197 fTimer.start(); | 225 SkDebugf("InnerLoops wrapped\n"); |
| 226 fLoops = 0; |
198 } else { | 227 } else { |
199 fCurrentSample++; | 228 fTimer.end(); |
| 229 double elapsed = fTimer.fWall; |
| 230 if (elapsed > FLAGS_loopMs) { |
| 231 fState = kPreWarmTiming_State; |
| 232 |
| 233 // Scale back the number of loops |
| 234 fLoops = (int)ceil(fLoops * FLAGS_loopMs / elapsed); |
| 235 fFlushes = (int)ceil(FLAGS_flushMs / elapsed); |
| 236 } else { |
| 237 fState = kPreWarmLoops_State; |
| 238 fLoops *= 2; |
| 239 } |
| 240 |
| 241 fCurrentFrame = 0; |
| 242 fTimer = WallTimer(); |
| 243 this->resetContext(); |
200 } | 244 } |
201 break; | 245 break; |
202 } | 246 } |
| 247 case kPreWarmTiming_State: { |
| 248 this->preWarm(kTiming_State); |
| 249 break; |
| 250 } |
203 case kTiming_State: { | 251 case kTiming_State: { |
204 if (fCurrentSample >= FLAGS_samples) { | 252 if (fCurrentFrame >= FLAGS_frames) { |
205 fTimer.end(); | 253 fTimer.end(); |
206 fRecords[fCurrentPictureIdx].fMeasurements.push_back(fTimer.fWal
l / FLAGS_samples); | 254 fRecords[fCurrentPictureIdx].fMeasurements.push_back( |
207 this->resetContext(); | 255 fTimer.fWall / (FLAGS_frames * fLoops * fFlushes)); |
208 fTimer = WallTimer(); | 256 if (fCurrentSample++ >= FLAGS_samples) { |
209 fState = kPreWarm_State; | 257 fState = kPreWarmLoops_State; |
210 fCurrentSample = 0; | |
211 if (fLoop++ > FLAGS_loops) { | |
212 this->printStats(); | 258 this->printStats(); |
213 fPicture.reset(NULL); | 259 fPicture.reset(NULL); |
214 fLoop = 0; | 260 fCurrentSample = 0; |
| 261 fFlushes = 1; |
| 262 fLoops = 1; |
| 263 } else { |
| 264 fState = kPreWarmTiming_State; |
215 } | 265 } |
| 266 fTimer = WallTimer(); |
| 267 this->resetContext(); |
| 268 fCurrentFrame = 0; |
216 } else { | 269 } else { |
217 fCurrentSample++; | 270 fCurrentFrame++; |
218 } | 271 } |
219 break; | 272 break; |
220 } | 273 } |
221 } | 274 } |
222 | 275 |
223 // Invalidate the window to force a redraw. Poor man's animation mechanism. | 276 // Invalidate the window to force a redraw. Poor man's animation mechanism. |
224 this->inval(NULL); | 277 this->inval(NULL); |
225 } | 278 } |
226 | 279 |
227 void VisualBench::onSizeChange() { | 280 void VisualBench::onSizeChange() { |
(...skipping 12 matching lines...) Expand all Loading... |
240 | 293 |
241 void application_term() { | 294 void application_term() { |
242 SkEvent::Term(); | 295 SkEvent::Term(); |
243 SkGraphics::Term(); | 296 SkGraphics::Term(); |
244 } | 297 } |
245 | 298 |
246 SkOSWindow* create_sk_window(void* hwnd, int argc, char** argv) { | 299 SkOSWindow* create_sk_window(void* hwnd, int argc, char** argv) { |
247 return new VisualBench(hwnd, argc, argv); | 300 return new VisualBench(hwnd, argc, argv); |
248 } | 301 } |
249 | 302 |
OLD | NEW |