SKPs-as-benches in nanobench

This is meant to replace bench_pictures.

CQ_EXTRA_TRYBOTS=tryserver.skia:Build-Mac10.7-Clang-Arm7-Release-iOS-Trybot

BUG=skia:
R=bsalomon@google.com, jcgregorio@google.com, mtklein@google.com

Author: mtklein@chromium.org

Review URL: https://codereview.chromium.org/425393004
This commit is contained in:
mtklein 2014-08-01 07:46:52 -07:00 committed by Commit bot
parent efea5a72d6
commit 92007583e4
10 changed files with 189 additions and 11 deletions

View File

@ -49,3 +49,4 @@ SkIPoint GMBench::onGetSize() {
SkISize size = fGM->getISize();
return SkIPoint::Make(size.fWidth, size.fHeight);
}

View File

@ -4,6 +4,8 @@
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GMBench_DEFINED
#define GMBench_DEFINED
#include "Benchmark.h"
#include "SkCanvas.h"
@ -29,3 +31,5 @@ private:
SkString fName;
typedef Benchmark INHERITED;
};
#endif

37
bench/SKPBench.cpp Normal file
View File

@ -0,0 +1,37 @@
/*
* Copyright 2014 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SKPBench.h"
SKPBench::SKPBench(const char* name, const SkPicture* pic, const SkIRect& clip, SkScalar scale)
: fPic(SkRef(pic))
, fClip(clip)
, fScale(scale) {
fName.printf("%s_%.2g", name, scale);
}
const char* SKPBench::onGetName() {
return fName.c_str();
}
bool SKPBench::isSuitableFor(Backend backend) {
return backend != kNonRendering_Backend;
}
SkIPoint SKPBench::onGetSize() {
return SkIPoint::Make(fClip.width(), fClip.height());
}
void SKPBench::onDraw(const int loops, SkCanvas* canvas) {
canvas->save();
canvas->scale(fScale, fScale);
for (int i = 0; i < loops; i++) {
fPic->draw(canvas);
canvas->flush();
}
canvas->restore();
}

37
bench/SKPBench.h Normal file
View File

@ -0,0 +1,37 @@
/*
* Copyright 2014 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SKPBench_DEFINED
#define SKPBench_DEFINED
#include "Benchmark.h"
#include "SkCanvas.h"
#include "SkPicture.h"
/**
* Runs an SkPicture as a benchmark by repeatedly drawing it scaled inside a device clip.
*/
class SKPBench : public Benchmark {
public:
SKPBench(const char* name, const SkPicture*, const SkIRect& devClip, SkScalar scale);
protected:
virtual const char* onGetName() SK_OVERRIDE;
virtual bool isSuitableFor(Backend backend) SK_OVERRIDE;
virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE;
virtual SkIPoint onGetSize() SK_OVERRIDE;
private:
SkAutoTUnref<const SkPicture> fPic;
const SkIRect fClip;
const SkScalar fScale;
SkString fName;
typedef Benchmark INHERITED;
};
#endif

View File

@ -11,9 +11,11 @@
#include "CrashHandler.h"
#include "GMBench.h"
#include "ResultsWriter.h"
#include "SKPBench.h"
#include "Stats.h"
#include "Timer.h"
#include "SkOSFile.h"
#include "SkCanvas.h"
#include "SkCommonFlags.h"
#include "SkForceLinking.h"
@ -49,6 +51,9 @@ DEFINE_int32(maxLoops, 1000000, "Never run a bench more times than this.");
DEFINE_string(key, "", "Space-separated key/value pairs to add to JSON.");
DEFINE_string(gitHash, "", "Git hash to add to JSON.");
DEFINE_string(clip, "0,0,1000,1000", "Clip for SKPs.");
DEFINE_string(scales, "1.0", "Space-separated scales for SKPs.");
static SkString humanize(double ms) {
if (ms > 1e+3) return SkStringPrintf("%.3gs", ms/1e3);
if (ms < 1e-3) return SkStringPrintf("%.3gns", ms*1e6);
@ -357,28 +362,108 @@ static void fill_gpu_options(ResultsWriter* log, SkGLContextHelper* ctx) {
class BenchmarkStream {
public:
BenchmarkStream() : fBenches(BenchRegistry::Head()) , fGMs(skiagm::GMRegistry::Head()) {}
BenchmarkStream() : fBenches(BenchRegistry::Head())
, fGMs(skiagm::GMRegistry::Head())
, fCurrentScale(0)
, 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());
}
}
}
Benchmark* next(const char** sourceType) {
if (4 != sscanf(FLAGS_clip[0], "%d,%d,%d,%d",
&fClip.fLeft, &fClip.fTop, &fClip.fRight, &fClip.fBottom)) {
SkDebugf("Can't parse %s from --clip as an SkIRect.\n", FLAGS_clip[0]);
exit(1);
}
for (int i = 0; i < FLAGS_scales.count(); i++) {
if (1 != sscanf(FLAGS_scales[i], "%f", &fScales.push_back())) {
SkDebugf("Can't parse %s from --scales as an SkScalar.\n", FLAGS_scales[i]);
exit(1);
}
}
}
Benchmark* next() {
if (fBenches) {
Benchmark* bench = fBenches->factory()(NULL);
fBenches = fBenches->next();
*sourceType = "bench";
fSourceType = "bench";
return bench;
}
while (fGMs) {
SkAutoTDelete<skiagm::GM> gm(fGMs->factory()(NULL));
fGMs = fGMs->next();
if (gm->getFlags() & skiagm::GM::kAsBench_Flag) {
*sourceType = "gm";
fSourceType = "gm";
return SkNEW_ARGS(GMBench, (gm.detach()));
}
}
while (fCurrentScale < fScales.count()) {
while (fCurrentSKP < fSKPs.count()) {
const SkString& path = fSKPs[fCurrentSKP++];
// 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.c_str())) {
continue;
}
SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(path.c_str()));
if (stream.get() == NULL) {
SkDebugf("Could not read %s.\n", path.c_str());
exit(1);
}
SkAutoTUnref<SkPicture> pic(SkPicture::CreateFromStream(stream.get()));
if (pic.get() == NULL) {
SkDebugf("Could not read %s as an SkPicture.\n", path.c_str());
exit(1);
}
SkString name = SkOSPath::Basename(path.c_str());
fSourceType = "skp";
return SkNEW_ARGS(SKPBench,
(name.c_str(), pic.get(), fClip, fScales[fCurrentScale]));
}
fCurrentSKP = 0;
fCurrentScale++;
}
return NULL;
}
void fillCurrentOptions(ResultsWriter* log) const {
log->configOption("source_type", fSourceType);
if (0 == strcmp(fSourceType, "skp")) {
log->configOption("clip",
SkStringPrintf("%d %d %d %d", fClip.fLeft, fClip.fTop,
fClip.fRight, fClip.fBottom).c_str());
log->configOption("scale", SkStringPrintf("%.2g", fScales[fCurrentScale]).c_str());
}
}
private:
const BenchRegistry* fBenches;
const skiagm::GMRegistry* fGMs;
SkIRect fClip;
SkTArray<SkScalar> fScales;
SkTArray<SkString> fSKPs;
const char* fSourceType;
int fCurrentScale;
int fCurrentSKP;
};
int nanobench_main();
@ -427,9 +512,8 @@ int nanobench_main() {
SkTDArray<Config> configs;
create_configs(&configs);
BenchmarkStream benches;
const char* sourceType;
while (Benchmark* b = benches.next(&sourceType)) {
BenchmarkStream benchStream;
while (Benchmark* b = benchStream.next()) {
SkAutoTDelete<Benchmark> bench(b);
if (SkCommandLineFlags::ShouldSkip(FLAGS_match, bench->getName())) {
continue;
@ -446,6 +530,18 @@ int nanobench_main() {
SkCanvas* canvas = targets[j]->surface.get() ? targets[j]->surface->getCanvas() : NULL;
const char* config = targets[j]->config.name;
#if SK_DEBUG
// skia:2797 Some SKPs SkASSERT in debug mode. Skip them for now.
if (0 == strcmp("565", config)
&& ( SkStrStartsWith(bench->getName(), "desk_carsvg.skp")
|| SkStrStartsWith(bench->getName(), "desk_forecastio.skp")
|| SkStrStartsWith(bench->getName(), "tabl_cnet.skp")
|| SkStrStartsWith(bench->getName(), "tabl_googlecalendar.skp"))) {
SkDebugf("Skipping 565 %s. It'd assert.\n", bench->getName());
continue;
}
#endif
const int loops =
#if SK_SUPPORT_GPU
Benchmark::kGPU_Backend == targets[j]->config.backend
@ -462,7 +558,7 @@ int nanobench_main() {
Stats stats(samples.get(), FLAGS_samples);
log.config(config);
log.configOption("source_type", sourceType);
benchStream.fillCurrentOptions(&log);
#if SK_SUPPORT_GPU
if (Benchmark::kGPU_Backend == targets[j]->config.backend) {
fill_gpu_options(&log, targets[j]->gl);

View File

@ -46,8 +46,6 @@ DEFINE_string2(expectations, r, "",
"If a file, compare generated images against JSON expectations at this path."
);
DEFINE_string(skps, "", "Directory to read skps from.");
DEFINE_bool(gms, true, "Run GMs?");
DEFINE_bool(tests, true, "Run tests?");
DEFINE_bool(reportUsedChars, false, "Output test font construction data to be pasted into"
@ -247,7 +245,7 @@ int dm_main() {
sk_tool_utils::report_used_chars();
}
#endif
SkTArray<SkString> failures;
reporter.getFailures(&failures);
report_failures(failures);

View File

@ -38,6 +38,7 @@
'type': 'executable',
'sources': [
'../bench/GMBench.cpp',
'../bench/SKPBench.cpp',
'../bench/ResultsWriter.cpp',
'../bench/nanobench.cpp',
],

View File

@ -19,6 +19,7 @@
],
'sources': [
'../bench/GMBench.cpp',
'../bench/SKPBench.cpp',
'../bench/ResultsWriter.cpp',
'../bench/nanobench.cpp',
'../tests/skia_test.cpp',

View File

@ -44,6 +44,8 @@ DEFINE_bool(abandonGpuContext, false, "Abandon the GrContext after running each
DEFINE_bool2(single, z, false, "run tests on a single thread internally.");
DEFINE_string(skps, "", "Directory to read skps from.");
DEFINE_int32(threads, SkThreadPool::kThreadPerCore,
"run threadsafe tests on a threadpool with this many threads.");

View File

@ -21,6 +21,7 @@ DECLARE_bool(quiet);
DECLARE_bool(resetGpuContext);
DECLARE_bool(abandonGpuContext);
DECLARE_bool(single);
DECLARE_string(skps);
DECLARE_int32(threads);
DECLARE_string(resourcePath);
DECLARE_bool(verbose);