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/bench/GrMemoryPoolBench.cpp b/bench/GrMemoryPoolBench.cpp
index 21f686d..96526e5 100644
--- a/bench/GrMemoryPoolBench.cpp
+++ b/bench/GrMemoryPoolBench.cpp
@@ -20,12 +20,12 @@
 struct A {
     int gStuff[10];
 #if OVERRIDE_NEW
-    void* operator new (size_t size) { return gPool.allocate(size); }
-    void operator delete (void* mem) { if (mem) { return gPool.release(mem); } }
+    void* operator new (size_t size) { return gBenchPool.allocate(size); }
+    void operator delete (void* mem) { if (mem) { return gBenchPool.release(mem); } }
 #endif
-    static GrMemoryPool gPool;
+    static GrMemoryPool gBenchPool;
 };
-GrMemoryPool A::gPool(10 * (1 << 10), 10 * (1 << 10));
+GrMemoryPool A::gBenchPool(10 * (1 << 10), 10 * (1 << 10));
 
 /**
  * This benchmark creates and deletes objects in stack order
@@ -79,6 +79,16 @@
     typedef SkBenchmark INHERITED;
 };
 
+struct B {
+    int gStuff[10];
+#if OVERRIDE_NEW
+    void* operator new (size_t size) { return gBenchPool.allocate(size); }
+    void operator delete (void* mem) { if (mem) { return gBenchPool.release(mem); } }
+#endif
+    static GrMemoryPool gBenchPool;
+};
+GrMemoryPool B::gBenchPool(10 * (1 << 10), 10 * (1 << 10));
+
 /**
  * This benchmark creates objects and deletes them in random order
  */
@@ -98,12 +108,12 @@
         enum {
             kMaxObjects = 4 * (1 << 10),
         };
-        SkAutoTDelete<A> objects[kMaxObjects];
+        SkAutoTDelete<B> objects[kMaxObjects];
 
         for (int i = 0; i < loops; i++) {
             uint32_t idx = r.nextRangeU(0, kMaxObjects-1);
             if (NULL == objects[idx].get()) {
-                objects[idx].reset(new A);
+                objects[idx].reset(new B);
             } else {
                 objects[idx].free();
             }
@@ -114,6 +124,16 @@
     typedef SkBenchmark INHERITED;
 };
 
+struct C {
+    int gStuff[10];
+#if OVERRIDE_NEW
+    void* operator new (size_t size) { return gBenchPool.allocate(size); }
+    void operator delete (void* mem) { if (mem) { return gBenchPool.release(mem); } }
+#endif
+    static GrMemoryPool gBenchPool;
+};
+GrMemoryPool C::gBenchPool(10 * (1 << 10), 10 * (1 << 10));
+
 /**
  * This benchmark creates objects and deletes them in queue order
  */
@@ -133,11 +153,11 @@
 
     virtual void onDraw(const int loops, SkCanvas*) {
         SkRandom r;
-        A* objects[M];
+        C* objects[M];
         for (int i = 0; i < loops; i++) {
             uint32_t count = r.nextRangeU(0, M-1);
             for (uint32_t i = 0; i < count; i++) {
-                objects[i] = new A;
+                objects[i] = new C;
             }
             for (uint32_t i = 0; i < count; i++) {
                 delete objects[i];
diff --git a/bench/SkBenchmark.h b/bench/SkBenchmark.h
index f1e317d..bf28689 100644
--- a/bench/SkBenchmark.h
+++ b/bench/SkBenchmark.h
@@ -15,10 +15,8 @@
 
 #define DEF_BENCH(code)                                                 \
 namespace {                                                             \
-class SK_MACRO_APPEND_LINE(F_CLASS) : public SkBenchmarkFactory {       \
-    virtual SkBenchmark* operator()() const SK_OVERRIDE { code; }       \
-} SK_MACRO_APPEND_LINE(g_F_);                                           \
-BenchRegistry SK_MACRO_APPEND_LINE(g_R_)(&SK_MACRO_APPEND_LINE(g_F_));  \
+static SkBenchmark* SK_MACRO_APPEND_LINE(factory)(void*) { code; }      \
+BenchRegistry SK_MACRO_APPEND_LINE(g_R_)(SK_MACRO_APPEND_LINE(factory)); \
 }
 
 /*
@@ -136,13 +134,6 @@
     typedef SkRefCnt INHERITED;
 };
 
-class SkBenchmarkFactory : public SkRefCnt {
-public:
-    // Creates a new SkBenchmark that is owned by the caller on each call.
-    virtual SkBenchmark* operator()() const = 0;
-    virtual ~SkBenchmarkFactory() {}
-};
-
-typedef SkTRegistry<SkBenchmarkFactory*> BenchRegistry;
+typedef SkTRegistry<SkBenchmark*(*)(void*)> BenchRegistry;
 
 #endif
diff --git a/bench/SkGMBench.cpp b/bench/SkGMBench.cpp
index e1d8124..77d29a7 100644
--- a/bench/SkGMBench.cpp
+++ b/bench/SkGMBench.cpp
@@ -8,7 +8,7 @@
 #include "SkGMBench.h"
 
 SkGMBench::SkGMBench(skiagm::GM* gm) : fGM(gm) {
-    fName.printf("GM:%s", gm->shortName());
+    fName.printf("GM:%s", gm->getName());
 }
 
 SkGMBench::~SkGMBench() { delete fGM; }
diff --git a/bench/benchmain.cpp b/bench/benchmain.cpp
index 6eea11f..2401d67 100644
--- a/bench/benchmain.cpp
+++ b/bench/benchmain.cpp
@@ -58,7 +58,7 @@
         if (fBenches) {
             BenchRegistry::Factory f = fBenches->factory();
             fBenches = fBenches->next();
-            return (*f)();
+            return (*f)(NULL);
         }
 
         while (fGMs) {
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);
diff --git a/gm/gm.cpp b/gm/gm.cpp
index 82dd476..803874f 100644
--- a/gm/gm.cpp
+++ b/gm/gm.cpp
@@ -40,7 +40,7 @@
     this->onDrawBackground(canvas);
 }
 
-const char* GM::shortName() {
+const char* GM::getName() {
     if (fShortName.size() == 0) {
         fShortName = this->onShortName();
     }
diff --git a/gm/gm.h b/gm/gm.h
index 372b781..90de96f 100644
--- a/gm/gm.h
+++ b/gm/gm.h
@@ -66,7 +66,7 @@
         void drawContent(SkCanvas*);
 
         SkISize getISize() { return this->onISize(); }
-        const char* shortName();
+        const char* getName();
 
         uint32_t getFlags() const {
             return this->onGetFlags();
diff --git a/gm/gmmain.cpp b/gm/gmmain.cpp
index fb50b1e..acdc598 100644
--- a/gm/gmmain.cpp
+++ b/gm/gmmain.cpp
@@ -938,7 +938,7 @@
             errors.add(ErrorCombination(kIntentionallySkipped_ErrorType));
         } else {
             ExpectationsSource *expectationsSource = this->fExpectationsSource.get();
-            SkString nameWithExtension = make_shortname_plus_config(gm->shortName(), configName);
+            SkString nameWithExtension = make_shortname_plus_config(gm->getName(), configName);
             nameWithExtension.append(".");
             nameWithExtension.append(kPNG_FileExtension);
 
@@ -957,11 +957,11 @@
                  * See comments above complete_bitmap() for more detail.
                  */
                 Expectations expectations = expectationsSource->get(nameWithExtension.c_str());
-                if (this->ShouldIgnoreTest(gm->shortName())) {
+                if (this->ShouldIgnoreTest(gm->getName())) {
                     expectations.setIgnoreFailure(true);
                 }
                 errors.add(compare_to_expectations(expectations, *actualBitmapAndDigest,
-                                                   gm->shortName(), configName, "", true));
+                                                   gm->getName(), configName, "", true));
             } else {
                 // If we are running without expectations, we still want to
                 // record the actual results.
@@ -1069,7 +1069,7 @@
                            gm, gRec, gRec.fName, &bitmapAndDigest));
 
             if (writePath && (gRec.fFlags & kWrite_ConfigFlag)) {
-                path = make_bitmap_filename(writePath, gm->shortName(), gRec.fName,
+                path = make_bitmap_filename(writePath, gm->getName(), gRec.fName,
                                             "", bitmapAndDigest.fDigest);
                 errors.add(write_bitmap(path, bitmapAndDigest.fBitmap));
             }
@@ -1079,7 +1079,7 @@
             } else {
                 SkAutoTUnref<SkStreamAsset> documentStream(document.detachAsStream());
                 if (writePath && (gRec.fFlags & kWrite_ConfigFlag)) {
-                    path = make_filename(writePath, gm->shortName(), gRec.fName, "", "pdf");
+                    path = make_filename(writePath, gm->getName(), gRec.fName, "", "pdf");
                     errors.add(write_document(path, documentStream));
                 }
 
@@ -1091,7 +1091,7 @@
                                 documentStream.get(), &pdfBitmap);
                         if (!success) {
                             gm_fprintf(stderr, "FAILED to render PDF for %s using renderer %s\n",
-                                       gm->shortName(),
+                                       gm->getName(),
                                        pdfRasterizers[i]->fName);
                             continue;
                         }
@@ -1105,7 +1105,7 @@
                                    gm, gRec, configName.c_str(), &bitmapAndDigest));
 
                         if (writePath && (gRec.fFlags & kWrite_ConfigFlag)) {
-                            path = make_bitmap_filename(writePath, gm->shortName(),
+                            path = make_bitmap_filename(writePath, gm->getName(),
                                                         configName.c_str(),
                                                         "", bitmapAndDigest.fDigest);
                             errors.add(write_bitmap(path, bitmapAndDigest.fBitmap));
@@ -1123,7 +1123,7 @@
                            gm, gRec, gRec.fName, NULL));
 
             if (writePath && (gRec.fFlags & kWrite_ConfigFlag)) {
-                path = make_filename(writePath, gm->shortName(), gRec.fName, "", "xps");
+                path = make_filename(writePath, gm->getName(), gRec.fName, "", "xps");
                 errors.add(write_document(path, documentStream));
             }
         } else {
@@ -1160,14 +1160,14 @@
                 return kEmpty_ErrorCombination;
             }
             return compare_test_results_to_reference_bitmap(
-                gm->shortName(), gRec.fName, renderModeDescriptor, bitmap, &referenceBitmap);
+                gm->getName(), gRec.fName, renderModeDescriptor, bitmap, &referenceBitmap);
         }
         return kEmpty_ErrorCombination;
     }
 
     ErrorCombination test_pipe_playback(GM* gm, const ConfigData& gRec,
                                         const SkBitmap& referenceBitmap, bool simulateFailure) {
-        const SkString shortNamePlusConfig = make_shortname_plus_config(gm->shortName(),
+        const SkString shortNamePlusConfig = make_shortname_plus_config(gm->getName(),
                                                                         gRec.fName);
         ErrorCombination errors;
         for (size_t i = 0; i < SK_ARRAY_COUNT(gPipeWritingFlagCombos); ++i) {
@@ -1199,7 +1199,7 @@
                 complete_bitmap(&bitmap);
                 writer.endRecording();
                 errors.add(compare_test_results_to_reference_bitmap(
-                    gm->shortName(), gRec.fName, renderModeDescriptor.c_str(), bitmap,
+                    gm->getName(), gRec.fName, renderModeDescriptor.c_str(), bitmap,
                     &referenceBitmap));
                 if (!errors.isEmpty()) {
                     break;
@@ -1211,7 +1211,7 @@
 
     ErrorCombination test_tiled_pipe_playback(GM* gm, const ConfigData& gRec,
                                               const SkBitmap& referenceBitmap) {
-        const SkString shortNamePlusConfig = make_shortname_plus_config(gm->shortName(),
+        const SkString shortNamePlusConfig = make_shortname_plus_config(gm->getName(),
                                                                         gRec.fName);
         ErrorCombination errors;
         for (size_t i = 0; i < SK_ARRAY_COUNT(gPipeWritingFlagCombos); ++i) {
@@ -1237,7 +1237,7 @@
                 invokeGM(gm, pipeCanvas, false, false);
                 complete_bitmap(&bitmap);
                 writer.endRecording();
-                errors.add(compare_test_results_to_reference_bitmap(gm->shortName(), gRec.fName,
+                errors.add(compare_test_results_to_reference_bitmap(gm->getName(), gRec.fName,
                                                                     renderModeDescriptor.c_str(),
                                                                     bitmap, &referenceBitmap));
                 if (!errors.isEmpty()) {
@@ -1555,7 +1555,7 @@
                                     const SkTDArray<SkScalar> &tileGridReplayScales) {
     ErrorCombination errorsForAllModes;
     uint32_t gmFlags = gm->getFlags();
-    const SkString shortNamePlusConfig = gmmain.make_shortname_plus_config(gm->shortName(),
+    const SkString shortNamePlusConfig = gmmain.make_shortname_plus_config(gm->getName(),
                                                                            compareConfig.fName);
 
     SkPicture* pict = gmmain.generate_new_picture(gm, kNone_BbhType, 0);
@@ -1570,7 +1570,7 @@
             SkBitmap bitmap;
             gmmain.generate_image_from_picture(gm, compareConfig, pict, &bitmap);
             errorsForAllModes.add(gmmain.compare_test_results_to_reference_bitmap(
-                gm->shortName(), compareConfig.fName, renderModeDescriptor, bitmap,
+                gm->getName(), compareConfig.fName, renderModeDescriptor, bitmap,
                 &comparisonBitmap));
         }
     }
@@ -1587,7 +1587,7 @@
             SkBitmap bitmap;
             gmmain.generate_image_from_picture(gm, compareConfig, repict, &bitmap);
             errorsForAllModes.add(gmmain.compare_test_results_to_reference_bitmap(
-                gm->shortName(), compareConfig.fName, renderModeDescriptor, bitmap,
+                gm->getName(), compareConfig.fName, renderModeDescriptor, bitmap,
                 &comparisonBitmap));
         }
     }
@@ -1602,7 +1602,7 @@
         // write out their SkPictures to separate files rather than
         // overwriting each other.  But we should make sure it doesn't
         // break anybody.
-        SkString path = gmmain.make_filename(FLAGS_writePicturePath[0], gm->shortName(),
+        SkString path = gmmain.make_filename(FLAGS_writePicturePath[0], gm->getName(),
                                              compareConfig.fName, "", pictureSuffix);
         SkFILEWStream stream(path.c_str());
         pict->serialize(&stream);
@@ -1622,7 +1622,7 @@
             SkBitmap bitmap;
             gmmain.generate_image_from_picture(gm, compareConfig, pict, &bitmap);
             errorsForAllModes.add(gmmain.compare_test_results_to_reference_bitmap(
-                gm->shortName(), compareConfig.fName, renderModeDescriptor, bitmap,
+                gm->getName(), compareConfig.fName, renderModeDescriptor, bitmap,
                 &comparisonBitmap));
         }
     }
@@ -1657,7 +1657,7 @@
                 gmmain.generate_image_from_picture(gm, compareConfig, pict, &bitmap,
                                                    replayScale /*, true */);
                 errorsForAllModes.add(gmmain.compare_test_results_to_reference_bitmap(
-                    gm->shortName(), compareConfig.fName, renderModeDescriptor.c_str(), bitmap,
+                    gm->getName(), compareConfig.fName, renderModeDescriptor.c_str(), bitmap,
                     &comparisonBitmap));
             }
         }
@@ -1699,7 +1699,7 @@
 
     for (int i = 0; i < configs.count(); i++) {
         ConfigData config = gRec[configs[i]];
-        const SkString shortNamePlusConfig = gmmain.make_shortname_plus_config(gm->shortName(),
+        const SkString shortNamePlusConfig = gmmain.make_shortname_plus_config(gm->getName(),
                                                                                config.fName);
 
         // Skip any tests that we don't even need to try.
@@ -2316,7 +2316,7 @@
             moduloStr.printf("[%d.%d] ", gmIndex, moduloDivisor);
         }
 
-        const char* shortName = gm->shortName();
+        const char* shortName = gm->getName();
 
         if (SkCommandLineFlags::ShouldSkip(FLAGS_match, shortName)) {
             continue;
diff --git a/gyp/bench.gyp b/gyp/bench.gyp
index cd0cdc7..c2337f6 100644
--- a/gyp/bench.gyp
+++ b/gyp/bench.gyp
@@ -8,11 +8,6 @@
     {
       'target_name': 'bench',
       'type': 'executable',
-      'include_dirs' : [
-        '../src/core',
-        '../src/effects',
-        '../src/utils',
-      ],
       'dependencies': [
         'skia_lib.gyp:skia_lib',
         'bench_timer',
@@ -20,87 +15,10 @@
         'jsoncpp.gyp:jsoncpp',
       ],
       'sources': [
-        '../bench/AAClipBench.cpp',
-        '../bench/BicubicBench.cpp',
-        '../bench/BitmapBench.cpp',
-        '../bench/BitmapRectBench.cpp',
-        '../bench/BitmapScaleBench.cpp',
-        '../bench/BlurBench.cpp',
-        '../bench/BlurImageFilterBench.cpp',
-        '../bench/BlurRectBench.cpp',
-        '../bench/BlurRoundRectBench.cpp',
-        '../bench/ChartBench.cpp',
-        '../bench/ChecksumBench.cpp',
-        '../bench/ChromeBench.cpp',
-        '../bench/CmapBench.cpp',
-        '../bench/ColorFilterBench.cpp',
-        '../bench/ColorPrivBench.cpp',
-        '../bench/CoverageBench.cpp',
-        '../bench/DashBench.cpp',
-        '../bench/DecodeBench.cpp',
-        '../bench/DeferredCanvasBench.cpp',
-        '../bench/DeferredSurfaceCopyBench.cpp',
-        '../bench/DisplacementBench.cpp',
-        '../bench/FSRectBench.cpp',
-        '../bench/FontCacheBench.cpp',
-        '../bench/FontScalerBench.cpp',
-        '../bench/GameBench.cpp',
-        '../bench/GrMemoryPoolBench.cpp',
-        '../bench/GrResourceCacheBench.cpp',
-        '../bench/GradientBench.cpp',
-        '../bench/HairlinePathBench.cpp',
-        '../bench/ImageCacheBench.cpp',
-        '../bench/ImageDecodeBench.cpp',
-        '../bench/InterpBench.cpp',
-        '../bench/LightingBench.cpp',
-        '../bench/LineBench.cpp',
-        '../bench/MagnifierBench.cpp',
-        '../bench/MathBench.cpp',
-        '../bench/Matrix44Bench.cpp',
-        '../bench/MatrixBench.cpp',
-        '../bench/MatrixConvolutionBench.cpp',
-        '../bench/MemoryBench.cpp',
-        '../bench/MemsetBench.cpp',
-        '../bench/MergeBench.cpp',
-        '../bench/MorphologyBench.cpp',
-        '../bench/MutexBench.cpp',
-        '../bench/PathBench.cpp',
-        '../bench/PathIterBench.cpp',
-        '../bench/PathUtilsBench.cpp',
-        '../bench/PerlinNoiseBench.cpp',
-        '../bench/PicturePlaybackBench.cpp',
-        '../bench/PictureRecordBench.cpp',
-        '../bench/PremulAndUnpremulAlphaOpsBench.cpp',
-        '../bench/QuadTreeBench.cpp',
-        '../bench/RTreeBench.cpp',
-        '../bench/ReadPixBench.cpp',
-        '../bench/RectBench.cpp',
-        '../bench/RectoriBench.cpp',
-        '../bench/RefCntBench.cpp',
-        '../bench/RegionBench.cpp',
-        '../bench/RegionContainBench.cpp',
-        '../bench/RepeatTileBench.cpp',
-        '../bench/ScalarBench.cpp',
-        '../bench/ShaderMaskBench.cpp',
-        '../bench/SkipZeroesBench.cpp',
-        '../bench/SortBench.cpp',
-        '../bench/StackBench.cpp',
-        '../bench/StrokeBench.cpp',
-        '../bench/TableBench.cpp',
-        '../bench/TextBench.cpp',
-        '../bench/TileBench.cpp',
-        '../bench/VertBench.cpp',
-        '../bench/WritePixelsBench.cpp',
-        '../bench/WriterBench.cpp',
-        '../bench/XfermodeBench.cpp',
-
         '../bench/SkBenchLogger.cpp',
         '../bench/SkBenchLogger.h',
-        '../bench/SkBenchmark.cpp',
-        '../bench/SkBenchmark.h',
         '../bench/SkGMBench.cpp',
         '../bench/SkGMBench.h',
-
         '../bench/benchmain.cpp',
       ],
       'conditions': [
@@ -116,6 +34,7 @@
         ],
       ],
       'includes': [
+        'bench.gypi',
         'gmslides.gypi',
       ],
     },
diff --git a/gyp/bench.gypi b/gyp/bench.gypi
new file mode 100644
index 0000000..2d934d8
--- /dev/null
+++ b/gyp/bench.gypi
@@ -0,0 +1,88 @@
+{
+  'include_dirs': [
+    '../src/core',
+    '../src/effects',
+    '../src/utils',
+  ],
+  'dependencies': [
+    'skia_lib.gyp:skia_lib',
+  ],
+  'sources': [
+    '../bench/SkBenchmark.cpp',
+    '../bench/SkBenchmark.h',
+
+    '../bench/AAClipBench.cpp',
+    '../bench/BicubicBench.cpp',
+    '../bench/BitmapBench.cpp',
+    '../bench/BitmapRectBench.cpp',
+    '../bench/BitmapScaleBench.cpp',
+    '../bench/BlurBench.cpp',
+    '../bench/BlurImageFilterBench.cpp',
+    '../bench/BlurRectBench.cpp',
+    '../bench/BlurRoundRectBench.cpp',
+    '../bench/ChartBench.cpp',
+    '../bench/ChecksumBench.cpp',
+    '../bench/ChromeBench.cpp',
+    '../bench/CmapBench.cpp',
+    '../bench/ColorFilterBench.cpp',
+    '../bench/ColorPrivBench.cpp',
+    '../bench/CoverageBench.cpp',
+    '../bench/DashBench.cpp',
+    '../bench/DecodeBench.cpp',
+    '../bench/DeferredCanvasBench.cpp',
+    '../bench/DeferredSurfaceCopyBench.cpp',
+    '../bench/DisplacementBench.cpp',
+    '../bench/FSRectBench.cpp',
+    '../bench/FontCacheBench.cpp',
+    '../bench/FontScalerBench.cpp',
+    '../bench/GameBench.cpp',
+    '../bench/GrMemoryPoolBench.cpp',
+    '../bench/GrResourceCacheBench.cpp',
+    '../bench/GradientBench.cpp',
+    '../bench/HairlinePathBench.cpp',
+    '../bench/ImageCacheBench.cpp',
+    '../bench/ImageDecodeBench.cpp',
+    '../bench/InterpBench.cpp',
+    '../bench/LightingBench.cpp',
+    '../bench/LineBench.cpp',
+    '../bench/MagnifierBench.cpp',
+    '../bench/MathBench.cpp',
+    '../bench/Matrix44Bench.cpp',
+    '../bench/MatrixBench.cpp',
+    '../bench/MatrixConvolutionBench.cpp',
+    '../bench/MemoryBench.cpp',
+    '../bench/MemsetBench.cpp',
+    '../bench/MergeBench.cpp',
+    '../bench/MorphologyBench.cpp',
+    '../bench/MutexBench.cpp',
+    '../bench/PathBench.cpp',
+    '../bench/PathIterBench.cpp',
+    '../bench/PathUtilsBench.cpp',
+    '../bench/PerlinNoiseBench.cpp',
+    '../bench/PicturePlaybackBench.cpp',
+    '../bench/PictureRecordBench.cpp',
+    '../bench/PremulAndUnpremulAlphaOpsBench.cpp',
+    '../bench/QuadTreeBench.cpp',
+    '../bench/RTreeBench.cpp',
+    '../bench/ReadPixBench.cpp',
+    '../bench/RectBench.cpp',
+    '../bench/RectoriBench.cpp',
+    '../bench/RefCntBench.cpp',
+    '../bench/RegionBench.cpp',
+    '../bench/RegionContainBench.cpp',
+    '../bench/RepeatTileBench.cpp',
+    '../bench/ScalarBench.cpp',
+    '../bench/ShaderMaskBench.cpp',
+    '../bench/SkipZeroesBench.cpp',
+    '../bench/SortBench.cpp',
+    '../bench/StackBench.cpp',
+    '../bench/StrokeBench.cpp',
+    '../bench/TableBench.cpp',
+    '../bench/TextBench.cpp',
+    '../bench/TileBench.cpp',
+    '../bench/VertBench.cpp',
+    '../bench/WritePixelsBench.cpp',
+    '../bench/WriterBench.cpp',
+    '../bench/XfermodeBench.cpp',
+  ],
+}
diff --git a/gyp/dm.gyp b/gyp/dm.gyp
index 55f5f9b..db50993 100644
--- a/gyp/dm.gyp
+++ b/gyp/dm.gyp
@@ -7,6 +7,7 @@
         'target_name': 'dm',
         'type': 'executable',
         'include_dirs': [
+            '../bench',
             '../dm',
             '../gm',
             '../tests',
@@ -20,12 +21,14 @@
             '../tools',
         ],
         'includes': [
+            'bench.gypi',
             'gmslides.gypi',
             'pathops_unittest.gypi',
             'tests.gypi',
         ],
         'sources': [
             '../dm/DM.cpp',
+            '../dm/DMBenchTask.cpp',
             '../dm/DMCpuTask.cpp',
             '../dm/DMExpectationsTask.cpp',
             '../dm/DMGpuTask.cpp',
diff --git a/samplecode/GMSampleView.h b/samplecode/GMSampleView.h
index 6791c34..40d11ab 100644
--- a/samplecode/GMSampleView.h
+++ b/samplecode/GMSampleView.h
@@ -36,7 +36,7 @@
     virtual bool onQuery(SkEvent* evt) {
         if (SampleCode::TitleQ(*evt)) {
             SkString name("GM:");
-            name.append(fGM->shortName());
+            name.append(fGM->getName());
             SampleCode::TitleR(evt, name.c_str());
             return true;
         }