DM: also run benches once.
Also:
- make GrMemoryPoolBenches threadsafe
- some tweaks to various DM code
- rename GM::shortName() to getName() to match benches and tests
On my desktop, (289 GMs, 617 benches) x 4 configs, 227 tests takes 46s in Debug, 14s in Release. (Still minutes faster than running tests && bench && gm.) GPU singlethreading is definitely the limiting factor again; going to reexamine whether that's helpful to thread it again.
BUG=skia:
R=reed@google.com, bsalomon@google.com, mtklein@google.com
Author: mtklein@chromium.org
Review URL: https://codereview.chromium.org/178473006
git-svn-id: http://skia.googlecode.com/svn/trunk@13603 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/dm/DM.cpp b/dm/DM.cpp
index ee53e9d..bf37d20 100644
--- a/dm/DM.cpp
+++ b/dm/DM.cpp
@@ -3,6 +3,7 @@
#include "GrContext.h"
#include "GrContextFactory.h"
+#include "SkBenchmark.h"
#include "SkCommandLineFlags.h"
#include "SkForceLinking.h"
#include "SkGraphics.h"
@@ -10,6 +11,7 @@
#include "Test.h"
#include "gm.h"
+#include "DMBenchTask.h"
#include "DMCpuTask.h"
#include "DMGpuTask.h"
#include "DMReporter.h"
@@ -38,11 +40,12 @@
"^ and $ requires an exact match\n"
"If a GM does not match any list entry,\n"
"it is skipped unless some list entry starts with ~");
-DEFINE_string(config, "565 8888 gpu",
- "Options: 565 8888 gpu msaa4 msaa16 gpunull gpudebug angle mesa"); // TODO(mtklein): pdf
+DEFINE_string(config, "565 8888 gpu nonrendering",
+ "Options: 565 8888 gpu nonrendering msaa4 msaa16 gpunull gpudebug angle mesa");
DEFINE_bool(leaks, false, "Print leaked instance-counted objects at exit?");
DEFINE_bool(gms, true, "Run GMs?");
+DEFINE_bool(benches, true, "Run benches? Does not run GMs-as-benches.");
DEFINE_bool(tests, true, "Run tests?");
__SK_FORCE_IMAGE_DECODER_LINKING;
@@ -55,46 +58,68 @@
return s;
}
+static const GrContextFactory::GLContextType native = GrContextFactory::kNative_GLContextType;
+static const GrContextFactory::GLContextType null = GrContextFactory::kNull_GLContextType;
+static const GrContextFactory::GLContextType debug = GrContextFactory::kDebug_GLContextType;
+static const GrContextFactory::GLContextType angle =
+#if SK_ANGLE
+GrContextFactory::kANGLE_GLContextType;
+#else
+native;
+#endif
+static const GrContextFactory::GLContextType mesa =
+#if SK_MESA
+GLContextFactory::kMESA_GLContextType;
+#else
+native;
+#endif
+
static void kick_off_gms(const SkTDArray<GMRegistry::Factory>& gms,
const SkTArray<SkString>& configs,
const DM::Expectations& expectations,
DM::Reporter* reporter,
DM::TaskRunner* tasks) {
- const SkColorType _565 = kRGB_565_SkColorType;
- const SkColorType _8888 = kPMColor_SkColorType;
- const GrContextFactory::GLContextType native = GrContextFactory::kNative_GLContextType;
- const GrContextFactory::GLContextType null = GrContextFactory::kNull_GLContextType;
- const GrContextFactory::GLContextType debug = GrContextFactory::kDebug_GLContextType;
- const GrContextFactory::GLContextType angle =
- #if SK_ANGLE
- GrContextFactory::kANGLE_GLContextType;
- #else
- native;
- #endif
- const GrContextFactory::GLContextType mesa =
- #if SK_MESA
- GLContextFactory::kMESA_GLContextType;
- #else
- native;
- #endif
-
- for (int i = 0; i < gms.count(); i++) {
-#define START(name, type, ...) \
- if (lowercase(configs[j]).equals(name)) { \
- tasks->add(SkNEW_ARGS(DM::type, \
- (name, reporter, tasks, expectations, gms[i], __VA_ARGS__))); \
+#define START(name, type, ...) \
+ if (lowercase(configs[j]).equals(name)) { \
+ tasks->add(SkNEW_ARGS(DM::type, \
+ (name, reporter, tasks, expectations, gms[i], ## __VA_ARGS__))); \
}
+ for (int i = 0; i < gms.count(); i++) {
for (int j = 0; j < configs.count(); j++) {
- START("565", CpuTask, _565);
- START("8888", CpuTask, _8888);
- START("gpu", GpuTask, _8888, native, 0);
- START("msaa4", GpuTask, _8888, native, 4);
- START("msaa16", GpuTask, _8888, native, 16);
- START("gpunull", GpuTask, _8888, null, 0);
- START("gpudebug", GpuTask, _8888, debug, 0);
- START("angle", GpuTask, _8888, angle, 0);
- START("mesa", GpuTask, _8888, mesa, 0);
- //START("pdf", PdfTask, _8888);
+ START("565", CpuTask, kRGB_565_SkColorType);
+ START("8888", CpuTask, kPMColor_SkColorType);
+ START("gpu", GpuTask, native, 0);
+ START("msaa4", GpuTask, native, 4);
+ START("msaa16", GpuTask, native, 16);
+ START("gpunull", GpuTask, null, 0);
+ START("gpudebug", GpuTask, debug, 0);
+ START("angle", GpuTask, angle, 0);
+ START("mesa", GpuTask, mesa, 0);
+ }
+ }
+#undef START
+}
+
+static void kick_off_benches(const SkTDArray<BenchRegistry::Factory>& benches,
+ const SkTArray<SkString>& configs,
+ DM::Reporter* reporter,
+ DM::TaskRunner* tasks) {
+#define START(name, type, ...) \
+ if (lowercase(configs[j]).equals(name)) { \
+ tasks->add(SkNEW_ARGS(DM::type, (name, reporter, tasks, benches[i], ## __VA_ARGS__))); \
+ }
+ for (int i = 0; i < benches.count(); i++) {
+ for (int j = 0; j < configs.count(); j++) {
+ START("nonrendering", NonRenderingBenchTask);
+ START("565", CpuBenchTask, kRGB_565_SkColorType);
+ START("8888", CpuBenchTask, kPMColor_SkColorType);
+ START("gpu", GpuBenchTask, native, 0);
+ START("msaa4", GpuBenchTask, native, 4);
+ START("msaa16", GpuBenchTask, native, 16);
+ START("gpunull", GpuBenchTask, null, 0);
+ START("gpudebug", GpuBenchTask, debug, 0);
+ START("angle", GpuBenchTask, angle, 0);
+ START("mesa", GpuBenchTask, mesa, 0);
}
}
#undef START
@@ -122,31 +147,36 @@
}
}
+template <typename T, typename Registry>
+static void append_matching_factories(Registry* head, SkTDArray<typename Registry::Factory>* out) {
+ for (const Registry* reg = head; reg != NULL; reg = reg->next()) {
+ SkAutoTDelete<T> forName(reg->factory()(NULL));
+ if (!SkCommandLineFlags::ShouldSkip(FLAGS_match, forName->getName())) {
+ *out->append() = reg->factory();
+ }
+ }
+}
+
int tool_main(int argc, char** argv);
int tool_main(int argc, char** argv) {
+ SkGraphics::Init();
+ SkCommandLineFlags::Parse(argc, argv);
#if SK_ENABLE_INST_COUNT
gPrintInstCount = FLAGS_leaks;
#endif
- SkGraphics::Init();
- SkCommandLineFlags::Parse(argc, argv);
GM::SetResourcePath(FLAGS_resources[0]);
+ SkBenchmark::SetResourcePath(FLAGS_resources[0]);
Test::SetResourcePath(FLAGS_resources[0]);
SkTArray<SkString> configs;
+ for (int i = 0; i < FLAGS_config.count(); i++) {
+ SkStrSplit(FLAGS_config[i], ", ", &configs);
+ }
+
SkTDArray<GMRegistry::Factory> gms;
SkAutoTDelete<DM::Expectations> expectations(SkNEW(DM::NoExpectations));
-
if (FLAGS_gms) {
- for (int i = 0; i < FLAGS_config.count(); i++) {
- SkStrSplit(FLAGS_config[i], ", ", &configs);
- }
-
- for (const GMRegistry* reg = GMRegistry::Head(); reg != NULL; reg = reg->next()) {
- SkAutoTDelete<GM> gmForName(reg->factory()(NULL));
- if (!SkCommandLineFlags::ShouldSkip(FLAGS_match, gmForName->shortName())) {
- *gms.append() = reg->factory();
- }
- }
+ append_matching_factories<GM>(GMRegistry::Head(), &gms);
if (FLAGS_expectations.count() > 0) {
const char* path = FLAGS_expectations[0];
@@ -158,20 +188,22 @@
}
}
- SkTDArray<TestRegistry::Factory> tests;
- if (FLAGS_tests) {
- for (const TestRegistry* reg = TestRegistry::Head(); reg != NULL; reg = reg->next()) {
- SkAutoTDelete<Test> testForName(reg->factory()(NULL));
- if (!SkCommandLineFlags::ShouldSkip(FLAGS_match, testForName->getName())) {
- *tests.append() = reg->factory();
- }
- }
+ SkTDArray<BenchRegistry::Factory> benches;
+ if (FLAGS_benches) {
+ append_matching_factories<SkBenchmark>(BenchRegistry::Head(), &benches);
}
- SkDebugf("%d GMs x %d configs, %d tests\n", gms.count(), configs.count(), tests.count());
+ SkTDArray<TestRegistry::Factory> tests;
+ if (FLAGS_tests) {
+ append_matching_factories<Test>(TestRegistry::Head(), &tests);
+ }
+
+ SkDebugf("(%d GMs, %d benches) x %d configs, %d tests\n",
+ gms.count(), benches.count(), configs.count(), tests.count());
DM::Reporter reporter;
DM::TaskRunner tasks(FLAGS_threads);
kick_off_gms(gms, configs, *expectations, &reporter, &tasks);
+ kick_off_benches(benches, configs, &reporter, &tasks);
kick_off_tests(tests, &reporter, &tasks);
tasks.wait();
diff --git a/dm/DMBenchTask.cpp b/dm/DMBenchTask.cpp
new file mode 100644
index 0000000..4e251de
--- /dev/null
+++ b/dm/DMBenchTask.cpp
@@ -0,0 +1,86 @@
+#include "DMBenchTask.h"
+#include "DMUtil.h"
+#include "SkSurface.h"
+
+namespace DM {
+
+static SkString bench_name(const char* name, const char* config) {
+ SkString result("bench ");
+ result.appendf("%s_%s", name, config);
+ return result;
+}
+
+NonRenderingBenchTask::NonRenderingBenchTask(const char* config,
+ Reporter* reporter,
+ TaskRunner* tasks,
+ BenchRegistry::Factory factory)
+ : Task(reporter, tasks)
+ , fBench(factory(NULL))
+ , fName(bench_name(fBench->getName(), config)) {}
+
+CpuBenchTask::CpuBenchTask(const char* config,
+ Reporter* reporter,
+ TaskRunner* tasks,
+ BenchRegistry::Factory factory,
+ SkColorType colorType)
+ : Task(reporter, tasks)
+ , fBench(factory(NULL))
+ , fName(bench_name(fBench->getName(), config))
+ , fColorType(colorType) {}
+
+GpuBenchTask::GpuBenchTask(const char* config,
+ Reporter* reporter,
+ TaskRunner* tasks,
+ BenchRegistry::Factory factory,
+ GrContextFactory::GLContextType contextType,
+ int sampleCount)
+ : Task(reporter, tasks)
+ , fBench(factory(NULL))
+ , fName(bench_name(fBench->getName(), config))
+ , fContextType(contextType)
+ , fSampleCount(sampleCount) {}
+
+bool NonRenderingBenchTask::shouldSkip() const {
+ return !fBench->isSuitableFor(SkBenchmark::kNonRendering_Backend);
+}
+
+bool CpuBenchTask::shouldSkip() const {
+ return !fBench->isSuitableFor(SkBenchmark::kRaster_Backend);
+}
+
+bool GpuBenchTask::shouldSkip() const {
+ return !fBench->isSuitableFor(SkBenchmark::kGPU_Backend);
+}
+
+static void draw_raster(SkBenchmark* bench, SkColorType colorType) {
+ SkBitmap bitmap;
+ SetupBitmap(colorType, bench, &bitmap);
+ SkCanvas canvas(bitmap);
+
+ bench->preDraw();
+ bench->draw(1, &canvas);
+ bench->postDraw();
+}
+
+void NonRenderingBenchTask::draw() {
+ draw_raster(fBench.get(), kPMColor_SkColorType);
+}
+
+void CpuBenchTask::draw() {
+ draw_raster(fBench.get(), fColorType);
+}
+
+void GpuBenchTask::draw() {
+ SkImageInfo info = SkImageInfo::Make(fBench->getSize().x(),
+ fBench->getSize().y(),
+ kPMColor_SkColorType,
+ kPremul_SkAlphaType);
+ SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTarget(
+ this->getGrContextFactory()->get(fContextType), info, fSampleCount));
+
+ fBench->preDraw();
+ fBench->draw(1, surface->getCanvas());
+ fBench->postDraw();
+}
+
+} // namespace DM
diff --git a/dm/DMBenchTask.h b/dm/DMBenchTask.h
new file mode 100644
index 0000000..1e9bc99
--- /dev/null
+++ b/dm/DMBenchTask.h
@@ -0,0 +1,67 @@
+#ifndef DMBenchTask_DEFINED
+#define DMBenchTask_DEFINED
+
+#include "DMReporter.h"
+#include "DMTask.h"
+#include "DMTaskRunner.h"
+#include "SkBenchmark.h"
+#include "SkString.h"
+#include "SkTemplates.h"
+
+// Tasks that run an SkBenchmark once as a check that it doesn't crash.
+
+namespace DM {
+
+class NonRenderingBenchTask : public Task {
+public:
+ NonRenderingBenchTask(const char* config, Reporter*, TaskRunner*, BenchRegistry::Factory);
+
+ virtual void draw() SK_OVERRIDE;
+ virtual bool usesGpu() const SK_OVERRIDE { return false; }
+ virtual bool shouldSkip() const SK_OVERRIDE;
+ virtual SkString name() const SK_OVERRIDE { return fName; }
+
+private:
+ SkAutoTDelete<SkBenchmark> fBench;
+ const SkString fName;
+};
+
+class CpuBenchTask : public Task {
+public:
+ CpuBenchTask(const char* config, Reporter*, TaskRunner*, BenchRegistry::Factory, SkColorType);
+
+ virtual void draw() SK_OVERRIDE;
+ virtual bool usesGpu() const SK_OVERRIDE { return false; }
+ virtual bool shouldSkip() const SK_OVERRIDE;
+ virtual SkString name() const SK_OVERRIDE { return fName; }
+
+private:
+ SkAutoTDelete<SkBenchmark> fBench;
+ const SkString fName;
+ const SkColorType fColorType;
+};
+
+class GpuBenchTask : public Task {
+public:
+ GpuBenchTask(const char* config,
+ Reporter*,
+ TaskRunner*,
+ BenchRegistry::Factory,
+ GrContextFactory::GLContextType,
+ int sampleCount);
+
+ virtual void draw() SK_OVERRIDE;
+ virtual bool usesGpu() const SK_OVERRIDE { return true; }
+ virtual bool shouldSkip() const SK_OVERRIDE;
+ virtual SkString name() const SK_OVERRIDE { return fName; }
+
+private:
+ SkAutoTDelete<SkBenchmark> fBench;
+ const SkString fName;
+ const GrContextFactory::GLContextType fContextType;
+ int fSampleCount;
+};
+
+} // namespace DM
+
+#endif // DMBenchTask_DEFINED
diff --git a/dm/DMCpuTask.cpp b/dm/DMCpuTask.cpp
index 7a82a75..acbe8d2 100644
--- a/dm/DMCpuTask.cpp
+++ b/dm/DMCpuTask.cpp
@@ -9,7 +9,7 @@
namespace DM {
-CpuTask::CpuTask(const char* name,
+CpuTask::CpuTask(const char* config,
Reporter* reporter,
TaskRunner* taskRunner,
const Expectations& expectations,
@@ -18,7 +18,7 @@
: Task(reporter, taskRunner)
, fGMFactory(gmFactory)
, fGM(fGMFactory(NULL))
- , fName(UnderJoin(fGM->shortName(), name))
+ , fName(UnderJoin(fGM->getName(), config))
, fExpectations(expectations)
, fColorType(colorType)
{}
diff --git a/dm/DMCpuTask.h b/dm/DMCpuTask.h
index 8e7f531..0ae112f 100644
--- a/dm/DMCpuTask.h
+++ b/dm/DMCpuTask.h
@@ -17,7 +17,7 @@
class CpuTask : public Task {
public:
- CpuTask(const char* name,
+ CpuTask(const char* config,
Reporter*,
TaskRunner*,
const Expectations&,
diff --git a/dm/DMGpuTask.cpp b/dm/DMGpuTask.cpp
index 3a4708b..c285d88 100644
--- a/dm/DMGpuTask.cpp
+++ b/dm/DMGpuTask.cpp
@@ -9,20 +9,17 @@
namespace DM {
-GpuTask::GpuTask(const char* name,
+GpuTask::GpuTask(const char* config,
Reporter* reporter,
TaskRunner* taskRunner,
const Expectations& expectations,
skiagm::GMRegistry::Factory gmFactory,
- SkColorType colorType,
GrContextFactory::GLContextType contextType,
int sampleCount)
: Task(reporter, taskRunner)
- , fTaskRunner(taskRunner)
, fGM(gmFactory(NULL))
- , fName(UnderJoin(fGM->shortName(), name))
+ , fName(UnderJoin(fGM->getName(), config))
, fExpectations(expectations)
- , fColorType(colorType)
, fContextType(contextType)
, fSampleCount(sampleCount)
{}
@@ -30,10 +27,10 @@
void GpuTask::draw() {
SkImageInfo info = SkImageInfo::Make(SkScalarCeilToInt(fGM->width()),
SkScalarCeilToInt(fGM->height()),
- fColorType,
+ kPMColor_SkColorType,
kPremul_SkAlphaType);
- GrContext* gr = fTaskRunner->getGrContextFactory()->get(fContextType); // Owned by surface.
- SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTarget(gr, info, fSampleCount));
+ SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTarget(
+ this->getGrContextFactory()->get(fContextType), info, fSampleCount));
SkCanvas* canvas = surface->getCanvas();
canvas->concat(fGM->getInitialTransform());
diff --git a/dm/DMGpuTask.h b/dm/DMGpuTask.h
index 1380e44..f74950c 100644
--- a/dm/DMGpuTask.h
+++ b/dm/DMGpuTask.h
@@ -17,12 +17,11 @@
class GpuTask : public Task {
public:
- GpuTask(const char* name,
+ GpuTask(const char* config,
Reporter*,
TaskRunner*,
const Expectations&,
skiagm::GMRegistry::Factory,
- SkColorType,
GrContextFactory::GLContextType,
int sampleCount);
@@ -32,11 +31,9 @@
virtual SkString name() const SK_OVERRIDE { return fName; }
private:
- TaskRunner* fTaskRunner;
SkAutoTDelete<skiagm::GM> fGM;
const SkString fName;
const Expectations& fExpectations;
- const SkColorType fColorType;
const GrContextFactory::GLContextType fContextType;
const int fSampleCount;
};
diff --git a/dm/DMTask.cpp b/dm/DMTask.cpp
index 2f009f0..d26971c 100644
--- a/dm/DMTask.cpp
+++ b/dm/DMTask.cpp
@@ -46,4 +46,8 @@
fReporter->fail(failure);
}
+GrContextFactory* Task::getGrContextFactory() const {
+ return fTaskRunner->getGrContextFactory();
+}
+
} // namespace DM
diff --git a/dm/DMTask.h b/dm/DMTask.h
index 638a939..e8598df 100644
--- a/dm/DMTask.h
+++ b/dm/DMTask.h
@@ -2,6 +2,7 @@
#define DMTask_DEFINED
#include "DMReporter.h"
+#include "GrContextFactory.h"
#include "SkRunnable.h"
#include "SkThreadPool.h"
@@ -36,6 +37,9 @@
void spawnChild(Task* task);
void fail(const char* msg = NULL);
+ // This can only be safely called from a GPU task's draw() method.
+ GrContextFactory* getGrContextFactory() const;
+
private:
// Both unowned.
Reporter* fReporter;
diff --git a/dm/DMTestTask.cpp b/dm/DMTestTask.cpp
index 7a5f8cf..32a698c 100644
--- a/dm/DMTestTask.cpp
+++ b/dm/DMTestTask.cpp
@@ -8,17 +8,22 @@
namespace DM {
+static SkString test_name(const char* name) {
+ SkString result("test ");
+ result.append(name);
+ return result;
+}
+
TestTask::TestTask(Reporter* reporter,
TaskRunner* taskRunner,
skiatest::TestRegistry::Factory factory)
: Task(reporter, taskRunner)
- , fTaskRunner(taskRunner)
, fTest(factory(NULL))
- , fName(UnderJoin("test", fTest->getName())) {}
+ , fName(test_name(fTest->getName())) {}
void TestTask::draw() {
if (this->usesGpu()) {
- fTest->setGrContextFactory(fTaskRunner->getGrContextFactory());
+ fTest->setGrContextFactory(this->getGrContextFactory());
}
fTest->setReporter(&fTestReporter);
fTest->run();
diff --git a/dm/DMTestTask.h b/dm/DMTestTask.h
index a4903ee..49a8e77 100644
--- a/dm/DMTestTask.h
+++ b/dm/DMTestTask.h
@@ -39,7 +39,6 @@
SkString fFailure;
};
- TaskRunner* fTaskRunner;
TestReporter fTestReporter;
SkAutoTDelete<skiatest::Test> fTest;
const SkString fName;
diff --git a/dm/DMUtil.cpp b/dm/DMUtil.cpp
index 849d1bf..5a849fb 100644
--- a/dm/DMUtil.cpp
+++ b/dm/DMUtil.cpp
@@ -19,13 +19,19 @@
picture->endRecording();
}
-void SetupBitmap(const SkColorType ct, skiagm::GM* gm, SkBitmap* bitmap) {
- const SkISize size = gm->getISize();
- bitmap->allocPixels(SkImageInfo::Make(size.width(), size.height(),
- ct, kPremul_SkAlphaType));
+static void setup_bitmap(SkColorType ct, int width, int height, SkBitmap* bitmap) {
+ bitmap->allocPixels(SkImageInfo::Make(width, height, ct, kPremul_SkAlphaType));
bitmap->eraseColor(0x00000000);
}
+void SetupBitmap(const SkColorType ct, skiagm::GM* gm, SkBitmap* bitmap) {
+ setup_bitmap(ct, gm->getISize().width(), gm->getISize().height(), bitmap);
+}
+
+void SetupBitmap(const SkColorType ct, SkBenchmark* bench, SkBitmap* bitmap) {
+ setup_bitmap(ct, bench->getSize().x(), bench->getSize().y(), bitmap);
+}
+
void DrawPicture(SkPicture* picture, SkBitmap* bitmap) {
SkASSERT(picture != NULL);
SkASSERT(bitmap != NULL);
diff --git a/dm/DMUtil.h b/dm/DMUtil.h
index a791649..faa4e39 100644
--- a/dm/DMUtil.h
+++ b/dm/DMUtil.h
@@ -1,6 +1,7 @@
#ifndef DMUtil_DEFINED
#define DMUtil_DEFINED
+#include "SkBenchmark.h"
#include "SkBitmap.h"
#include "SkString.h"
#include "gm_expectations.h"
@@ -15,8 +16,10 @@
// Draw gm to picture. Passes recordFlags to SkPicture::beginRecording().
void RecordPicture(skiagm::GM* gm, SkPicture* picture, uint32_t recordFlags = 0);
-// Prepare bitmap to have gm draw into it with this config.
+// Prepare bitmap to have gm or bench draw into it with this config.
+// TODO(mtklein): make SkBenchmark::getSize()/GM::getISize() const.
void SetupBitmap(const SkColorType, skiagm::GM* gm, SkBitmap* bitmap);
+void SetupBitmap(const SkColorType, SkBenchmark* bench, SkBitmap* bitmap);
// Draw picture to bitmap.
void DrawPicture(SkPicture* picture, SkBitmap* bitmap);