| 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 |