Add warmup bench to visual bench

BUG=skia:

Review URL: https://codereview.chromium.org/1358373003
This commit is contained in:
joshualitt 2015-09-24 08:08:23 -07:00 committed by Commit bot
parent 3f9deab9fc
commit 7d4b458b9f
3 changed files with 56 additions and 7 deletions

View File

@ -39,6 +39,8 @@ public:
return fName.c_str();
}
bool isVisual() override { return true; }
protected:
virtual void drawThisRect(SkCanvas* c, const SkRect& r, const SkPaint& p) {
c->drawRect(r, p);

View File

@ -26,6 +26,7 @@ __SK_FORCE_IMAGE_DECODER_LINKING;
// Between samples we reset context
// Between frames we swap buffers
DEFINE_int32(maxWarmupFrames, 100, "maxmium frames to try and tune for sane timings");
DEFINE_int32(gpuFrameLag, 5, "Overestimate of maximum number of frames GPU allows to lag.");
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.");
@ -46,18 +47,31 @@ static SkString humanize(double ms) {
#define HUMANIZE(time) humanize(time).c_str()
// A trivial bench to warm up the gpu
class WarmupBench : public Benchmark {
public:
private:
const char* onGetName() override { return "warmupbench"; }
void onDraw(const int loops, SkCanvas* canvas) override {
for (int i = 0; i < loops; i++) {
sk_tool_utils::draw_checkerboard(canvas, 0xffffffff, 0xffc6c3c6, 10);
}
}
};
VisualLightweightBenchModule::VisualLightweightBenchModule(VisualBench* owner)
: fCurrentSample(0)
, fCurrentFrame(0)
, fLoops(1)
, fState(kPreWarmLoops_State)
, fState(kWarmup_State)
, fBenchmark(nullptr)
, fOwner(SkRef(owner))
, fResults(new ResultsWriter) {
fBenchmarkStream.reset(new VisualBenchmarkStream);
// Print header
SkDebugf("curr/maxrss\tloops\tflushes\tmin\tmedian\tmean\tmax\tstddev\tbench\n");
SkDebugf("curr/maxrss\tloops\tmin\tmedian\tmean\tmax\tstddev\t%-*s\tbench\n", FLAGS_samples,
"samples");
// setup json logging if required
if (!FLAGS_outResultsFile.isEmpty()) {
@ -100,10 +114,10 @@ void VisualLightweightBenchModule::printStats() {
configName.appendf("gpu");
}
fResults->config(configName.c_str());
fResults->configOption("name", fBenchmark->getUniqueName());
fResults->configOption("name", shortName);
SkASSERT(measurements.count());
Stats stats(measurements);
fResults->metric("min_ms", stats.min);
fResults->metric("min_ms", stats.min);
// Print output
if (FLAGS_verbose) {
@ -113,7 +127,7 @@ void VisualLightweightBenchModule::printStats() {
SkDebugf("%s\n", shortName);
} else {
const double stdDevPercent = 100 * sqrt(stats.var) / stats.mean;
SkDebugf("%4d/%-4dMB\t%d\t%s\t%s\t%s\t%s\t%.0f%%\t%s\n",
SkDebugf("%4d/%-4dMB\t%d\t%s\t%s\t%s\t%s\t%.0f%%\t%s\t%s\n",
sk_tools::getCurrResidentSetSizeMB(),
sk_tools::getMaxResidentSetSizeMB(),
fLoops,
@ -122,11 +136,17 @@ void VisualLightweightBenchModule::printStats() {
HUMANIZE(stats.mean),
HUMANIZE(stats.max),
stdDevPercent,
stats.plot.c_str(),
shortName);
}
}
bool VisualLightweightBenchModule::advanceRecordIfNecessary(SkCanvas* canvas) {
if (!fBenchmark && fState == kWarmup_State) {
fBenchmark.reset(new WarmupBench);
return true;
}
if (fBenchmark) {
return true;
}
@ -138,7 +158,6 @@ bool VisualLightweightBenchModule::advanceRecordIfNecessary(SkCanvas* canvas) {
fOwner->clear(canvas, SK_ColorWHITE, 2);
fBenchmark->preDraw();
fRecords.push_back();
@ -158,6 +177,27 @@ void VisualLightweightBenchModule::perCanvasPreDraw(SkCanvas* canvas, State next
this->nextState(nextState);
}
void VisualLightweightBenchModule::warmup(SkCanvas* canvas) {
if (fCurrentFrame >= FLAGS_maxWarmupFrames) {
this->nextState(kPreWarmLoopsPerCanvasPreDraw_State);
fBenchmark.reset(nullptr);
this->resetTimingState();
fLoops = 1;
} else {
bool isEven = (fCurrentFrame++ % 2) == 0;
if (isEven) {
fTimer.start();
} else {
double elapsedMs = this->elapsed();
if (elapsedMs < FLAGS_loopMs) {
fLoops *= 2;
}
fTimer = WallTimer();
fOwner->reset();
}
}
}
void VisualLightweightBenchModule::preWarm(State nextState) {
if (fCurrentFrame >= FLAGS_gpuFrameLag) {
// we currently time across all frames to make sure we capture all GPU work
@ -177,6 +217,10 @@ void VisualLightweightBenchModule::draw(SkCanvas* canvas) {
}
this->renderFrame(canvas);
switch (fState) {
case kWarmup_State: {
this->warmup(canvas);
break;
}
case kPreWarmLoopsPerCanvasPreDraw_State: {
this->perCanvasPreDraw(canvas, kPreWarmLoops_State);
break;
@ -224,7 +268,7 @@ inline void VisualLightweightBenchModule::tuneLoops() {
if (1 << 30 == fLoops) {
// We're about to wrap. Something's wrong with the bench.
SkDebugf("InnerLoops wrapped\n");
fLoops = 0;
fLoops = 1;
} else {
double elapsedMs = this->elapsed();
if (elapsedMs > FLAGS_loopMs) {

View File

@ -34,6 +34,7 @@ public:
private:
/*
* The heart of visual bench is an event driven timing loop.
* kWarmup_State: We run a dummy bench to let things settle on startup
* kPreWarmLoopsPerCanvasPreDraw_State: Before we begin timing, Benchmarks have a hook to
* access the canvas. Then we prewarm before the autotune
* loops step.
@ -53,6 +54,7 @@ private:
* In either case we reset the context.
*/
enum State {
kWarmup_State,
kPreWarmLoopsPerCanvasPreDraw_State,
kPreWarmLoops_State,
kTuneLoops_State,
@ -76,6 +78,7 @@ private:
void resetTimingState();
void postDraw(SkCanvas*);
void recordMeasurement();
void warmup(SkCanvas* canvas);
struct Record {
SkTArray<double> fMeasurements;