Index: tools/VisualBench.cpp |
diff --git a/tools/VisualBench.cpp b/tools/VisualBench.cpp |
index 60174a435c765e51ca183dc615418bef157aa22b..cbc89945924833633aa57c17200029c15fa06f91 100644 |
--- a/tools/VisualBench.cpp |
+++ b/tools/VisualBench.cpp |
@@ -24,9 +24,15 @@ |
__SK_FORCE_IMAGE_DECODER_LINKING; |
+// Between samples we reset context |
+// Between frames we swap buffers |
+// Between flushes we call flush on GrContext |
+ |
DEFINE_int32(gpuFrameLag, 5, "Overestimate of maximum number of frames GPU allows to lag."); |
-DEFINE_int32(samples, 10, "Number of times to render each skp."); |
-DEFINE_int32(loops, 5, "Number of times to time."); |
+DEFINE_int32(samples, 10, "Number of times to time each skp."); |
+DEFINE_int32(frames, 5, "Number of frames of each skp to render per sample."); |
+DEFINE_double(flushMs, 20, "Target flush time in millseconds."); |
+DEFINE_double(loopMs, 5, "Target loop time in millseconds."); |
DEFINE_int32(msaa, 0, "Number of msaa samples."); |
DEFINE_bool2(fullscreen, f, true, "Run fullscreen."); |
@@ -41,10 +47,12 @@ static SkString humanize(double ms) { |
VisualBench::VisualBench(void* hwnd, int argc, char** argv) |
: INHERITED(hwnd) |
- , fLoop(0) |
, fCurrentPictureIdx(-1) |
, fCurrentSample(0) |
- , fState(kPreWarm_State) { |
+ , fCurrentFrame(0) |
+ , fFlushes(1) |
+ , fLoops(1) |
+ , fState(kPreWarmLoops_State) { |
SkCommandLineFlags::Parse(argc, argv); |
// read all the skp file names. |
@@ -66,6 +74,9 @@ VisualBench::VisualBench(void* hwnd, int argc, char** argv) |
this->setTitle(); |
this->setupBackend(); |
+ |
+ // Print header |
+ SkDebugf("curr/maxrss\tloops\tflushes\tmin\tmedian\tmean\tmax\tstddev\tbench\n"); |
} |
VisualBench::~VisualBench() { |
@@ -122,8 +133,12 @@ void VisualBench::setupRenderTarget() { |
} |
inline void VisualBench::renderFrame(SkCanvas* canvas) { |
- canvas->drawPicture(fPicture); |
- canvas->flush(); |
+ for (int flush = 0; flush < fFlushes; flush++) { |
+ for (int loop = 0; loop < fLoops; loop++) { |
+ canvas->drawPicture(fPicture); |
+ } |
+ canvas->flush(); |
+ } |
INHERITED::present(); |
} |
@@ -139,9 +154,11 @@ void VisualBench::printStats() { |
SkASSERT(measurements.count()); |
Stats stats(measurements.begin(), measurements.count()); |
const double stdDevPercent = 100 * sqrt(stats.var) / stats.mean; |
- SkDebugf("%4d/%-4dMB\t%s\t%s\t%s\t%s\t%.0f%%\t%s\n", |
+ SkDebugf("%4d/%-4dMB\t%d\t%d\t%s\t%s\t%s\t%s\t%.0f%%\t%s\n", |
sk_tools::getCurrResidentSetSizeMB(), |
sk_tools::getMaxResidentSetSizeMB(), |
+ fLoops, |
+ fFlushes, |
HUMANIZE(stats.min), |
HUMANIZE(stats.median), |
HUMANIZE(stats.mean), |
@@ -180,6 +197,17 @@ bool VisualBench::loadPicture() { |
return false; |
} |
+void VisualBench::preWarm(State nextState) { |
+ if (fCurrentFrame >= FLAGS_gpuFrameLag) { |
+ // we currently time across all frames to make sure we capture all GPU work |
+ fState = nextState; |
+ fCurrentFrame = 0; |
+ fTimer.start(); |
+ } else { |
+ fCurrentFrame++; |
+ } |
+} |
+ |
void VisualBench::draw(SkCanvas* canvas) { |
if (!this->advanceRecordIfNecessary()) { |
this->closeWindow(); |
@@ -187,34 +215,59 @@ void VisualBench::draw(SkCanvas* canvas) { |
} |
this->renderFrame(canvas); |
switch (fState) { |
- case kPreWarm_State: { |
- if (fCurrentSample >= FLAGS_gpuFrameLag) { |
- // TODO we currently time across all frames to make sure we capture all GPU work |
- // We should also rendering an empty SKP to get a baseline to subtract from |
- // our timing |
- fState = kTiming_State; |
- fCurrentSample -= FLAGS_gpuFrameLag; |
- fTimer.start(); |
+ case kPreWarmLoops_State: { |
+ this->preWarm(kTuneLoops_State); |
+ break; |
+ } |
+ case kTuneLoops_State: { |
+ if (1 << 30 == fLoops) { |
+ // We're about to wrap. Something's wrong with the bench. |
+ SkDebugf("InnerLoops wrapped\n"); |
+ fLoops = 0; |
} else { |
- fCurrentSample++; |
+ fTimer.end(); |
+ double elapsed = fTimer.fWall; |
+ if (elapsed > FLAGS_loopMs) { |
+ fState = kPreWarmTiming_State; |
+ |
+ // Scale back the number of loops |
+ fLoops = (int)ceil(fLoops * FLAGS_loopMs / elapsed); |
+ fFlushes = (int)ceil(FLAGS_flushMs / elapsed); |
+ } else { |
+ fState = kPreWarmLoops_State; |
+ fLoops *= 2; |
+ } |
+ |
+ fCurrentFrame = 0; |
+ fTimer = WallTimer(); |
+ this->resetContext(); |
} |
break; |
} |
+ case kPreWarmTiming_State: { |
+ this->preWarm(kTiming_State); |
+ break; |
+ } |
case kTiming_State: { |
- if (fCurrentSample >= FLAGS_samples) { |
+ if (fCurrentFrame >= FLAGS_frames) { |
fTimer.end(); |
- fRecords[fCurrentPictureIdx].fMeasurements.push_back(fTimer.fWall / FLAGS_samples); |
- this->resetContext(); |
- fTimer = WallTimer(); |
- fState = kPreWarm_State; |
- fCurrentSample = 0; |
- if (fLoop++ > FLAGS_loops) { |
+ fRecords[fCurrentPictureIdx].fMeasurements.push_back( |
+ fTimer.fWall / (FLAGS_frames * fLoops * fFlushes)); |
+ if (fCurrentSample++ >= FLAGS_samples) { |
+ fState = kPreWarmLoops_State; |
this->printStats(); |
fPicture.reset(NULL); |
- fLoop = 0; |
+ fCurrentSample = 0; |
+ fFlushes = 1; |
+ fLoops = 1; |
+ } else { |
+ fState = kPreWarmTiming_State; |
} |
+ fTimer = WallTimer(); |
+ this->resetContext(); |
+ fCurrentFrame = 0; |
} else { |
- fCurrentSample++; |
+ fCurrentFrame++; |
} |
break; |
} |