aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar mtklein <mtklein@chromium.org>2014-09-03 15:34:37 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2014-09-03 15:34:37 -0700
commit406654be7a930b484159f5bca107d3b11d8a9ede (patch)
tree11d0b7ba5e6757e55c735743e649e61696f81571
parentf8b4563e15d7567020b46d52ea43a9d4433c556a (diff)
SkThreadPool ~~> SkTaskGroup
SkTaskGroup is like SkThreadPool except the threads stay in one global pool. Each SkTaskGroup itself is tiny (4 bytes) and its wait() method applies only to tasks add()ed to that instance, not the whole thread pool. This means we don't need to bring up new thread pools when tests themselves want to use multithreading (e.g. pathops, quilt). We just create a new SkTaskGroup and wait for that to complete. This should be more efficient, and allow us to expand where we use threads to really latency sensitive places. E.g. we can probably now use these in nanobench for CPU .skp rendering. Now that all threads are sharing the same pool, I think we can remove most of the custom mechanism pathops tests use to control threading. They'll just ride on the global pool with all other tests now. This (temporarily?) removes the GPU multithreading feature from DM, which we don't use. On my desktop, DM runs a little faster (57s -> 55s) in Debug, and a lot faster in Release (36s -> 24s). The bots show speedups of similar proportions, cutting more than a minute off the N4/Release and Win7/Debug runtimes. BUG=skia: Committed: https://skia.googlesource.com/skia/+/9c7207b5dc71dc5a96a2eb107d401133333d5b6f R=caryclark@google.com, bsalomon@google.com, bungeman@google.com, mtklein@google.com, reed@google.com Author: mtklein@chromium.org Review URL: https://codereview.chromium.org/531653002
-rw-r--r--dm/DM.cpp6
-rw-r--r--dm/DMQuiltTask.cpp6
-rw-r--r--dm/DMTask.cpp20
-rw-r--r--dm/DMTask.h9
-rw-r--r--dm/DMTaskRunner.cpp18
-rw-r--r--dm/DMTaskRunner.h13
-rw-r--r--dm/DMTestTask.cpp8
-rw-r--r--dm/DMTestTask.h1
-rw-r--r--gyp/dm.gypi2
-rwxr-xr-xgyp/pathops_skpclip.gyp3
-rw-r--r--gyp/pathops_unittest.gyp1
-rw-r--r--gyp/tools.gyp1
-rw-r--r--gyp/utils.gypi1
-rw-r--r--src/utils/SkRunnable.h13
-rw-r--r--src/utils/SkTaskGroup.cpp143
-rw-r--r--src/utils/SkTaskGroup.h36
-rw-r--r--src/utils/SkThreadPool.h221
-rw-r--r--tests/OnceTest.cpp10
-rw-r--r--tests/PathOpsExtendedTest.cpp5
-rw-r--r--tests/PathOpsExtendedTest.h2
-rw-r--r--tests/PathOpsOpCubicThreadedTest.cpp4
-rwxr-xr-xtests/PathOpsOpLoopThreadedTest.cpp6
-rw-r--r--tests/PathOpsOpRectThreadedTest.cpp4
-rw-r--r--tests/PathOpsQuadLineIntersectionThreadedTest.cpp4
-rwxr-xr-xtests/PathOpsSimplifyDegenerateThreadedTest.cpp4
-rw-r--r--tests/PathOpsSimplifyQuadThreadedTest.cpp4
-rwxr-xr-xtests/PathOpsSimplifyQuadralateralsThreadedTest.cpp4
-rw-r--r--tests/PathOpsSimplifyRectThreadedTest.cpp4
-rwxr-xr-xtests/PathOpsSimplifyTrianglesThreadedTest.cpp4
-rwxr-xr-xtests/PathOpsSkpClipTest.cpp44
-rw-r--r--tests/PathOpsThreadedCommon.cpp6
-rw-r--r--tests/PathOpsThreadedCommon.h6
-rw-r--r--tests/PathOpsTightBoundsTest.cpp8
-rw-r--r--tests/SkpSkGrTest.cpp15
-rw-r--r--tests/Test.cpp4
-rw-r--r--tests/Test.h1
-rw-r--r--tests/skia_test.cpp10
-rw-r--r--tools/flags/SkCommonFlags.cpp7
-rw-r--r--tools/flags/SkCommonFlags.h1
-rw-r--r--tools/iOSShell.cpp1
-rw-r--r--tools/skpdiff/SkDiffContext.cpp17
-rw-r--r--tools/skpdiff/skpdiff_main.cpp2
42 files changed, 293 insertions, 386 deletions
diff --git a/dm/DM.cpp b/dm/DM.cpp
index 09f0ce8f26..b330445186 100644
--- a/dm/DM.cpp
+++ b/dm/DM.cpp
@@ -8,6 +8,7 @@
#include "SkGraphics.h"
#include "SkPicture.h"
#include "SkString.h"
+#include "SkTaskGroup.h"
#include "Test.h"
#include "gm.h"
#include "sk_tool_utils.h"
@@ -41,7 +42,6 @@ using skiatest::TestRegistry;
static const char kGpuAPINameGL[] = "gl";
static const char kGpuAPINameGLES[] = "gles";
-DEFINE_int32(gpuThreads, 1, "Threads for GPU work.");
DEFINE_string2(expectations, r, "",
"If a directory, compare generated images against images under this path. "
"If a file, compare generated images against JSON expectations at this path."
@@ -192,6 +192,7 @@ int dm_main();
int dm_main() {
SetupCrashHandler();
SkAutoGraphics ag;
+ SkTaskGroup::Enabler enabled(FLAGS_threads);
if (FLAGS_dryRun) {
FLAGS_verbose = true;
@@ -233,7 +234,8 @@ int dm_main() {
SkDebugf("%d GMs x %d configs, %d tests, %d pictures\n",
gms.count(), configs.count(), tests.count(), skps.count());
DM::Reporter reporter;
- DM::TaskRunner tasks(FLAGS_threads, FLAGS_gpuThreads);
+
+ DM::TaskRunner tasks;
kick_off_tests(tests, &reporter, &tasks);
kick_off_gms(gms, configs, gpuAPI, *expectations, &reporter, &tasks);
kick_off_skps(skps, &reporter, &tasks);
diff --git a/dm/DMQuiltTask.cpp b/dm/DMQuiltTask.cpp
index 6961f09671..a824de0f15 100644
--- a/dm/DMQuiltTask.cpp
+++ b/dm/DMQuiltTask.cpp
@@ -5,7 +5,7 @@
#include "SkBBHFactory.h"
#include "SkCommandLineFlags.h"
#include "SkPicture.h"
-#include "SkThreadPool.h"
+#include "SkTaskGroup.h"
DEFINE_bool(quilt, true, "If true, draw GM via a picture into a quilt of small tiles and compare.");
DEFINE_int32(quiltTile, 256, "Dimension of (square) quilt tile.");
@@ -96,11 +96,11 @@ void QuiltTask::draw() {
canvas.flush();
} else {
// Draw tiles in parallel into the same bitmap, simulating aggressive impl-side painting.
- SkThreadPool pool(SkThreadPool::kThreadPerCore);
+ SkTaskGroup tg;
for (int y = 0; y < tiles_needed(full.height(), FLAGS_quiltTile); y++) {
for (int x = 0; x < tiles_needed(full.width(), FLAGS_quiltTile); x++) {
// Deletes itself when done.
- pool.add(new Tile(x, y, *recorded, &full));
+ tg.add(new Tile(x, y, *recorded, &full));
}
}
}
diff --git a/dm/DMTask.cpp b/dm/DMTask.cpp
index 05eda4ea20..5ceb53b062 100644
--- a/dm/DMTask.cpp
+++ b/dm/DMTask.cpp
@@ -38,8 +38,8 @@ void Task::finish() {
fReporter->printStatus(this->name(), SkTime::GetMSecs() - fStart);
}
-void Task::spawnChildNext(CpuTask* task) {
- fTaskRunner->addNext(task);
+void Task::reallySpawnChild(CpuTask* task) {
+ fTaskRunner->add(task);
}
CpuTask::CpuTask(Reporter* reporter, TaskRunner* taskRunner) : Task(reporter, taskRunner) {}
@@ -56,32 +56,32 @@ void CpuTask::run() {
void CpuTask::spawnChild(CpuTask* task) {
// Run children serially on this (CPU) thread. This tends to save RAM and is usually no slower.
- // Calling spawnChildNext() is nearly equivalent, but it'd pointlessly contend on the
- // threadpool; spawnChildNext() is most useful when you want to change threadpools.
+ // Calling reallySpawnChild() is nearly equivalent, but it'd pointlessly contend on the
+ // threadpool; reallySpawnChild() is most useful when you want to change threadpools.
task->run();
}
GpuTask::GpuTask(Reporter* reporter, TaskRunner* taskRunner) : Task(reporter, taskRunner) {}
-void GpuTask::run(GrContextFactory& factory) {
+void GpuTask::run(GrContextFactory* factory) {
if (FLAGS_gpu && !this->shouldSkip()) {
this->start();
- if (!FLAGS_dryRun) this->draw(&factory);
+ if (!FLAGS_dryRun) this->draw(factory);
this->finish();
if (FLAGS_abandonGpuContext) {
- factory.abandonContexts();
+ factory->abandonContexts();
}
if (FLAGS_resetGpuContext || FLAGS_abandonGpuContext) {
- factory.destroyContexts();
+ factory->destroyContexts();
}
}
SkDELETE(this);
}
void GpuTask::spawnChild(CpuTask* task) {
- // Really spawn a new task so it runs on the CPU threadpool instead of the GPU one we're on now.
+ // Spawn a new task so it runs on the CPU threadpool instead of the GPU one we're on now.
// It goes on the front of the queue to minimize the time we must hold reference bitmaps in RAM.
- this->spawnChildNext(task);
+ this->reallySpawnChild(task);
}
} // namespace DM
diff --git a/dm/DMTask.h b/dm/DMTask.h
index 32bb9486f5..3f41b497ba 100644
--- a/dm/DMTask.h
+++ b/dm/DMTask.h
@@ -1,9 +1,10 @@
#ifndef DMTask_DEFINED
#define DMTask_DEFINED
-#include "DMReporter.h"
#include "DMGpuSupport.h"
+#include "DMReporter.h"
#include "SkRunnable.h"
+#include "SkTaskGroup.h"
#include "SkTime.h"
// DM will run() these tasks on one of two threadpools.
@@ -36,7 +37,7 @@ protected:
void fail(const char* msg = NULL);
void finish();
- void spawnChildNext(CpuTask* task); // For now we don't allow GPU child tasks.
+ void reallySpawnChild(CpuTask* task); // For now we don't allow GPU child tasks.
private:
Reporter* fReporter; // Unowned.
@@ -57,12 +58,12 @@ public:
void spawnChild(CpuTask* task);
};
-class GpuTask : public Task, public SkTRunnable<GrContextFactory> {
+class GpuTask : public Task {
public:
GpuTask(Reporter* reporter, TaskRunner* taskRunner);
virtual ~GpuTask() {}
- void run(GrContextFactory&) SK_OVERRIDE;
+ void run(GrContextFactory*);
virtual void draw(GrContextFactory*) = 0;
void spawnChild(CpuTask* task);
diff --git a/dm/DMTaskRunner.cpp b/dm/DMTaskRunner.cpp
index 8a0bc838e1..92381a7a7e 100644
--- a/dm/DMTaskRunner.cpp
+++ b/dm/DMTaskRunner.cpp
@@ -3,19 +3,15 @@
namespace DM {
-TaskRunner::TaskRunner(int cpuThreads, int gpuThreads) : fCpu(cpuThreads), fGpu(gpuThreads) {}
-
-void TaskRunner::add(CpuTask* task) { fCpu.add(task); }
-void TaskRunner::addNext(CpuTask* task) { fCpu.addNext(task); }
-void TaskRunner::add(GpuTask* task) { fGpu.add(task); }
+void TaskRunner::add(CpuTask* task) { fCpuWork.add(task); }
+void TaskRunner::add(GpuTask* task) { fGpuWork.push(task); }
void TaskRunner::wait() {
- // These wait calls block until each threadpool is done. We don't allow
- // spawning new child GPU tasks, so we can wait for that first knowing
- // we'll never try to add to it later. Same can't be said of the CPU pool:
- // both CPU and GPU tasks can spawn off new CPU work, so we wait for that last.
- fGpu.wait();
- fCpu.wait();
+ GrContextFactory factory;
+ for (int i = 0; i < fGpuWork.count(); i++) {
+ fGpuWork[i]->run(&factory);
+ }
+ fCpuWork.wait();
}
} // namespace DM
diff --git a/dm/DMTaskRunner.h b/dm/DMTaskRunner.h
index dd1440ed9a..3d4e491b9c 100644
--- a/dm/DMTaskRunner.h
+++ b/dm/DMTaskRunner.h
@@ -2,12 +2,10 @@
#define DMTaskRunner_DEFINED
#include "DMGpuSupport.h"
-#include "SkThreadPool.h"
+#include "SkTDArray.h"
+#include "SkTaskGroup.h"
#include "SkTypes.h"
-// TaskRunner runs Tasks on one of two threadpools depending on the need for a GrContextFactory.
-// It's typically a good idea to run fewer GPU threads than CPU threads (go nuts with those).
-
namespace DM {
class CpuTask;
@@ -15,16 +13,15 @@ class GpuTask;
class TaskRunner : SkNoncopyable {
public:
- explicit TaskRunner(int cpuThreads, int gpuThreads);
+ TaskRunner() {}
void add(CpuTask* task);
- void addNext(CpuTask* task);
void add(GpuTask* task);
void wait();
private:
- SkTThreadPool<void> fCpu;
- SkTThreadPool<GrContextFactory> fGpu;
+ SkTaskGroup fCpuWork;
+ SkTDArray<GpuTask*> fGpuWork;
};
} // namespace DM
diff --git a/dm/DMTestTask.cpp b/dm/DMTestTask.cpp
index 9e7f41e7d0..ad0c3fb4f3 100644
--- a/dm/DMTestTask.cpp
+++ b/dm/DMTestTask.cpp
@@ -3,17 +3,11 @@
#include "SkCommandLineFlags.h"
#include "SkCommonFlags.h"
-// When PathOps threaded tests get going, they're briefly a big consumer of lots of RAM.
-// We disable the internal threading there by default on 32-bit builds.
-static const bool is32Bit = sizeof(void*) == 4;
-
-DEFINE_bool2(pathOpsExtended, x, false, "Run extended pathOps tests.");
-DEFINE_bool2(pathOpsSingleThread, z, is32Bit, "Disallow pathOps tests from using threads.");
+DEFINE_bool2(pathOpsExtended, x, false, "Run extended pathOps tests.");
namespace DM {
bool TestReporter::allowExtendedTest() const { return FLAGS_pathOpsExtended; }
-bool TestReporter::allowThreaded() const { return !FLAGS_pathOpsSingleThread; }
bool TestReporter::verbose() const { return FLAGS_veryVerbose; }
static SkString test_name(const char* name) {
diff --git a/dm/DMTestTask.h b/dm/DMTestTask.h
index a65f096c58..ceb0e12e96 100644
--- a/dm/DMTestTask.h
+++ b/dm/DMTestTask.h
@@ -19,7 +19,6 @@ public:
private:
virtual bool allowExtendedTest() const SK_OVERRIDE;
- virtual bool allowThreaded() const SK_OVERRIDE;
virtual bool verbose() const SK_OVERRIDE;
virtual void onReportFailed(const SkString& desc) SK_OVERRIDE {
diff --git a/gyp/dm.gypi b/gyp/dm.gypi
index 1ecccd82b2..0d8652fd22 100644
--- a/gyp/dm.gypi
+++ b/gyp/dm.gypi
@@ -47,6 +47,8 @@
'../gm/gm.cpp',
'../gm/gm_expectations.cpp',
+ '../src/utils/SkTaskGroup.cpp',
+
'../src/pipe/utils/SamplePipeControllers.cpp',
'../src/utils/debugger/SkDebugCanvas.cpp',
'../src/utils/debugger/SkDrawCommand.cpp',
diff --git a/gyp/pathops_skpclip.gyp b/gyp/pathops_skpclip.gyp
index a1e51d65f8..32a909bd47 100755
--- a/gyp/pathops_skpclip.gyp
+++ b/gyp/pathops_skpclip.gyp
@@ -15,7 +15,7 @@
'../src/pipe/utils',
'../src/utils',
],
- 'dependencies': [
+ 'dependencies': [
'flags.gyp:flags',
'skia_lib.gyp:skia_lib',
'tools.gyp:crash_handler',
@@ -24,6 +24,7 @@
'sources': [
'../tests/PathOpsDebug.cpp',
'../tests/PathOpsSkpClipTest.cpp',
+ '../src/utils/SkTaskGroup.cpp',
],
'conditions': [
[ 'skia_android_framework == 1', {
diff --git a/gyp/pathops_unittest.gyp b/gyp/pathops_unittest.gyp
index d3152d2cf3..98e74bd54c 100644
--- a/gyp/pathops_unittest.gyp
+++ b/gyp/pathops_unittest.gyp
@@ -20,6 +20,7 @@
'../tests/PathOpsDebug.cpp',
'../tests/PathOpsOpLoopThreadedTest.cpp',
'../tests/skia_test.cpp',
+ '../src/utils/SkTaskGroup.cpp',
],
'conditions': [
[ 'skia_android_framework == 1', {
diff --git a/gyp/tools.gyp b/gyp/tools.gyp
index 66b84db66f..ce397f3cf3 100644
--- a/gyp/tools.gyp
+++ b/gyp/tools.gyp
@@ -167,6 +167,7 @@
'../tools/skpdiff/SkImageDiffer.cpp',
'../tools/skpdiff/SkPMetric.cpp',
'../tools/skpdiff/skpdiff_util.cpp',
+ '../src/utils/SkTaskGroup.cpp',
],
'include_dirs': [
'../src/core/', # needed for SkTLList.h
diff --git a/gyp/utils.gypi b/gyp/utils.gypi
index 9156b847c8..e62d287bb9 100644
--- a/gyp/utils.gypi
+++ b/gyp/utils.gypi
@@ -10,7 +10,6 @@
# Classes for a threadpool.
'<(skia_src_path)/utils/SkCondVar.h',
'<(skia_src_path)/utils/SkRunnable.h',
- '<(skia_src_path)/utils/SkThreadPool.h',
'<(skia_src_path)/utils/SkCondVar.cpp',
'<(skia_include_path)/utils/SkBoundaryPatch.h',
diff --git a/src/utils/SkRunnable.h b/src/utils/SkRunnable.h
index 5acf4dbc61..7a93b60c89 100644
--- a/src/utils/SkRunnable.h
+++ b/src/utils/SkRunnable.h
@@ -8,18 +8,9 @@
#ifndef SkRunnable_DEFINED
#define SkRunnable_DEFINED
-template <typename T>
-struct SkTRunnable {
- virtual ~SkTRunnable() {};
- virtual void run(T&) = 0;
-};
-
-template <>
-struct SkTRunnable<void> {
- virtual ~SkTRunnable() {};
+struct SkRunnable {
+ virtual ~SkRunnable() {};
virtual void run() = 0;
};
-typedef SkTRunnable<void> SkRunnable;
-
#endif
diff --git a/src/utils/SkTaskGroup.cpp b/src/utils/SkTaskGroup.cpp
new file mode 100644
index 0000000000..e7de6becd8
--- /dev/null
+++ b/src/utils/SkTaskGroup.cpp
@@ -0,0 +1,143 @@
+#include "SkTaskGroup.h"
+
+#include "SkCondVar.h"
+#include "SkTDArray.h"
+#include "SkThread.h"
+#include "SkThreadUtils.h"
+
+#if defined(SK_BUILD_FOR_WIN32)
+ static inline int num_cores() {
+ SYSTEM_INFO sysinfo;
+ GetSystemInfo(&sysinfo);
+ return sysinfo.dwNumberOfProcessors;
+ }
+#else
+ #include <unistd.h>
+ static inline int num_cores() {
+ return (int) sysconf(_SC_NPROCESSORS_ONLN);
+ }
+#endif
+
+namespace {
+
+class ThreadPool : SkNoncopyable {
+public:
+ static void Add(SkRunnable* task, int32_t* pending) {
+ SkASSERT(gGlobal); // If this fails, see SkTaskGroup::Enabler.
+ gGlobal->add(task, pending);
+ }
+
+ static void Wait(int32_t* pending) {
+ SkASSERT(gGlobal); // If this fails, see SkTaskGroup::Enabler.
+ while (sk_acquire_load(pending) > 0) { // Pairs with sk_atomic_dec here or in Loop.
+ // Lend a hand until our SkTaskGroup of interest is done.
+ Work work;
+ {
+ AutoLock lock(&gGlobal->fReady);
+ if (gGlobal->fWork.isEmpty()) {
+ // Someone has picked up all the work (including ours). How nice of them!
+ // (They may still be working on it, so we can't assert *pending == 0 here.)
+ continue;
+ }
+ gGlobal->fWork.pop(&work);
+ }
+ // This Work isn't necessarily part of our SkTaskGroup of interest, but that's fine.
+ // We threads gotta stick together. We're always making forward progress.
+ work.task->run();
+ sk_atomic_dec(work.pending); // Release pairs with the sk_acquire_load() just above.
+ }
+ }
+
+private:
+ struct AutoLock {
+ AutoLock(SkCondVar* c) : fC(c) { fC->lock(); }
+ ~AutoLock() { fC->unlock(); }
+ private:
+ SkCondVar* fC;
+ };
+
+ struct Work {
+ SkRunnable* task; // A task to ->run(),
+ int32_t* pending; // then sk_atomic_dec(pending) afterwards.
+ };
+
+ explicit ThreadPool(int threads) : fDraining(false) {
+ if (threads == 0) {
+ threads = num_cores();
+ }
+ for (int i = 0; i < threads; i++) {
+ fThreads.push(SkNEW_ARGS(SkThread, (&ThreadPool::Loop, this)));
+ fThreads.top()->start();
+ }
+ }
+
+ ~ThreadPool() {
+ SkASSERT(fWork.isEmpty()); // All SkTaskGroups should be destroyed by now.
+ {
+ AutoLock lock(&fReady);
+ fDraining = true;
+ fReady.broadcast();
+ }
+ for (int i = 0; i < fThreads.count(); i++) {
+ fThreads[i]->join();
+ }
+ SkASSERT(fWork.isEmpty()); // Can't hurt to double check.
+ fThreads.deleteAll();
+ }
+
+ void add(SkRunnable* task, int32_t* pending) {
+ Work work = { task, pending };
+ sk_atomic_inc(pending); // No barrier needed.
+ {
+ AutoLock lock(&fReady);
+ fWork.push(work);
+ fReady.signal();
+ }
+ }
+
+ static void Loop(void* arg) {
+ ThreadPool* pool = (ThreadPool*)arg;
+ Work work;
+ while (true) {
+ {
+ AutoLock lock(&pool->fReady);
+ while (pool->fWork.isEmpty()) {
+ if (pool->fDraining) {
+ return;
+ }
+ pool->fReady.wait();
+ }
+ pool->fWork.pop(&work);
+ }
+ work.task->run();
+ sk_atomic_dec(work.pending); // Release pairs with sk_acquire_load() in Wait().
+ }
+ }
+
+ SkTDArray<Work> fWork;
+ SkTDArray<SkThread*> fThreads;
+ SkCondVar fReady;
+ bool fDraining;
+
+ static ThreadPool* gGlobal;
+ friend struct SkTaskGroup::Enabler;
+};
+ThreadPool* ThreadPool::gGlobal = NULL;
+
+} // namespace
+
+SkTaskGroup::Enabler::Enabler(int threads) {
+ SkASSERT(ThreadPool::gGlobal == NULL);
+ ThreadPool::gGlobal = SkNEW_ARGS(ThreadPool, (threads));
+}
+
+SkTaskGroup::Enabler::~Enabler() {
+ SkASSERT(ThreadPool::gGlobal != NULL);
+ SkDELETE(ThreadPool::gGlobal);
+}
+
+SkTaskGroup::SkTaskGroup() : fPending(0) {}
+
+void SkTaskGroup::add(SkRunnable* task) { ThreadPool::Add(task, &fPending); }
+void SkTaskGroup::wait() { ThreadPool::Wait(&fPending); }
+
diff --git a/src/utils/SkTaskGroup.h b/src/utils/SkTaskGroup.h
new file mode 100644
index 0000000000..d9e6f597d0
--- /dev/null
+++ b/src/utils/SkTaskGroup.h
@@ -0,0 +1,36 @@
+/*
+ * 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 SkTaskGroup_DEFINED
+#define SkTaskGroup_DEFINED
+
+#include "SkTypes.h"
+#include "SkRunnable.h"
+
+class SkTaskGroup : SkNoncopyable {
+public:
+ // Create one of these in main() to enable SkTaskGroups globally.
+ struct Enabler : SkNoncopyable {
+ explicit Enabler(int threads = 0); // Default is system-reported core count.
+ ~Enabler();
+ };
+
+ SkTaskGroup();
+ ~SkTaskGroup() { this->wait(); }
+
+ // Add a task to this SkTaskGroup. It will likely run() on another thread.
+ void add(SkRunnable*);
+
+ // Block until all Tasks previously add()ed to this SkTaskGroup have run().
+ // You may safely reuse this SkTaskGroup after wait() returns.
+ void wait();
+
+private:
+ /*atomic*/ int32_t fPending;
+};
+
+#endif//SkTaskGroup_DEFINED
diff --git a/src/utils/SkThreadPool.h b/src/utils/SkThreadPool.h
deleted file mode 100644
index c99c5c4188..0000000000
--- a/src/utils/SkThreadPool.h
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SkThreadPool_DEFINED
-#define SkThreadPool_DEFINED
-
-#include "SkCondVar.h"
-#include "SkRunnable.h"
-#include "SkTDArray.h"
-#include "SkTInternalLList.h"
-#include "SkThreadUtils.h"
-#include "SkTypes.h"
-
-#if defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_ANDROID)
-# include <unistd.h>
-#endif
-
-// Returns the number of cores on this machine.
-static inline int num_cores() {
-#if defined(SK_BUILD_FOR_WIN32)
- SYSTEM_INFO sysinfo;
- GetSystemInfo(&sysinfo);
- return sysinfo.dwNumberOfProcessors;
-#elif defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_ANDROID)
- return (int) sysconf(_SC_NPROCESSORS_ONLN);
-#else
- return 1;
-#endif
-}
-
-template <typename T>
-class SkTThreadPool {
-public:
- /**
- * Create a threadpool with count threads, or one thread per core if kThreadPerCore.
- */
- static const int kThreadPerCore = -1;
- explicit SkTThreadPool(int count);
- ~SkTThreadPool();
-
- /**
- * Queues up an SkRunnable to run when a thread is available, or synchronously if count is 0.
- * Does not take ownership. NULL is a safe no-op. If T is not void, the runnable will be passed
- * a reference to a T on the thread's local stack.
- */
- void add(SkTRunnable<T>*);
-
- /**
- * Same as add, but adds the runnable as the very next to run rather than enqueueing it.
- */
- void addNext(SkTRunnable<T>*);
-
- /**
- * Block until all added SkRunnables have completed. Once called, calling add() is undefined.
- */
- void wait();
-
- private:
- struct LinkedRunnable {
- SkTRunnable<T>* fRunnable; // Unowned.
- SK_DECLARE_INTERNAL_LLIST_INTERFACE(LinkedRunnable);
- };
-
- enum State {
- kRunning_State, // Normal case. We've been constructed and no one has called wait().
- kWaiting_State, // wait has been called, but there still might be work to do or being done.
- kHalting_State, // There's no work to do and no thread is busy. All threads can shut down.
- };
-
- void addSomewhere(SkTRunnable<T>* r,
- void (SkTInternalLList<LinkedRunnable>::*)(LinkedRunnable*));
-
- SkTInternalLList<LinkedRunnable> fQueue;
- SkCondVar fReady;
- SkTDArray<SkThread*> fThreads;
- State fState;
- int fBusyThreads;
-
- static void Loop(void*); // Static because we pass in this.
-};
-
-template <typename T>
-SkTThreadPool<T>::SkTThreadPool(int count) : fState(kRunning_State), fBusyThreads(0) {
- if (count < 0) {
- count = num_cores();
- }
- // Create count threads, all running SkTThreadPool::Loop.
- for (int i = 0; i < count; i++) {
- SkThread* thread = SkNEW_ARGS(SkThread, (&SkTThreadPool::Loop, this));
- *fThreads.append() = thread;
- thread->start();
- }
-}
-
-template <typename T>
-SkTThreadPool<T>::~SkTThreadPool() {
- if (kRunning_State == fState) {
- this->wait();
- }
-}
-
-namespace SkThreadPoolPrivate {
-
-template <typename T>
-struct ThreadLocal {
- void run(SkTRunnable<T>* r) { r->run(data); }
- T data;
-};
-
-template <>
-struct ThreadLocal<void> {
- void run(SkTRunnable<void>* r) { r->run(); }
-};
-
-} // namespace SkThreadPoolPrivate
-
-template <typename T>
-void SkTThreadPool<T>::addSomewhere(SkTRunnable<T>* r,
- void (SkTInternalLList<LinkedRunnable>::* f)(LinkedRunnable*)) {
- if (r == NULL) {
- return;
- }
-
- if (fThreads.isEmpty()) {
- SkThreadPoolPrivate::ThreadLocal<T> threadLocal;
- threadLocal.run(r);
- return;
- }
-
- LinkedRunnable* linkedRunnable = SkNEW(LinkedRunnable);
- linkedRunnable->fRunnable = r;
- fReady.lock();
- SkASSERT(fState != kHalting_State); // Shouldn't be able to add work when we're halting.
- (fQueue.*f)(linkedRunnable);
- fReady.signal();
- fReady.unlock();
-}
-
-template <typename T>
-void SkTThreadPool<T>::add(SkTRunnable<T>* r) {
- this->addSomewhere(r, &SkTInternalLList<LinkedRunnable>::addToTail);
-}
-
-template <typename T>
-void SkTThreadPool<T>::addNext(SkTRunnable<T>* r) {
- this->addSomewhere(r, &SkTInternalLList<LinkedRunnable>::addToHead);
-}
-
-
-template <typename T>
-void SkTThreadPool<T>::wait() {
- fReady.lock();
- fState = kWaiting_State;
- fReady.broadcast();
- fReady.unlock();
-
- // Wait for all threads to stop.
- for (int i = 0; i < fThreads.count(); i++) {
- fThreads[i]->join();
- SkDELETE(fThreads[i]);
- }
- SkASSERT(fQueue.isEmpty());
-}
-
-template <typename T>
-/*static*/ void SkTThreadPool<T>::Loop(void* arg) {
- // The SkTThreadPool passes itself as arg to each thread as they're created.
- SkTThreadPool<T>* pool = static_cast<SkTThreadPool<T>*>(arg);
- SkThreadPoolPrivate::ThreadLocal<T> threadLocal;
-
- while (true) {
- // We have to be holding the lock to read the queue and to call wait.
- pool->fReady.lock();
- while(pool->fQueue.isEmpty()) {
- // Does the client want to stop and are all the threads ready to stop?
- // If so, we move into the halting state, and whack all the threads so they notice.
- if (kWaiting_State == pool->fState && pool->fBusyThreads == 0) {
- pool->fState = kHalting_State;
- pool->fReady.broadcast();
- }
- // Any time we find ourselves in the halting state, it's quitting time.
- if (kHalting_State == pool->fState) {
- pool->fReady.unlock();
- return;
- }
- // wait yields the lock while waiting, but will have it again when awoken.
- pool->fReady.wait();
- }
- // We've got the lock back here, no matter if we ran wait or not.
-
- // The queue is not empty, so we have something to run. Claim it.
- LinkedRunnable* r = pool->fQueue.head();
-
- pool->fQueue.remove(r);
-
- // Having claimed our SkRunnable, we now give up the lock while we run it.
- // Otherwise, we'd only ever do work on one thread at a time, which rather
- // defeats the point of this code.
- pool->fBusyThreads++;
- pool->fReady.unlock();
-
- // OK, now really do the work.
- threadLocal.run(r->fRunnable);
- SkDELETE(r);
-
- // Let everyone know we're not busy.
- pool->fReady.lock();
- pool->fBusyThreads--;
- pool->fReady.unlock();
- }
-
- SkASSERT(false); // Unreachable. The only exit happens when pool->fState is kHalting_State.
-}
-
-typedef SkTThreadPool<void> SkThreadPool;
-
-#endif
diff --git a/tests/OnceTest.cpp b/tests/OnceTest.cpp
index 389d257b73..192abaaee3 100644
--- a/tests/OnceTest.cpp
+++ b/tests/OnceTest.cpp
@@ -6,7 +6,7 @@
*/
#include "SkOnce.h"
-#include "SkThreadPool.h"
+#include "SkTaskGroup.h"
#include "Test.h"
static void add_five(int* x) {
@@ -42,7 +42,7 @@ public:
};
DEF_TEST(SkOnce_Multithreaded, r) {
- const int kTasks = 16, kThreads = 4;
+ const int kTasks = 16;
// Make a bunch of tasks that will race to be the first to add six to x.
Racer racers[kTasks];
@@ -54,11 +54,11 @@ DEF_TEST(SkOnce_Multithreaded, r) {
}
// Let them race.
- SkThreadPool pool(kThreads);
+ SkTaskGroup tg;
for (int i = 0; i < kTasks; i++) {
- pool.add(&racers[i]);
+ tg.add(&racers[i]);
}
- pool.wait();
+ tg.wait();
// Only one should have done the +=.
REPORTER_ASSERT(r, 6 == x);
diff --git a/tests/PathOpsExtendedTest.cpp b/tests/PathOpsExtendedTest.cpp
index 05d00045b9..f90b9fec69 100644
--- a/tests/PathOpsExtendedTest.cpp
+++ b/tests/PathOpsExtendedTest.cpp
@@ -14,8 +14,8 @@
#include "SkPaint.h"
#include "SkRTConf.h"
#include "SkStream.h"
+#include "SkTaskGroup.h"
#include "SkThread.h"
-#include "SkThreadPool.h"
#ifdef SK_BUILD_FOR_MAC
#include <sys/sysctl.h>
@@ -542,7 +542,7 @@ bool testThreadedPathOp(skiatest::Reporter* reporter, const SkPath& a, const SkP
SK_DECLARE_STATIC_MUTEX(gMutex);
-int initializeTests(skiatest::Reporter* reporter, const char* test) {
+void initializeTests(skiatest::Reporter* reporter, const char* test) {
#if 0 // doesn't work yet
SK_CONF_SET("images.jpeg.suppressDecoderWarnings", true);
SK_CONF_SET("images.png.suppressDecoderWarnings", true);
@@ -566,7 +566,6 @@ int initializeTests(skiatest::Reporter* reporter, const char* test) {
}
}
}
- return reporter->allowThreaded() ? SkThreadPool::kThreadPerCore : 1;
}
void outputProgress(char* ramStr, const char* pathStr, SkPath::FillType pathFillType) {
diff --git a/tests/PathOpsExtendedTest.h b/tests/PathOpsExtendedTest.h
index 5f3413c572..a854410139 100644
--- a/tests/PathOpsExtendedTest.h
+++ b/tests/PathOpsExtendedTest.h
@@ -36,7 +36,7 @@ extern bool testSimplify(SkPath& path, bool useXor, SkPath& out, PathOpsThreadSt
const char* pathStr);
extern bool testSimplify(skiatest::Reporter* reporter, const SkPath& path, const char* filename);
-int initializeTests(skiatest::Reporter* reporter, const char* testName);
+void initializeTests(skiatest::Reporter* reporter, const char* testName);
void outputProgress(char* ramStr, const char* pathStr, SkPath::FillType );
void outputProgress(char* ramStr, const char* pathStr, SkPathOp op);
diff --git a/tests/PathOpsOpCubicThreadedTest.cpp b/tests/PathOpsOpCubicThreadedTest.cpp
index 889ade0487..751ccc5f1b 100644
--- a/tests/PathOpsOpCubicThreadedTest.cpp
+++ b/tests/PathOpsOpCubicThreadedTest.cpp
@@ -67,8 +67,8 @@ static void testOpCubicsMain(PathOpsThreadState* data) {
}
DEF_TEST(PathOpsOpCubicsThreaded, reporter) {
- int threadCount = initializeTests(reporter, "cubicOp");
- PathOpsThreadedTestRunner testRunner(reporter, threadCount);
+ initializeTests(reporter, "cubicOp");
+ PathOpsThreadedTestRunner testRunner(reporter);
for (int a = 0; a < 6; ++a) { // outermost
for (int b = a + 1; b < 7; ++b) {
for (int c = 0 ; c < 6; ++c) {
diff --git a/tests/PathOpsOpLoopThreadedTest.cpp b/tests/PathOpsOpLoopThreadedTest.cpp
index 71efff3edc..3f316d1fe9 100755
--- a/tests/PathOpsOpLoopThreadedTest.cpp
+++ b/tests/PathOpsOpLoopThreadedTest.cpp
@@ -62,8 +62,8 @@ static void testOpLoopsMain(PathOpsThreadState* data) {
}
DEF_TEST(PathOpsOpLoopsThreaded, reporter) {
- int threadCount = initializeTests(reporter, "cubicOp");
- PathOpsThreadedTestRunner testRunner(reporter, threadCount);
+ initializeTests(reporter, "cubicOp");
+ PathOpsThreadedTestRunner testRunner(reporter);
for (int a = 0; a < 6; ++a) { // outermost
for (int b = a + 1; b < 7; ++b) {
for (int c = 0 ; c < 6; ++c) {
@@ -81,7 +81,7 @@ finish:
}
DEF_TEST(PathOpsOpLoops, reporter) {
- (void) initializeTests(reporter, "cubicOp");
+ initializeTests(reporter, "cubicOp");
PathOpsThreadState state;
state.fReporter = reporter;
SkBitmap bitmap;
diff --git a/tests/PathOpsOpRectThreadedTest.cpp b/tests/PathOpsOpRectThreadedTest.cpp
index 3d07d74bb0..1b6e4e86b9 100644
--- a/tests/PathOpsOpRectThreadedTest.cpp
+++ b/tests/PathOpsOpRectThreadedTest.cpp
@@ -74,8 +74,8 @@ static void testPathOpsRectsMain(PathOpsThreadState* data)
}
DEF_TEST(PathOpsRectsThreaded, reporter) {
- int threadCount = initializeTests(reporter, "testOp");
- PathOpsThreadedTestRunner testRunner(reporter, threadCount);
+ initializeTests(reporter, "testOp");
+ PathOpsThreadedTestRunner testRunner(reporter);
for (int a = 0; a < 6; ++a) { // outermost
for (int b = a + 1; b < 7; ++b) {
for (int c = 0 ; c < 6; ++c) {
diff --git a/tests/PathOpsQuadLineIntersectionThreadedTest.cpp b/tests/PathOpsQuadLineIntersectionThreadedTest.cpp
index fd7581fa58..7e33b7b374 100644
--- a/tests/PathOpsQuadLineIntersectionThreadedTest.cpp
+++ b/tests/PathOpsQuadLineIntersectionThreadedTest.cpp
@@ -111,8 +111,8 @@ static void testQuadLineIntersectMain(PathOpsThreadState* data)
}
DEF_TEST(PathOpsQuadLineIntersectionThreaded, reporter) {
- int threadCount = initializeTests(reporter, "testQuadLineIntersect");
- PathOpsThreadedTestRunner testRunner(reporter, threadCount);
+ initializeTests(reporter, "testQuadLineIntersect");
+ PathOpsThreadedTestRunner testRunner(reporter);
for (int a = 0; a < 16; ++a) {
for (int b = 0 ; b < 16; ++b) {
for (int c = 0 ; c < 16; ++c) {
diff --git a/tests/PathOpsSimplifyDegenerateThreadedTest.cpp b/tests/PathOpsSimplifyDegenerateThreadedTest.cpp
index 5cd3c35d8a..8e8c58bf44 100755
--- a/tests/PathOpsSimplifyDegenerateThreadedTest.cpp
+++ b/tests/PathOpsSimplifyDegenerateThreadedTest.cpp
@@ -68,8 +68,8 @@ static void testSimplifyDegeneratesMain(PathOpsThreadState* data) {
}
DEF_TEST(PathOpsSimplifyDegeneratesThreaded, reporter) {
- int threadCount = initializeTests(reporter, "testDegenerates");
- PathOpsThreadedTestRunner testRunner(reporter, threadCount);
+ initializeTests(reporter, "testDegenerates");
+ PathOpsThreadedTestRunner testRunner(reporter);
for (int a = 0; a < 16; ++a) {
int ax = a & 0x03;
int ay = a >> 2;
diff --git a/tests/PathOpsSimplifyQuadThreadedTest.cpp b/tests/PathOpsSimplifyQuadThreadedTest.cpp
index dbbec3e3e6..3c92cca217 100644
--- a/tests/PathOpsSimplifyQuadThreadedTest.cpp
+++ b/tests/PathOpsSimplifyQuadThreadedTest.cpp
@@ -74,8 +74,8 @@ static void testSimplifyQuadsMain(PathOpsThreadState* data)
}
DEF_TEST(PathOpsSimplifyQuadsThreaded, reporter) {
- int threadCount = initializeTests(reporter, "testQuads");
- PathOpsThreadedTestRunner testRunner(reporter, threadCount);
+ initializeTests(reporter, "testQuads");
+ PathOpsThreadedTestRunner testRunner(reporter);
int a = 0;
for (; a < 16; ++a) {
for (int b = a ; b < 16; ++b) {
diff --git a/tests/PathOpsSimplifyQuadralateralsThreadedTest.cpp b/tests/PathOpsSimplifyQuadralateralsThreadedTest.cpp
index afa9200389..f8e9a6e3dc 100755
--- a/tests/PathOpsSimplifyQuadralateralsThreadedTest.cpp
+++ b/tests/PathOpsSimplifyQuadralateralsThreadedTest.cpp
@@ -76,8 +76,8 @@ static void testSimplifyQuadralateralsMain(PathOpsThreadState* data)
}
DEF_TEST(PathOpsSimplifyQuadralateralsThreaded, reporter) {
- int threadCount = initializeTests(reporter, "testQuadralaterals");
- PathOpsThreadedTestRunner testRunner(reporter, threadCount);
+ initializeTests(reporter, "testQuadralaterals");
+ PathOpsThreadedTestRunner testRunner(reporter);
for (int a = 0; a < 16; ++a) {
for (int b = a ; b < 16; ++b) {
for (int c = b ; c < 16; ++c) {
diff --git a/tests/PathOpsSimplifyRectThreadedTest.cpp b/tests/PathOpsSimplifyRectThreadedTest.cpp
index 9e6a5eaf03..52a78ece84 100644
--- a/tests/PathOpsSimplifyRectThreadedTest.cpp
+++ b/tests/PathOpsSimplifyRectThreadedTest.cpp
@@ -187,8 +187,8 @@ static void testSimplify4x4RectsMain(PathOpsThreadState* data)
}
DEF_TEST(PathOpsSimplifyRectsThreaded, reporter) {
- int threadCount = initializeTests(reporter, "testLine");
- PathOpsThreadedTestRunner testRunner(reporter, threadCount);
+ initializeTests(reporter, "testLine");
+ PathOpsThreadedTestRunner testRunner(reporter);
for (int a = 0; a < 8; ++a) { // outermost
for (int b = a ; b < 8; ++b) {
for (int c = b ; c < 8; ++c) {
diff --git a/tests/PathOpsSimplifyTrianglesThreadedTest.cpp b/tests/PathOpsSimplifyTrianglesThreadedTest.cpp
index b5d6508846..ee0ca2bcaa 100755
--- a/tests/PathOpsSimplifyTrianglesThreadedTest.cpp
+++ b/tests/PathOpsSimplifyTrianglesThreadedTest.cpp
@@ -73,8 +73,8 @@ static void testSimplifyTrianglesMain(PathOpsThreadState* data) {
}
DEF_TEST(PathOpsSimplifyTrianglesThreaded, reporter) {
- int threadCount = initializeTests(reporter, "testTriangles");
- PathOpsThreadedTestRunner testRunner(reporter, threadCount);
+ initializeTests(reporter, "testTriangles");
+ PathOpsThreadedTestRunner testRunner(reporter);
for (int a = 0; a < 15; ++a) {
int ax = a & 0x03;
int ay = a >> 2;
diff --git a/tests/PathOpsSkpClipTest.cpp b/tests/PathOpsSkpClipTest.cpp
index cdc3c1fcd9..0769141685 100755
--- a/tests/PathOpsSkpClipTest.cpp
+++ b/tests/PathOpsSkpClipTest.cpp
@@ -20,8 +20,8 @@
#include "SkString.h"
#include "SkTArray.h"
#include "SkTDArray.h"
+#include "SkTaskGroup.h"
#include "SkTemplates.h"
-#include "SkThreadPool.h"
#include "SkTime.h"
__SK_FORCE_IMAGE_DECODER_LINKING;
@@ -90,14 +90,14 @@ static SkString get_in_path(int dirNo, const char* filename) {
}
if (filename) {
path.appendf("%s%s", PATH_SLASH, filename);
- if (!sk_exists(path.c_str())) {
+ if (!sk_exists(path.c_str())) {
SkDebugf("could not read %s\n", path.c_str());
return SkString();
}
}
return path;
}
-
+
static void make_recursive_dir(const SkString& path) {
if (sk_exists(path.c_str())) {
return;
@@ -129,7 +129,7 @@ static SkString get_out_path(int dirNo, const char* dirName) {
make_recursive_dir(path);
return path;
}
-
+
static SkString get_sum_path(const char* dirName) {
SkString path;
SkASSERT(dirName);
@@ -166,12 +166,12 @@ struct TestResult {
fTestStep = kCompareBits;
fScale = 1;
}
-
+
void init(int dirNo, const SkString& filename) {
fDirNo = dirNo;
strcpy(fFilename, filename.c_str());
fTestStep = kCompareBits;
- fScale = 1;
+ fScale = 1;
}
SkString status() {
@@ -204,7 +204,7 @@ struct TestResult {
}
void testOne();
-
+
char fFilename[kMaxLength];
TestStep fTestStep;
int fDirNo;
@@ -245,13 +245,8 @@ struct TestState {
};
struct TestRunner {
- TestRunner(int threadCount)
- : fNumThreads(threadCount) {
- }
-
~TestRunner();
void render();
- int fNumThreads;
SkTDArray<class TestRunnable*> fRunnables;
};
@@ -300,9 +295,9 @@ TestRunner::~TestRunner() {
}
void TestRunner::render() {
- SkThreadPool pool(fNumThreads);
+ SkTaskGroup tg;
for (int index = 0; index < fRunnables.count(); ++ index) {
- pool.add(fRunnables[index]);
+ tg.add(fRunnables[index]);
}
}
@@ -531,18 +526,12 @@ DEFINE_string2(dir, d, NULL, "range of directories (e.g., 1-100)");
DEFINE_string2(skp, s, NULL, "skp to test");
DEFINE_bool2(single, z, false, "run tests on a single thread internally.");
DEFINE_int32(testIndex, 0, "override local test index (PathOpsSkpClipOneOff only).");
-DEFINE_int32(threads, SkThreadPool::kThreadPerCore,
- "Run threadsafe tests on a threadpool with this many threads.");
DEFINE_bool2(verbose, v, false, "enable verbose output.");
static bool verbose() {
return FLAGS_verbose;
}
-static int getThreadCount() {
- return FLAGS_single ? 1 : FLAGS_threads;
-}
-
class Dirs {
public:
Dirs() {
@@ -616,7 +605,7 @@ public:
}
return NULL;
}
-
+
void set(const SkCommandLineFlags::StringArray& names) {
fNames = &names;
}
@@ -626,7 +615,7 @@ private:
const SkCommandLineFlags::StringArray* fNames;
} gNames;
-static bool buildTestDir(int dirNo, int firstDirNo,
+static bool buildTestDir(int dirNo, int firstDirNo,
SkTDArray<TestResult>* tests, SkTDArray<SortByName*>* sorted) {
SkString dirName = get_out_path(dirNo, outStatusDir);
if (!dirName.size()) {
@@ -792,8 +781,7 @@ static void encodeFound(TestState& state) {
}
}
}
- int threadCount = getThreadCount();
- TestRunner testRunner(threadCount);
+ TestRunner testRunner;
for (int index = 0; index < state.fPixelWorst.count(); ++index) {
const TestResult& result = state.fPixelWorst[index];
SkString filename(result.fFilename);
@@ -865,8 +853,7 @@ static void testSkpClipMain(TestState* data) {
DEF_TEST(PathOpsSkpClipThreaded) {
gDirs.setDefault();
initTest();
- int threadCount = getThreadCount();
- TestRunner testRunner(threadCount);
+ TestRunner testRunner;
int dirNo;
gDirs.reset();
while ((dirNo = gDirs.next()) > 0) {
@@ -889,7 +876,7 @@ DEF_TEST(PathOpsSkpClipThreaded) {
}
encodeFound(state);
}
-
+
static bool buildTests(SkTDArray<TestResult>* tests, SkTDArray<SortByName*>* sorted) {
int firstDirNo = gDirs.first();
int dirNo;
@@ -912,8 +899,7 @@ DEF_TEST(PathOpsSkpClipUberThreaded) {
if (!buildTests(tests.get(), sorted.get())) {
return;
}
- int threadCount = getThreadCount();
- TestRunner testRunner(threadCount);
+ TestRunner testRunner;
int dirNo;
gDirs.reset();
while ((dirNo = gDirs.next()) > 0) {
diff --git a/tests/PathOpsThreadedCommon.cpp b/tests/PathOpsThreadedCommon.cpp
index ac4cd6ba62..0adde915e0 100644
--- a/tests/PathOpsThreadedCommon.cpp
+++ b/tests/PathOpsThreadedCommon.cpp
@@ -7,7 +7,7 @@
#include "PathOpsExtendedTest.h"
#include "PathOpsThreadedCommon.h"
-#include "SkThreadPool.h"
+#include "SkTaskGroup.h"
PathOpsThreadedTestRunner::~PathOpsThreadedTestRunner() {
for (int index = 0; index < fRunnables.count(); index++) {
@@ -16,8 +16,8 @@ PathOpsThreadedTestRunner::~PathOpsThreadedTestRunner() {
}
void PathOpsThreadedTestRunner::render() {
- SkThreadPool pool(fNumThreads);
+ SkTaskGroup tg;
for (int index = 0; index < fRunnables.count(); ++ index) {
- pool.add(fRunnables[index]);
+ tg.add(fRunnables[index]);
}
}
diff --git a/tests/PathOpsThreadedCommon.h b/tests/PathOpsThreadedCommon.h
index a638cd2fdf..124921e389 100644
--- a/tests/PathOpsThreadedCommon.h
+++ b/tests/PathOpsThreadedCommon.h
@@ -33,17 +33,13 @@ struct PathOpsThreadState {
class PathOpsThreadedTestRunner {
public:
- PathOpsThreadedTestRunner(skiatest::Reporter* reporter, int threadCount)
- : fNumThreads(threadCount)
- , fReporter(reporter) {
- }
+ PathOpsThreadedTestRunner(skiatest::Reporter* reporter) : fReporter(reporter) {}
~PathOpsThreadedTestRunner();
void render();
public:
- int fNumThreads;
SkTDArray<PathOpsThreadedRunnable*> fRunnables;
skiatest::Reporter* fReporter;
};
diff --git a/tests/PathOpsTightBoundsTest.cpp b/tests/PathOpsTightBoundsTest.cpp
index 09f962296f..cea37520b1 100644
--- a/tests/PathOpsTightBoundsTest.cpp
+++ b/tests/PathOpsTightBoundsTest.cpp
@@ -35,8 +35,8 @@ static void testTightBoundsLines(PathOpsThreadState* data) {
}
DEF_TEST(PathOpsTightBoundsLines, reporter) {
- int threadCount = initializeTests(reporter, "tightBoundsLines");
- PathOpsThreadedTestRunner testRunner(reporter, threadCount);
+ initializeTests(reporter, "tightBoundsLines");
+ PathOpsThreadedTestRunner testRunner(reporter);
int outerCount = reporter->allowExtendedTest() ? 100 : 1;
for (int index = 0; index < outerCount; ++index) {
for (int idx2 = 0; idx2 < 10; ++idx2) {
@@ -110,8 +110,8 @@ static void testTightBoundsQuads(PathOpsThreadState* data) {
}
DEF_TEST(PathOpsTightBoundsQuads, reporter) {
- int threadCount = initializeTests(reporter, "tightBoundsQuads");
- PathOpsThreadedTestRunner testRunner(reporter, threadCount);
+ initializeTests(reporter, "tightBoundsQuads");
+ PathOpsThreadedTestRunner testRunner(reporter);
int outerCount = reporter->allowExtendedTest() ? 100 : 1;
for (int index = 0; index < outerCount; ++index) {
for (int idx2 = 0; idx2 < 10; ++idx2) {
diff --git a/tests/SkpSkGrTest.cpp b/tests/SkpSkGrTest.cpp
index c1883a9890..c882654650 100644
--- a/tests/SkpSkGrTest.cpp
+++ b/tests/SkpSkGrTest.cpp
@@ -23,7 +23,7 @@
#include "SkString.h"
#include "SkTArray.h"
#include "SkTDArray.h"
-#include "SkThreadPool.h"
+#include "SkTaskGroup.h"
#include "SkTime.h"
#include "Test.h"
@@ -125,14 +125,12 @@ struct SkpSkGrThreadState {
};
struct SkpSkGrThreadedTestRunner {
- SkpSkGrThreadedTestRunner(skiatest::Reporter* reporter, int threadCount)
- : fNumThreads(threadCount)
- , fReporter(reporter) {
+ SkpSkGrThreadedTestRunner(skiatest::Reporter* reporter)
+ : fReporter(reporter) {
}
~SkpSkGrThreadedTestRunner();
void render();
- int fNumThreads;
SkTDArray<SkpSkGrThreadedRunnable*> fRunnables;
skiatest::Reporter* fReporter;
};
@@ -164,9 +162,9 @@ SkpSkGrThreadedTestRunner::~SkpSkGrThreadedTestRunner() {
}
void SkpSkGrThreadedTestRunner::render() {
- SkThreadPool pool(fNumThreads);
+ SkTaskGroup tg;
for (int index = 0; index < fRunnables.count(); ++ index) {
- pool.add(fRunnables[index]);
+ tg.add(fRunnables[index]);
}
}
@@ -676,8 +674,7 @@ DEF_TEST(SkpSkGrThreaded, reporter) {
if (!initTest()) {
return;
}
- int threadCount = reporter->allowThreaded() ? 3 : 1;
- SkpSkGrThreadedTestRunner testRunner(reporter, threadCount);
+ SkpSkGrThreadedTestRunner testRunner(reporter);
for (int dirIndex = 1; dirIndex <= 100; ++dirIndex) {
SkString pictDir = make_in_dir_name(dirIndex);
if (pictDir.size() == 0) {
diff --git a/tests/Test.cpp b/tests/Test.cpp
index 20afd45561..d0147e1e4a 100644
--- a/tests/Test.cpp
+++ b/tests/Test.cpp
@@ -75,10 +75,6 @@ protected:
return fReporter->allowExtendedTest();
}
- virtual bool allowThreaded() const SK_OVERRIDE {
- return fReporter->allowThreaded();
- }
-
virtual void bumpTestCount() SK_OVERRIDE {
fReporter->bumpTestCount();
}
diff --git a/tests/Test.h b/tests/Test.h
index 72b0bee126..6c85b32bce 100644
--- a/tests/Test.h
+++ b/tests/Test.h
@@ -32,7 +32,6 @@ namespace skiatest {
void endTest(Test*);
virtual bool allowExtendedTest() const { return false; }
- virtual bool allowThreaded() const { return false; }
virtual bool verbose() const { return false; }
virtual void bumpTestCount() { sk_atomic_inc(&fTestCount); }
diff --git a/tests/skia_test.cpp b/tests/skia_test.cpp
index 97ac29b0fd..0058215ccf 100644
--- a/tests/skia_test.cpp
+++ b/tests/skia_test.cpp
@@ -12,8 +12,8 @@
#include "SkGraphics.h"
#include "SkOSFile.h"
#include "SkTArray.h"
+#include "SkTaskGroup.h"
#include "SkTemplates.h"
-#include "SkThreadPool.h"
#include "SkTime.h"
#include "Test.h"
@@ -54,7 +54,6 @@ public:
explicit DebugfReporter(int total) : fDone(0), fTotal(total) {}
virtual bool allowExtendedTest() const SK_OVERRIDE { return FLAGS_extendedTest; }
- virtual bool allowThreaded() const SK_OVERRIDE { return !FLAGS_single; }
virtual bool verbose() const SK_OVERRIDE { return FLAGS_veryVerbose; }
protected:
@@ -175,7 +174,8 @@ int test_main() {
int32_t failCount = 0;
int skipCount = 0;
- SkThreadPool threadpool(FLAGS_threads);
+ SkTaskGroup::Enabler enabled(FLAGS_threads);
+ SkTaskGroup cpuTests;
SkTArray<Test*> gpuTests; // Always passes ownership to an SkTestRunnable
DebugfReporter reporter(toRun);
@@ -186,7 +186,7 @@ int test_main() {
} else if (test->isGPUTest()) {
gpuTests.push_back() = test.detach();
} else {
- threadpool.add(SkNEW_ARGS(SkTestRunnable, (test.detach(), &failCount)));
+ cpuTests.add(SkNEW_ARGS(SkTestRunnable, (test.detach(), &failCount)));
}
}
@@ -204,7 +204,7 @@ int test_main() {
}
// Block until threaded tests finish.
- threadpool.wait();
+ cpuTests.wait();
if (FLAGS_verbose) {
SkDebugf("\nFinished %d tests, %d failures, %d skipped. (%d internal tests)",
diff --git a/tools/flags/SkCommonFlags.cpp b/tools/flags/SkCommonFlags.cpp
index 4d08ba6340..7776c36a59 100644
--- a/tools/flags/SkCommonFlags.cpp
+++ b/tools/flags/SkCommonFlags.cpp
@@ -6,7 +6,6 @@
*/
#include "SkCommonFlags.h"
-#include "SkThreadPool.h"
DEFINE_string(config, "565 8888 pdf gpu nonrendering angle",
"Options: 565 8888 pdf gpu nonrendering msaa4 msaa16 nvprmsaa4 nvprmsaa16 "
@@ -42,12 +41,10 @@ DEFINE_bool(resetGpuContext, true, "Reset the GrContext before running each test
DEFINE_bool(abandonGpuContext, false, "Abandon the GrContext after running each test. "
"Implies --resetGpuContext.");
-DEFINE_bool2(single, z, false, "run tests on a single thread internally.");
-
DEFINE_string(skps, "skps", "Directory to read skps from.");
-DEFINE_int32(threads, SkThreadPool::kThreadPerCore,
- "run threadsafe tests on a threadpool with this many threads.");
+DEFINE_int32(threads, 0, "Run threadsafe tests on a threadpool with this many threads, "
+ "defaulting to one thread per core.");
DEFINE_bool2(verbose, v, false, "enable verbose output from the test driver.");
diff --git a/tools/flags/SkCommonFlags.h b/tools/flags/SkCommonFlags.h
index b45ef0738a..ecd4148448 100644
--- a/tools/flags/SkCommonFlags.h
+++ b/tools/flags/SkCommonFlags.h
@@ -20,7 +20,6 @@ DECLARE_string(match);
DECLARE_bool(quiet);
DECLARE_bool(resetGpuContext);
DECLARE_bool(abandonGpuContext);
-DECLARE_bool(single);
DECLARE_string(skps);
DECLARE_int32(threads);
DECLARE_string(resourcePath);
diff --git a/tools/iOSShell.cpp b/tools/iOSShell.cpp
index 49be34d65b..8656e645aa 100644
--- a/tools/iOSShell.cpp
+++ b/tools/iOSShell.cpp
@@ -12,7 +12,6 @@
#include "SkCanvas.h"
#include "SkCommonFlags.h"
#include "SkGraphics.h"
-#include "SkThreadPool.h"
#include "SkWindow.h"
#include "sk_tool_utils.h"
diff --git a/tools/skpdiff/SkDiffContext.cpp b/tools/skpdiff/SkDiffContext.cpp
index 42d20de19d..78d8400968 100644
--- a/tools/skpdiff/SkDiffContext.cpp
+++ b/tools/skpdiff/SkDiffContext.cpp
@@ -12,7 +12,7 @@
#include "SkSize.h"
#include "SkStream.h"
#include "SkTDict.h"
-#include "SkThreadPool.h"
+#include "SkTaskGroup.h"
// from the tools directory for replace_char(...)
#include "picture_utils.h"
@@ -24,7 +24,6 @@
SkDiffContext::SkDiffContext() {
fDiffers = NULL;
fDifferCount = 0;
- fThreadCount = SkThreadPool::kThreadPerCore;
}
SkDiffContext::~SkDiffContext() {
@@ -87,7 +86,7 @@ static SkString get_common_prefix(const SkString& a, const SkString& b) {
}
static SkString get_combined_name(const SkString& a, const SkString& b) {
- // Note (stephana): We must keep this function in sync with
+ // Note (stephana): We must keep this function in sync with
// getImageDiffRelativeUrl() in static/loader.js (under rebaseline_server).
SkString result = a;
result.append("-vs-");
@@ -238,7 +237,7 @@ void SkDiffContext::diffDirectories(const char baselinePath[], const char testPa
return;
}
- SkThreadPool threadPool(fThreadCount);
+ SkTaskGroup tg;
SkTArray<SkThreadedDiff> runnableDiffs;
runnableDiffs.reset(baselineEntries.count());
@@ -253,13 +252,11 @@ void SkDiffContext::diffDirectories(const char baselinePath[], const char testPa
if (sk_exists(testFile.c_str()) && !sk_isdir(testFile.c_str())) {
// Queue up the comparison with the differ
runnableDiffs[x].setup(this, baselineFile, testFile);
- threadPool.add(&runnableDiffs[x]);
+ tg.add(&runnableDiffs[x]);
} else {
SkDebugf("Baseline file \"%s\" has no corresponding test file\n", baselineFile.c_str());
}
}
-
- threadPool.wait();
}
@@ -284,16 +281,14 @@ void SkDiffContext::diffPatterns(const char baselinePattern[], const char testPa
return;
}
- SkThreadPool threadPool(fThreadCount);
+ SkTaskGroup tg;
SkTArray<SkThreadedDiff> runnableDiffs;
runnableDiffs.reset(baselineEntries.count());
for (int x = 0; x < baselineEntries.count(); x++) {
runnableDiffs[x].setup(this, baselineEntries[x], testEntries[x]);
- threadPool.add(&runnableDiffs[x]);
+ tg.add(&runnableDiffs[x]);
}
-
- threadPool.wait();
}
void SkDiffContext::outputRecords(SkWStream& stream, bool useJSONP) {
diff --git a/tools/skpdiff/skpdiff_main.cpp b/tools/skpdiff/skpdiff_main.cpp
index 6c40552d33..9c1f37f243 100644
--- a/tools/skpdiff/skpdiff_main.cpp
+++ b/tools/skpdiff/skpdiff_main.cpp
@@ -27,6 +27,7 @@
#include "SkGraphics.h"
#include "SkStream.h"
#include "SkTDArray.h"
+#include "SkTaskGroup.h"
#include "SkDifferentPixelsMetric.h"
#include "SkDiffContext.h"
@@ -125,6 +126,7 @@ int tool_main(int argc, char * argv[]) {
// Needed by various Skia components
SkAutoGraphics ag;
+ SkTaskGroup::Enabler enabled;
if (FLAGS_list) {
SkDebugf("Available Metrics:\n");