Some cleanups of VisualBench

BUG=skia:

Review URL: https://codereview.chromium.org/1240633005
This commit is contained in:
joshualitt 2015-07-17 09:09:23 -07:00 committed by Commit bot
parent 5150a77ee7
commit a2a6fe8699
2 changed files with 123 additions and 53 deletions

View File

@ -170,15 +170,24 @@ bool VisualBench::advanceRecordIfNecessary(SkCanvas* canvas) {
canvas->clear(0xffffffff);
fBenchmark->preDraw();
fBenchmark->perCanvasPreDraw(canvas);
fRecords.push_back();
return true;
}
inline void VisualBench::nextState(State nextState) {
fState = nextState;
}
void VisualBench::perCanvasPreDraw(SkCanvas* canvas, State nextState) {
fBenchmark->perCanvasPreDraw(canvas);
fCurrentFrame = 0;
this->nextState(nextState);
}
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;
this->nextState(nextState);
fCurrentFrame = 0;
fTimer.start();
} else {
@ -193,33 +202,20 @@ void VisualBench::draw(SkCanvas* canvas) {
}
this->renderFrame(canvas);
switch (fState) {
case kPreWarmLoopsPerCanvasPreDraw_State: {
this->perCanvasPreDraw(canvas, kPreWarmLoops_State);
break;
}
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 {
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();
}
this->tuneLoops();
break;
}
case kPreWarmTimingPerCanvasPreDraw_State: {
this->perCanvasPreDraw(canvas, kPreWarmTiming_State);
break;
}
case kPreWarmTiming_State: {
@ -227,27 +223,7 @@ void VisualBench::draw(SkCanvas* canvas) {
break;
}
case kTiming_State: {
if (fCurrentFrame >= FLAGS_frames) {
fTimer.end();
fRecords.back().fMeasurements.push_back(
fTimer.fWall / (FLAGS_frames * fLoops * fFlushes));
if (fCurrentSample++ >= FLAGS_samples) {
fState = kPreWarmLoops_State;
this->printStats();
fBenchmark->perCanvasPostDraw(canvas);
fBenchmark.reset(NULL);
fCurrentSample = 0;
fFlushes = 1;
fLoops = 1;
} else {
fState = kPreWarmTiming_State;
}
fTimer = WallTimer();
this->resetContext();
fCurrentFrame = 0;
} else {
fCurrentFrame++;
}
this->timing(canvas);
break;
}
}
@ -256,6 +232,70 @@ void VisualBench::draw(SkCanvas* canvas) {
this->inval(NULL);
}
inline double VisualBench::elapsed() {
fTimer.end();
return fTimer.fWall;
}
void VisualBench::resetTimingState() {
fCurrentFrame = 0;
fTimer = WallTimer();
this->resetContext();
}
void VisualBench::scaleLoops(double elapsedMs) {
// Scale back the number of loops
fLoops = (int)ceil(fLoops * FLAGS_loopMs / elapsedMs);
fFlushes = (int)ceil(FLAGS_flushMs / elapsedMs);
}
inline void VisualBench::tuneLoops() {
if (1 << 30 == fLoops) {
// We're about to wrap. Something's wrong with the bench.
SkDebugf("InnerLoops wrapped\n");
fLoops = 0;
} else {
double elapsedMs = this->elapsed();
if (elapsedMs > FLAGS_loopMs) {
this->scaleLoops(elapsedMs);
this->nextState(kPreWarmTimingPerCanvasPreDraw_State);
} else {
fLoops *= 2;
this->nextState(kPreWarmLoops_State);
}
this->resetTimingState();
}
}
void VisualBench::recordMeasurement() {
double measurement = this->elapsed() / (FLAGS_frames * fLoops * fFlushes);
fRecords.back().fMeasurements.push_back(measurement);
}
void VisualBench::postDraw(SkCanvas* canvas) {
fBenchmark->perCanvasPostDraw(canvas);
fBenchmark.reset(NULL);
fCurrentSample = 0;
fFlushes = 1;
fLoops = 1;
}
inline void VisualBench::timing(SkCanvas* canvas) {
if (fCurrentFrame >= FLAGS_frames) {
this->recordMeasurement();
if (fCurrentSample++ >= FLAGS_samples) {
this->printStats();
this->postDraw(canvas);
this->nextState(kPreWarmLoopsPerCanvasPreDraw_State);
} else {
this->nextState(kPreWarmTimingPerCanvasPreDraw_State);
}
this->resetTimingState();
} else {
fCurrentFrame++;
}
}
void VisualBench::onSizeChange() {
this->setupRenderTarget();
}

View File

@ -39,6 +39,34 @@ protected:
void onSizeChange() override;
private:
/*
* The heart of visual bench is an event driven timing loop.
* kPreWarmLoopsPerCanvasPreDraw_State: Before we begin timing, Benchmarks have a hook to
* access the canvas. Then we prewarm before the autotune
* loops step.
* kPreWarmLoops_State: We prewarm the gpu before auto tuning to enter a steady
* work state
* kTuneLoops_State: Then we tune the loops of the benchmark to ensure we
* are doing a measurable amount of work
* kPreWarmTimingPerCanvasPreDraw_State: Because reset the context after tuning loops to ensure
* coherent state, we need to give the benchmark
* another hook
* kPreWarmTiming_State: We prewarm the gpu again to enter a steady state
* kTiming_State: Finally we time the benchmark. When finished timing
* if we have enough samples then we'll start the next
* benchmark in the kPreWarmLoopsPerCanvasPreDraw_State.
* otherwise, we enter the
* kPreWarmTimingPerCanvasPreDraw_State for another sample
* In either case we reset the context.
*/
enum State {
kPreWarmLoopsPerCanvasPreDraw_State,
kPreWarmLoops_State,
kTuneLoops_State,
kPreWarmTimingPerCanvasPreDraw_State,
kPreWarmTiming_State,
kTiming_State,
};
void setTitle();
bool setupBackend();
void resetContext();
@ -47,19 +75,21 @@ private:
void printStats();
bool advanceRecordIfNecessary(SkCanvas*);
inline void renderFrame(SkCanvas*);
inline void nextState(State);
void perCanvasPreDraw(SkCanvas*, State);
void preWarm(State nextState);
void scaleLoops(double elapsedMs);
inline void tuneLoops();
inline void timing(SkCanvas*);
inline double elapsed();
void resetTimingState();
void postDraw(SkCanvas*);
void recordMeasurement();
struct Record {
SkTArray<double> fMeasurements;
};
enum State {
kPreWarmLoops_State,
kTuneLoops_State,
kPreWarmTiming_State,
kTiming_State,
};
void preWarm(State nextState);
int fCurrentSample;
int fCurrentFrame;
int fFlushes;