add autotuning to visualbench

BUG=skia:

Review URL: https://codereview.chromium.org/1201003002
This commit is contained in:
joshualitt 2015-06-23 07:10:59 -07:00 committed by Commit bot
parent 5351aad9bc
commit 6205af0e70
2 changed files with 85 additions and 27 deletions

View File

@ -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;
}

View File

@ -54,14 +54,19 @@ private:
};
enum State {
kPreWarm_State,
kPreWarmLoops_State,
kTuneLoops_State,
kPreWarmTiming_State,
kTiming_State,
};
void preWarm(State nextState);
int fLoop;
int fCurrentPictureIdx;
SkAutoTUnref<SkPicture> fPicture;
int fCurrentSample;
int fCurrentFrame;
int fFlushes;
int fLoops;
SkTArray<Record> fRecords;
WallTimer fTimer;
State fState;