Add benchmarkstream to visualbench

BUG=skia:

Review URL: https://codereview.chromium.org/1215033002
This commit is contained in:
joshualitt 2015-06-30 07:43:14 -07:00 committed by Commit bot
parent 2757e3f09d
commit 962cc98eb4
8 changed files with 266 additions and 59 deletions

View File

@ -102,6 +102,11 @@ public:
fClearMask = clearMask;
}
/*
* Benches which support running in a visual mode can advertise this functionality
*/
virtual bool isVisual() { return false; }
protected:
virtual void setupPaint(SkPaint* paint);

View File

@ -11,19 +11,37 @@
{
'target_name': 'visualbench',
'type': 'executable',
'includes' : [
'gmslides.gypi',
],
'include_dirs' : [
'../bench',
'../include/gpu',
'../src/core',
'../src/effects',
'../src/images',
],
'sources': [
'../gm/gm.cpp',
'../tools/VisualBench/VisualBench.h',
'../tools/VisualBench/VisualBench.cpp',
'../tools/VisualBench/VisualBenchmarkStream.h',
'../tools/VisualBench/VisualBenchmarkStream.cpp',
'../tools/VisualBench/VisualSKPBench.h',
'../tools/VisualBench/VisualSKPBench.cpp',
'<!@(python find.py ../bench "*.cpp")',
],
'sources!': [
'../bench/nanobench.cpp',
'../bench/nanobenchAndroid.cpp',
],
'dependencies': [
'flags.gyp:flags_common',
'etc1.gyp:libetc1',
'flags.gyp:flags',
'gputest.gyp:skgputest',
'skia_lib.gyp:skia_lib',
'tools.gyp:proc_stats',
'tools.gyp:sk_tool_utils',
'tools.gyp:timer',
'views.gyp:views',
],

View File

@ -12,7 +12,6 @@
#include "SkApplication.h"
#include "SkCanvas.h"
#include "SkCommandLineFlags.h"
#include "SkCommonFlags.h"
#include "SkForceLinking.h"
#include "SkGraphics.h"
#include "SkGr.h"
@ -35,6 +34,7 @@ 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.");
DEFINE_bool2(verbose, v, false, "enable verbose output from the test driver.");
static SkString humanize(double ms) {
if (FLAGS_verbose) {
@ -47,34 +47,19 @@ static SkString humanize(double ms) {
VisualBench::VisualBench(void* hwnd, int argc, char** argv)
: INHERITED(hwnd)
, fCurrentPictureIdx(-1)
, fCurrentSample(0)
, fCurrentFrame(0)
, fFlushes(1)
, fLoops(1)
, fState(kPreWarmLoops_State) {
, fState(kPreWarmLoops_State)
, fBenchmark(NULL) {
SkCommandLineFlags::Parse(argc, argv);
// read all the skp file names.
for (int i = 0; i < FLAGS_skps.count(); i++) {
if (SkStrEndsWith(FLAGS_skps[i], ".skp")) {
fRecords.push_back().fFilename = FLAGS_skps[i];
} else {
SkOSFile::Iter it(FLAGS_skps[i], ".skp");
SkString path;
while (it.next(&path)) {
fRecords.push_back().fFilename = SkOSPath::Join(FLAGS_skps[i], path.c_str());;
}
}
}
if (fRecords.empty()) {
SkDebugf("no valid skps found\n");
}
this->setTitle();
this->setupBackend();
fBenchmarkStream.reset(SkNEW(VisualBenchmarkStream));
// Print header
SkDebugf("curr/maxrss\tloops\tflushes\tmin\tmedian\tmean\tmax\tstddev\tbench\n");
}
@ -134,22 +119,20 @@ void VisualBench::setupRenderTarget() {
inline void VisualBench::renderFrame(SkCanvas* canvas) {
for (int flush = 0; flush < fFlushes; flush++) {
for (int loop = 0; loop < fLoops; loop++) {
canvas->drawPicture(fPicture);
}
fBenchmark->draw(fLoops, canvas);
canvas->flush();
}
INHERITED::present();
}
void VisualBench::printStats() {
const SkTArray<double>& measurements = fRecords[fCurrentPictureIdx].fMeasurements;
SkString shortName = SkOSPath::Basename(fRecords[fCurrentPictureIdx].fFilename.c_str());
const SkTArray<double>& measurements = fRecords.back().fMeasurements;
const char* shortName = fBenchmark->getUniqueName();
if (FLAGS_verbose) {
for (int i = 0; i < measurements.count(); i++) {
SkDebugf("%s ", HUMANIZE(measurements[i]));
}
SkDebugf("%s\n", shortName.c_str());
SkDebugf("%s\n", shortName);
} else {
SkASSERT(measurements.count());
Stats stats(measurements);
@ -164,37 +147,28 @@ void VisualBench::printStats() {
HUMANIZE(stats.mean),
HUMANIZE(stats.max),
stdDevPercent,
shortName.c_str());
shortName);
}
}
bool VisualBench::advanceRecordIfNecessary() {
if (fPicture) {
bool VisualBench::advanceRecordIfNecessary(SkCanvas* canvas) {
if (fBenchmark) {
return true;
}
++fCurrentPictureIdx;
while (true) {
if (fCurrentPictureIdx >= fRecords.count()) {
return false;
}
if (this->loadPicture()) {
return true;
}
fRecords.removeShuffle(fCurrentPictureIdx);
}
}
bool VisualBench::loadPicture() {
const char* fileName = fRecords[fCurrentPictureIdx].fFilename.c_str();
SkFILEStream stream(fileName);
if (stream.isValid()) {
fPicture.reset(SkPicture::CreateFromStream(&stream));
if (SkToBool(fPicture)) {
return true;
}
while ((fBenchmark = fBenchmarkStream->next()) &&
(SkCommandLineFlags::ShouldSkip(FLAGS_match, fBenchmark->getUniqueName()) ||
!fBenchmark->isSuitableFor(Benchmark::kGPU_Backend))) {}
if (!fBenchmark) {
return false;
}
SkDebugf("couldn't load picture at \"%s\"\n", fileName);
return false;
canvas->clear(0xffffffff);
fBenchmark->preDraw();
fBenchmark->perCanvasPreDraw(canvas);
fRecords.push_back();
return true;
}
void VisualBench::preWarm(State nextState) {
@ -209,7 +183,7 @@ void VisualBench::preWarm(State nextState) {
}
void VisualBench::draw(SkCanvas* canvas) {
if (!this->advanceRecordIfNecessary()) {
if (!this->advanceRecordIfNecessary(canvas)) {
this->closeWindow();
return;
}
@ -251,12 +225,13 @@ void VisualBench::draw(SkCanvas* canvas) {
case kTiming_State: {
if (fCurrentFrame >= FLAGS_frames) {
fTimer.end();
fRecords[fCurrentPictureIdx].fMeasurements.push_back(
fRecords.back().fMeasurements.push_back(
fTimer.fWall / (FLAGS_frames * fLoops * fFlushes));
if (fCurrentSample++ >= FLAGS_samples) {
fState = kPreWarmLoops_State;
this->printStats();
fPicture.reset(NULL);
fBenchmark->perCanvasPostDraw(canvas);
fBenchmark = NULL;
fCurrentSample = 0;
fFlushes = 1;
fLoops = 1;

View File

@ -15,6 +15,7 @@
#include "SkString.h"
#include "SkSurface.h"
#include "Timer.h"
#include "VisualBenchmarkStream.h"
#include "gl/SkGLContext.h"
class GrContext;
@ -44,12 +45,10 @@ private:
void setupRenderTarget();
bool onHandleChar(SkUnichar unichar) override;
void printStats();
bool loadPicture();
bool advanceRecordIfNecessary();
bool advanceRecordIfNecessary(SkCanvas*);
inline void renderFrame(SkCanvas*);
struct Record {
SkString fFilename;
SkTArray<double> fMeasurements;
};
@ -61,8 +60,6 @@ private:
};
void preWarm(State nextState);
int fCurrentPictureIdx;
SkAutoTUnref<SkPicture> fPicture;
int fCurrentSample;
int fCurrentFrame;
int fFlushes;
@ -70,6 +67,8 @@ private:
SkTArray<Record> fRecords;
WallTimer fTimer;
State fState;
SkAutoTDelete<VisualBenchmarkStream> fBenchmarkStream;
Benchmark* fBenchmark;
// support framework
SkAutoTUnref<SkSurface> fSurface;

View File

@ -0,0 +1,103 @@
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
*/
#include <VisualBench/VisualBenchmarkStream.h>
#include "GMBench.h"
#include "SkOSFile.h"
#include "SkPictureRecorder.h"
#include "SkStream.h"
#include "VisualSKPBench.h"
DEFINE_string2(match, m, NULL,
"[~][^]substring[$] [...] of bench name to run.\n"
"Multiple matches may be separated by spaces.\n"
"~ causes a matching bench to always be skipped\n"
"^ requires the start of the bench to match\n"
"$ requires the end of the bench to match\n"
"^ and $ requires an exact match\n"
"If a bench does not match any list entry,\n"
"it is skipped unless some list entry starts with ~");
DEFINE_string(skps, "skps", "Directory to read skps from.");
VisualBenchmarkStream::VisualBenchmarkStream()
: fBenches(BenchRegistry::Head())
, fGMs(skiagm::GMRegistry::Head())
, fSourceType(NULL)
, fBenchType(NULL)
, fCurrentSKP(0) {
for (int i = 0; i < FLAGS_skps.count(); i++) {
if (SkStrEndsWith(FLAGS_skps[i], ".skp")) {
fSKPs.push_back() = FLAGS_skps[i];
} else {
SkOSFile::Iter it(FLAGS_skps[i], ".skp");
SkString path;
while (it.next(&path)) {
fSKPs.push_back() = SkOSPath::Join(FLAGS_skps[0], path.c_str());
}
}
}
}
bool VisualBenchmarkStream::ReadPicture(const char* path, SkAutoTUnref<SkPicture>* pic) {
// Not strictly necessary, as it will be checked again later,
// but helps to avoid a lot of pointless work if we're going to skip it.
if (SkCommandLineFlags::ShouldSkip(FLAGS_match, path)) {
return false;
}
SkAutoTDelete<SkStream> stream(SkStream::NewFromFile(path));
if (stream.get() == NULL) {
SkDebugf("Could not read %s.\n", path);
return false;
}
pic->reset(SkPicture::CreateFromStream(stream.get()));
if (pic->get() == NULL) {
SkDebugf("Could not read %s as an SkPicture.\n", path);
return false;
}
return true;
}
Benchmark* VisualBenchmarkStream::next() {
while (fBenches) {
Benchmark* bench = fBenches->factory()(NULL);
fBenches = fBenches->next();
if (bench->isVisual()) {
fSourceType = "bench";
fBenchType = "micro";
return bench;
}
}
while (fGMs) {
SkAutoTDelete<skiagm::GM> gm(fGMs->factory()(NULL));
fGMs = fGMs->next();
if (gm->runAsBench()) {
fSourceType = "gm";
fBenchType = "micro";
return SkNEW_ARGS(GMBench, (gm.detach()));
}
}
// Render skps
while (fCurrentSKP < fSKPs.count()) {
const SkString& path = fSKPs[fCurrentSKP++];
SkAutoTUnref<SkPicture> pic;
if (!ReadPicture(path.c_str(), &pic)) {
continue;
}
SkString name = SkOSPath::Basename(path.c_str());
fSourceType = "skp";
fBenchType = "playback";
return SkNEW_ARGS(VisualSKPBench, (name.c_str(), pic.get()));
}
return NULL;
}

View File

@ -0,0 +1,37 @@
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
*/
#ifndef VisualBenchmarkStream_DEFINED
#define VisualBenchmarkStream_DEFINED
#include "Benchmark.h"
#include "gm.h"
#include "SkCommandLineFlags.h"
#include "SkPicture.h"
DECLARE_string(match);
class VisualBenchmarkStream {
public:
VisualBenchmarkStream();
static bool ReadPicture(const char* path, SkAutoTUnref<SkPicture>* pic);
Benchmark* next();
private:
const BenchRegistry* fBenches;
const skiagm::GMRegistry* fGMs;
SkTArray<SkString> fSKPs;
const char* fSourceType; // What we're benching: bench, GM, SKP, ...
const char* fBenchType; // How we bench it: micro, playback, ...
int fCurrentSKP;
};
#endif

View File

@ -0,0 +1,33 @@
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
*/
#include "VisualSKPBench.h"
VisualSKPBench::VisualSKPBench(const char* name, const SkPicture* pic)
: fPic(SkRef(pic))
, fName(name) {
fUniqueName.printf("%s", name);
}
const char* VisualSKPBench::onGetName() {
return fName.c_str();
}
const char* VisualSKPBench::onGetUniqueName() {
return fUniqueName.c_str();
}
bool VisualSKPBench::isSuitableFor(Backend backend) {
return backend != kNonRendering_Backend;
}
void VisualSKPBench::onDraw(const int loops, SkCanvas* canvas) {
for (int i = 0; i < loops; i++) {
canvas->drawPicture(fPic);
}
}

View File

@ -0,0 +1,37 @@
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
*/
#ifndef VisualSKPBench_DEFINED
#define VisualSKPBench_DEFINED
#include "Benchmark.h"
#include "SkCanvas.h"
#include "SkPicture.h"
/**
* Runs an SkPicture as a benchmark by repeatedly drawing it
*/
class VisualSKPBench : public Benchmark {
public:
VisualSKPBench(const char* name, const SkPicture*);
protected:
const char* onGetName() override;
const char* onGetUniqueName() override;
bool isSuitableFor(Backend backend) override;
void onDraw(const int loops, SkCanvas* canvas) override;
private:
SkAutoTUnref<const SkPicture> fPic;
SkString fName;
SkString fUniqueName;
typedef Benchmark INHERITED;
};
#endif