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