summaryrefslogtreecommitdiffstats
path: root/cc/base
diff options
context:
space:
mode:
authorreveman@chromium.org <reveman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-14 01:06:55 +0000
committerreveman@chromium.org <reveman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-14 01:06:55 +0000
commit24891e6990f1f302594a2ce1e3c6609dbbb9b7dd (patch)
treece76dace03060f745817e90ad01a0c9d3b4bee3d /cc/base
parentd1ef0ec9bf488963a1c5b0700af051a872ebc454 (diff)
downloadchromium_src-24891e6990f1f302594a2ce1e3c6609dbbb9b7dd.zip
chromium_src-24891e6990f1f302594a2ce1e3c6609dbbb9b7dd.tar.gz
chromium_src-24891e6990f1f302594a2ce1e3c6609dbbb9b7dd.tar.bz2
cc: Move WorkerPool from cc/base to cc/resources.
R=jamesr BUG= Review URL: https://chromiumcodereview.appspot.com/17004002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@206263 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'cc/base')
-rw-r--r--cc/base/worker_pool.cc461
-rw-r--r--cc/base/worker_pool.h154
-rw-r--r--cc/base/worker_pool_perftest.cc244
-rw-r--r--cc/base/worker_pool_unittest.cc206
4 files changed, 0 insertions, 1065 deletions
diff --git a/cc/base/worker_pool.cc b/cc/base/worker_pool.cc
deleted file mode 100644
index bb910e9..0000000
--- a/cc/base/worker_pool.cc
+++ /dev/null
@@ -1,461 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/base/worker_pool.h"
-
-#if defined(OS_ANDROID)
-// TODO(epenner): Move thread priorities to base. (crbug.com/170549)
-#include <sys/resource.h>
-#endif
-
-#include <map>
-
-#include "base/bind.h"
-#include "base/containers/hash_tables.h"
-#include "base/debug/trace_event.h"
-#include "base/strings/stringprintf.h"
-#include "base/threading/simple_thread.h"
-#include "base/threading/thread_restrictions.h"
-#include "cc/base/scoped_ptr_deque.h"
-
-namespace cc {
-
-namespace internal {
-
-WorkerPoolTask::WorkerPoolTask()
- : did_schedule_(false),
- did_run_(false),
- did_complete_(false) {
-}
-
-WorkerPoolTask::WorkerPoolTask(TaskVector* dependencies)
- : did_schedule_(false),
- did_run_(false),
- did_complete_(false) {
- dependencies_.swap(*dependencies);
-}
-
-WorkerPoolTask::~WorkerPoolTask() {
- DCHECK_EQ(did_schedule_, did_complete_);
- DCHECK(!did_run_ || did_schedule_);
- DCHECK(!did_run_ || did_complete_);
-}
-
-void WorkerPoolTask::DidSchedule() {
- DCHECK(!did_complete_);
- did_schedule_ = true;
-}
-
-void WorkerPoolTask::WillRun() {
- DCHECK(did_schedule_);
- DCHECK(!did_complete_);
- DCHECK(!did_run_);
-}
-
-void WorkerPoolTask::DidRun() {
- did_run_ = true;
-}
-
-void WorkerPoolTask::DidComplete() {
- DCHECK(did_schedule_);
- DCHECK(!did_complete_);
- did_complete_ = true;
-}
-
-bool WorkerPoolTask::IsReadyToRun() const {
- // TODO(reveman): Use counter to improve performance.
- for (TaskVector::const_reverse_iterator it = dependencies_.rbegin();
- it != dependencies_.rend(); ++it) {
- WorkerPoolTask* dependency = it->get();
- if (!dependency->HasFinishedRunning())
- return false;
- }
- return true;
-}
-
-bool WorkerPoolTask::HasFinishedRunning() const {
- return did_run_;
-}
-
-bool WorkerPoolTask::HasCompleted() const {
- return did_complete_;
-}
-
-} // namespace internal
-
-// Internal to the worker pool. Any data or logic that needs to be
-// shared between threads lives in this class. All members are guarded
-// by |lock_|.
-class WorkerPool::Inner : public base::DelegateSimpleThread::Delegate {
- public:
- Inner(size_t num_threads, const std::string& thread_name_prefix);
- virtual ~Inner();
-
- void Shutdown();
-
- // Schedule running of tasks in |graph|. Tasks previously scheduled but
- // no longer needed will be canceled unless already running. Canceled
- // tasks are moved to |completed_tasks_| without being run. The result
- // is that once scheduled, a task is guaranteed to end up in the
- // |completed_tasks_| queue even if they later get canceled by another
- // call to SetTaskGraph().
- void SetTaskGraph(TaskGraph* graph);
-
- // Collect all completed tasks in |completed_tasks|.
- void CollectCompletedTasks(TaskDeque* completed_tasks);
-
- private:
- // Overridden from base::DelegateSimpleThread:
- virtual void Run() OVERRIDE;
-
- // This lock protects all members of this class except
- // |worker_pool_on_origin_thread_|. Do not read or modify anything
- // without holding this lock. Do not block while holding this lock.
- mutable base::Lock lock_;
-
- // Condition variable that is waited on by worker threads until new
- // tasks are ready to run or shutdown starts.
- base::ConditionVariable has_ready_to_run_tasks_cv_;
-
- // Provides each running thread loop with a unique index. First thread
- // loop index is 0.
- unsigned next_thread_index_;
-
- // Set during shutdown. Tells workers to exit when no more tasks
- // are pending.
- bool shutdown_;
-
- // This set contains all pending tasks.
- GraphNodeMap pending_tasks_;
-
- // Ordered set of tasks that are ready to run.
- // TODO(reveman): priority_queue might be more efficient.
- typedef std::map<unsigned, internal::WorkerPoolTask*> TaskMap;
- TaskMap ready_to_run_tasks_;
-
- // This set contains all currently running tasks.
- GraphNodeMap running_tasks_;
-
- // Completed tasks not yet collected by origin thread.
- TaskDeque completed_tasks_;
-
- ScopedPtrDeque<base::DelegateSimpleThread> workers_;
-
- DISALLOW_COPY_AND_ASSIGN(Inner);
-};
-
-WorkerPool::Inner::Inner(
- size_t num_threads, const std::string& thread_name_prefix)
- : lock_(),
- has_ready_to_run_tasks_cv_(&lock_),
- next_thread_index_(0),
- shutdown_(false) {
- base::AutoLock lock(lock_);
-
- while (workers_.size() < num_threads) {
- scoped_ptr<base::DelegateSimpleThread> worker = make_scoped_ptr(
- new base::DelegateSimpleThread(
- this,
- thread_name_prefix +
- base::StringPrintf(
- "Worker%u",
- static_cast<unsigned>(workers_.size() + 1)).c_str()));
- worker->Start();
- workers_.push_back(worker.Pass());
- }
-}
-
-WorkerPool::Inner::~Inner() {
- base::AutoLock lock(lock_);
-
- DCHECK(shutdown_);
-
- DCHECK_EQ(0u, pending_tasks_.size());
- DCHECK_EQ(0u, ready_to_run_tasks_.size());
- DCHECK_EQ(0u, running_tasks_.size());
- DCHECK_EQ(0u, completed_tasks_.size());
-}
-
-void WorkerPool::Inner::Shutdown() {
- {
- base::AutoLock lock(lock_);
-
- DCHECK(!shutdown_);
- shutdown_ = true;
-
- // Wake up a worker so it knows it should exit. This will cause all workers
- // to exit as each will wake up another worker before exiting.
- has_ready_to_run_tasks_cv_.Signal();
- }
-
- while (workers_.size()) {
- scoped_ptr<base::DelegateSimpleThread> worker = workers_.take_front();
- // http://crbug.com/240453 - Join() is considered IO and will block this
- // thread. See also http://crbug.com/239423 for further ideas.
- base::ThreadRestrictions::ScopedAllowIO allow_io;
- worker->Join();
- }
-}
-
-void WorkerPool::Inner::SetTaskGraph(TaskGraph* graph) {
- // It is OK to call SetTaskGraph() after shutdown if |graph| is empty.
- DCHECK(graph->empty() || !shutdown_);
-
- GraphNodeMap new_pending_tasks;
- GraphNodeMap new_running_tasks;
- TaskMap new_ready_to_run_tasks;
-
- new_pending_tasks.swap(*graph);
-
- {
- base::AutoLock lock(lock_);
-
- // First remove all completed tasks from |new_pending_tasks|.
- for (TaskDeque::iterator it = completed_tasks_.begin();
- it != completed_tasks_.end(); ++it) {
- internal::WorkerPoolTask* task = it->get();
- new_pending_tasks.take_and_erase(task);
- }
-
- // Move tasks not present in |new_pending_tasks| to |completed_tasks_|.
- for (GraphNodeMap::iterator it = pending_tasks_.begin();
- it != pending_tasks_.end(); ++it) {
- internal::WorkerPoolTask* task = it->first;
-
- // Task has completed if not present in |new_pending_tasks|.
- if (!new_pending_tasks.contains(task))
- completed_tasks_.push_back(task);
- }
-
- // Build new running task set.
- for (GraphNodeMap::iterator it = running_tasks_.begin();
- it != running_tasks_.end(); ++it) {
- internal::WorkerPoolTask* task = it->first;
- // Transfer scheduled task value from |new_pending_tasks| to
- // |new_running_tasks| if currently running. Value must be set to
- // NULL if |new_pending_tasks| doesn't contain task. This does
- // the right in both cases.
- new_running_tasks.set(task, new_pending_tasks.take_and_erase(task));
- }
-
- // Build new "ready to run" tasks queue.
- for (GraphNodeMap::iterator it = new_pending_tasks.begin();
- it != new_pending_tasks.end(); ++it) {
- internal::WorkerPoolTask* task = it->first;
-
- // Completed tasks should not exist in |new_pending_tasks|.
- DCHECK(!task->HasFinishedRunning());
-
- // Call DidSchedule() to indicate that this task has been scheduled.
- // Note: This is only for debugging purposes.
- task->DidSchedule();
-
- DCHECK_EQ(0u, new_ready_to_run_tasks.count(it->second->priority()));
- if (task->IsReadyToRun())
- new_ready_to_run_tasks[it->second->priority()] = task;
- }
-
- // Swap task sets.
- // Note: old tasks are intentionally destroyed after releasing |lock_|.
- pending_tasks_.swap(new_pending_tasks);
- running_tasks_.swap(new_running_tasks);
- ready_to_run_tasks_.swap(new_ready_to_run_tasks);
-
- // If there is more work available, wake up worker thread.
- if (!ready_to_run_tasks_.empty())
- has_ready_to_run_tasks_cv_.Signal();
- }
-}
-
-void WorkerPool::Inner::CollectCompletedTasks(TaskDeque* completed_tasks) {
- base::AutoLock lock(lock_);
-
- DCHECK_EQ(0u, completed_tasks->size());
- completed_tasks->swap(completed_tasks_);
-}
-
-void WorkerPool::Inner::Run() {
-#if defined(OS_ANDROID)
- base::PlatformThread::SetThreadPriority(
- base::PlatformThread::CurrentHandle(),
- base::kThreadPriority_Background);
-#endif
-
- base::AutoLock lock(lock_);
-
- // Get a unique thread index.
- int thread_index = next_thread_index_++;
-
- while (true) {
- if (ready_to_run_tasks_.empty()) {
- // Exit when shutdown is set and no more tasks are pending.
- if (shutdown_ && pending_tasks_.empty())
- break;
-
- // Wait for more tasks.
- has_ready_to_run_tasks_cv_.Wait();
- continue;
- }
-
- // Take top priority task from |ready_to_run_tasks_|.
- scoped_refptr<internal::WorkerPoolTask> task(
- ready_to_run_tasks_.begin()->second);
- ready_to_run_tasks_.erase(ready_to_run_tasks_.begin());
-
- // Move task from |pending_tasks_| to |running_tasks_|.
- DCHECK(pending_tasks_.contains(task.get()));
- DCHECK(!running_tasks_.contains(task.get()));
- running_tasks_.set(task.get(), pending_tasks_.take_and_erase(task.get()));
-
- // There may be more work available, so wake up another worker thread.
- has_ready_to_run_tasks_cv_.Signal();
-
- // Call WillRun() before releasing |lock_| and running task.
- task->WillRun();
-
- {
- base::AutoUnlock unlock(lock_);
-
- task->RunOnThread(thread_index);
- }
-
- // This will mark task as finished running.
- task->DidRun();
-
- // Now iterate over all dependents to check if they are ready to run.
- scoped_ptr<GraphNode> node = running_tasks_.take_and_erase(task.get());
- if (node) {
- typedef internal::WorkerPoolTask::TaskVector TaskVector;
- for (TaskVector::const_iterator it = node->dependents().begin();
- it != node->dependents().end(); ++it) {
- GraphNodeMap::iterator dependent_it = pending_tasks_.find(it->get());
- DCHECK(dependent_it != pending_tasks_.end());
-
- internal::WorkerPoolTask* dependent = dependent_it->first;
- if (!dependent->IsReadyToRun())
- continue;
-
- // Task is ready. Add it to |ready_to_run_tasks_|.
- GraphNode* dependent_node = dependent_it->second;
- unsigned priority = dependent_node->priority();
- DCHECK(!ready_to_run_tasks_.count(priority) ||
- ready_to_run_tasks_[priority] == dependent);
- ready_to_run_tasks_[priority] = dependent;
- }
- }
-
- // Finally add task to |completed_tasks_|.
- completed_tasks_.push_back(task);
- }
-
- // We noticed we should exit. Wake up the next worker so it knows it should
- // exit as well (because the Shutdown() code only signals once).
- has_ready_to_run_tasks_cv_.Signal();
-}
-
-WorkerPool::GraphNode::GraphNode(
- internal::WorkerPoolTask* dependent, unsigned priority)
- : priority_(priority) {
- if (dependent)
- dependents_.push_back(dependent);
-}
-
-WorkerPool::GraphNode::~GraphNode() {
-}
-
-void WorkerPool::GraphNode::AddDependent(internal::WorkerPoolTask* dependent) {
- DCHECK(dependent);
- dependents_.push_back(dependent);
-}
-
-WorkerPool::WorkerPool(size_t num_threads,
- const std::string& thread_name_prefix)
- : in_dispatch_completion_callbacks_(false),
- inner_(make_scoped_ptr(new Inner(num_threads, thread_name_prefix))) {
-}
-
-WorkerPool::~WorkerPool() {
-}
-
-void WorkerPool::Shutdown() {
- TRACE_EVENT0("cc", "WorkerPool::Shutdown");
-
- DCHECK(!in_dispatch_completion_callbacks_);
-
- inner_->Shutdown();
-}
-
-void WorkerPool::CheckForCompletedTasks() {
- TRACE_EVENT0("cc", "WorkerPool::CheckForCompletedTasks");
-
- DCHECK(!in_dispatch_completion_callbacks_);
-
- TaskDeque completed_tasks;
- inner_->CollectCompletedTasks(&completed_tasks);
- DispatchCompletionCallbacks(&completed_tasks);
-}
-
-void WorkerPool::DispatchCompletionCallbacks(TaskDeque* completed_tasks) {
- TRACE_EVENT0("cc", "WorkerPool::DispatchCompletionCallbacks");
-
- // Worker pool instance is not reentrant while processing completed tasks.
- in_dispatch_completion_callbacks_ = true;
-
- while (!completed_tasks->empty()) {
- internal::WorkerPoolTask* task = completed_tasks->front().get();
-
- task->DidComplete();
- task->DispatchCompletionCallback();
-
- completed_tasks->pop_front();
- }
-
- in_dispatch_completion_callbacks_ = false;
-}
-
-void WorkerPool::SetTaskGraph(TaskGraph* graph) {
- TRACE_EVENT0("cc", "WorkerPool::SetTaskGraph");
-
- DCHECK(!in_dispatch_completion_callbacks_);
-
- inner_->SetTaskGraph(graph);
-}
-
-// static
-unsigned WorkerPool::BuildTaskGraphRecursive(
- internal::WorkerPoolTask* task,
- internal::WorkerPoolTask* dependent,
- unsigned priority,
- TaskGraph* tasks) {
- // Skip sub-tree if task has already completed.
- if (task->HasCompleted())
- return priority;
-
- GraphNodeMap::iterator it = tasks->find(task);
- if (it != tasks->end()) {
- it->second->AddDependent(dependent);
- return priority;
- }
-
- typedef internal::WorkerPoolTask::TaskVector TaskVector;
- for (TaskVector::iterator dependency_it = task->dependencies().begin();
- dependency_it != task->dependencies().end(); ++dependency_it) {
- internal::WorkerPoolTask* dependency = dependency_it->get();
- priority = BuildTaskGraphRecursive(dependency, task, priority, tasks);
- }
-
- tasks->set(task, make_scoped_ptr(new GraphNode(dependent, priority)));
-
- return priority + 1;
-}
-
-// static
-void WorkerPool::BuildTaskGraph(
- internal::WorkerPoolTask* root, TaskGraph* tasks) {
- const unsigned kBasePriority = 0u;
- if (root)
- BuildTaskGraphRecursive(root, NULL, kBasePriority, tasks);
-}
-
-} // namespace cc
diff --git a/cc/base/worker_pool.h b/cc/base/worker_pool.h
deleted file mode 100644
index eeffb56..0000000
--- a/cc/base/worker_pool.h
+++ /dev/null
@@ -1,154 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_BASE_WORKER_POOL_H_
-#define CC_BASE_WORKER_POOL_H_
-
-#include <deque>
-#include <string>
-#include <vector>
-
-#include "base/cancelable_callback.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/message_loop.h"
-#include "cc/base/cc_export.h"
-#include "cc/base/scoped_ptr_hash_map.h"
-
-namespace cc {
-namespace internal {
-
-class CC_EXPORT WorkerPoolTask
- : public base::RefCountedThreadSafe<WorkerPoolTask> {
- public:
- typedef std::vector<scoped_refptr<WorkerPoolTask> > TaskVector;
-
- virtual void RunOnThread(unsigned thread_index) = 0;
- virtual void DispatchCompletionCallback() = 0;
-
- void DidSchedule();
- void WillRun();
- void DidRun();
- void DidComplete();
-
- bool IsReadyToRun() const;
- bool HasFinishedRunning() const;
- bool HasCompleted() const;
-
- TaskVector& dependencies() { return dependencies_; }
-
- protected:
- friend class base::RefCountedThreadSafe<WorkerPoolTask>;
-
- WorkerPoolTask();
- explicit WorkerPoolTask(TaskVector* dependencies);
- virtual ~WorkerPoolTask();
-
- private:
- bool did_schedule_;
- bool did_run_;
- bool did_complete_;
- TaskVector dependencies_;
-};
-
-} // namespace internal
-} // namespace cc
-
-#if defined(COMPILER_GCC)
-namespace BASE_HASH_NAMESPACE {
-template <> struct hash<cc::internal::WorkerPoolTask*> {
- size_t operator()(cc::internal::WorkerPoolTask* ptr) const {
- return hash<size_t>()(reinterpret_cast<size_t>(ptr));
- }
-};
-} // namespace BASE_HASH_NAMESPACE
-#endif // COMPILER
-
-namespace cc {
-
-// A worker thread pool that runs tasks provided by task graph and
-// guarantees completion of all pending tasks at shutdown.
-class CC_EXPORT WorkerPool {
- public:
- virtual ~WorkerPool();
-
- // Tells the worker pool to shutdown and returns once all pending tasks have
- // completed.
- virtual void Shutdown();
-
- // Force a check for completed tasks.
- virtual void CheckForCompletedTasks();
-
- protected:
- class CC_EXPORT GraphNode {
- public:
- GraphNode(internal::WorkerPoolTask* dependent, unsigned priority);
- ~GraphNode();
-
- void AddDependent(internal::WorkerPoolTask* dependent);
-
- const internal::WorkerPoolTask::TaskVector& dependents() const {
- return dependents_;
- }
- unsigned priority() const { return priority_; }
-
- private:
- internal::WorkerPoolTask::TaskVector dependents_;
- unsigned priority_;
-
- DISALLOW_COPY_AND_ASSIGN(GraphNode);
- };
- typedef ScopedPtrHashMap<internal::WorkerPoolTask*, GraphNode> GraphNodeMap;
- typedef GraphNodeMap TaskGraph;
-
- WorkerPool(size_t num_threads, const std::string& thread_name_prefix);
-
- // Schedule running of tasks in |graph|. Any previously scheduled tasks
- // that are not already running will be canceled. Canceled tasks don't run
- // but completion of them is still processed.
- void SetTaskGraph(TaskGraph* graph);
-
- // BuildTaskGraph() takes a task tree as input and constructs a
- // unique set of tasks with edges between dependencies pointing in
- // the direction of the dependents. Each task is given a unique priority
- // which is currently the same as the DFS traversal order.
- //
- // Input: Output:
- //
- // root task4 Task | Priority (lower is better)
- // / \ / \ -------+---------------------------
- // task1 task2 task3 task2 root | 4
- // | | | | task1 | 2
- // task3 | task1 | task2 | 3
- // | | \ / task3 | 1
- // task4 task4 root task4 | 0
- //
- // The output can be used to efficiently maintain a queue of
- // "ready to run" tasks.
- static unsigned BuildTaskGraphRecursive(
- internal::WorkerPoolTask* task,
- internal::WorkerPoolTask* dependent,
- unsigned priority,
- TaskGraph* tasks);
- static void BuildTaskGraph(
- internal::WorkerPoolTask* root, TaskGraph* tasks);
-
- private:
- class Inner;
- friend class Inner;
-
- typedef std::deque<scoped_refptr<internal::WorkerPoolTask> > TaskDeque;
-
- void DispatchCompletionCallbacks(TaskDeque* completed_tasks);
-
- bool in_dispatch_completion_callbacks_;
-
- // Hide the gory details of the worker pool in |inner_|.
- const scoped_ptr<Inner> inner_;
-};
-
-} // namespace cc
-
-#endif // CC_BASE_WORKER_POOL_H_
diff --git a/cc/base/worker_pool_perftest.cc b/cc/base/worker_pool_perftest.cc
deleted file mode 100644
index f83b886..0000000
--- a/cc/base/worker_pool_perftest.cc
+++ /dev/null
@@ -1,244 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/base/worker_pool.h"
-
-#include "base/time.h"
-#include "cc/base/completion_event.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace cc {
-
-namespace {
-
-static const int kTimeLimitMillis = 2000;
-static const int kWarmupRuns = 5;
-static const int kTimeCheckInterval = 10;
-
-class PerfTaskImpl : public internal::WorkerPoolTask {
- public:
- explicit PerfTaskImpl(internal::WorkerPoolTask::TaskVector* dependencies)
- : internal::WorkerPoolTask(dependencies) {}
-
- // Overridden from internal::WorkerPoolTask:
- virtual void RunOnThread(unsigned thread_index) OVERRIDE {}
- virtual void DispatchCompletionCallback() OVERRIDE {}
-
- private:
- virtual ~PerfTaskImpl() {}
-};
-
-class PerfControlTaskImpl : public internal::WorkerPoolTask {
- public:
- explicit PerfControlTaskImpl(
- internal::WorkerPoolTask::TaskVector* dependencies)
- : internal::WorkerPoolTask(dependencies),
- did_start_(new CompletionEvent),
- can_finish_(new CompletionEvent) {}
-
- // Overridden from internal::WorkerPoolTask:
- virtual void RunOnThread(unsigned thread_index) OVERRIDE {
- did_start_->Signal();
- can_finish_->Wait();
- }
- virtual void DispatchCompletionCallback() OVERRIDE {}
-
- void WaitForTaskToStartRunning() {
- did_start_->Wait();
- }
-
- void AllowTaskToFinish() {
- can_finish_->Signal();
- }
-
- private:
- virtual ~PerfControlTaskImpl() {}
-
- scoped_ptr<CompletionEvent> did_start_;
- scoped_ptr<CompletionEvent> can_finish_;
-};
-
-class PerfWorkerPool : public WorkerPool {
- public:
- PerfWorkerPool() : WorkerPool(1, "test") {}
- virtual ~PerfWorkerPool() {}
-
- static scoped_ptr<PerfWorkerPool> Create() {
- return make_scoped_ptr(new PerfWorkerPool);
- }
-
- void BuildTaskGraph(internal::WorkerPoolTask* root) {
- graph_.clear();
- WorkerPool::BuildTaskGraph(root, &graph_);
- }
-
- void ScheduleTasks() {
- SetTaskGraph(&graph_);
- }
-
- private:
- TaskGraph graph_;
-};
-
-class WorkerPoolPerfTest : public testing::Test {
- public:
- WorkerPoolPerfTest() : num_runs_(0) {}
-
- // Overridden from testing::Test:
- virtual void SetUp() OVERRIDE {
- worker_pool_ = PerfWorkerPool::Create();
- }
- virtual void TearDown() OVERRIDE {
- worker_pool_->Shutdown();
- worker_pool_->CheckForCompletedTasks();
- }
-
- void EndTest() {
- elapsed_ = base::TimeTicks::HighResNow() - start_time_;
- }
-
- void AfterTest(const std::string test_name) {
- // Format matches chrome/test/perf/perf_test.h:PrintResult
- printf("*RESULT %s: %.2f runs/s\n",
- test_name.c_str(),
- num_runs_ / elapsed_.InSecondsF());
- }
-
- void CreateTasks(internal::WorkerPoolTask::TaskVector* dependencies,
- unsigned current_depth,
- unsigned max_depth,
- unsigned num_children_per_node) {
- internal::WorkerPoolTask::TaskVector children;
- if (current_depth < max_depth) {
- for (unsigned i = 0; i < num_children_per_node; ++i) {
- CreateTasks(&children,
- current_depth + 1,
- max_depth,
- num_children_per_node);
- }
- } else if (leaf_task_.get()) {
- children.push_back(leaf_task_);
- }
- dependencies->push_back(make_scoped_refptr(new PerfTaskImpl(&children)));
- }
-
- bool DidRun() {
- ++num_runs_;
- if (num_runs_ == kWarmupRuns)
- start_time_ = base::TimeTicks::HighResNow();
-
- if (!start_time_.is_null() && (num_runs_ % kTimeCheckInterval) == 0) {
- base::TimeDelta elapsed = base::TimeTicks::HighResNow() - start_time_;
- if (elapsed >= base::TimeDelta::FromMilliseconds(kTimeLimitMillis)) {
- elapsed_ = elapsed;
- return false;
- }
- }
-
- return true;
- }
-
- void RunBuildTaskGraphTest(const std::string test_name,
- unsigned max_depth,
- unsigned num_children_per_node) {
- start_time_ = base::TimeTicks();
- num_runs_ = 0;
- internal::WorkerPoolTask::TaskVector children;
- CreateTasks(&children, 0, max_depth, num_children_per_node);
- scoped_refptr<PerfTaskImpl> root_task(
- make_scoped_refptr(new PerfTaskImpl(&children)));
- do {
- worker_pool_->BuildTaskGraph(root_task.get());
- } while (DidRun());
-
- AfterTest(test_name);
- }
-
- void RunScheduleTasksTest(const std::string test_name,
- unsigned max_depth,
- unsigned num_children_per_node) {
- start_time_ = base::TimeTicks();
- num_runs_ = 0;
- do {
- internal::WorkerPoolTask::TaskVector empty;
- leaf_task_ = make_scoped_refptr(new PerfControlTaskImpl(&empty));
- internal::WorkerPoolTask::TaskVector children;
- CreateTasks(&children, 0, max_depth, num_children_per_node);
- scoped_refptr<PerfTaskImpl> root_task(
- make_scoped_refptr(new PerfTaskImpl(&children)));
-
- worker_pool_->BuildTaskGraph(root_task.get());
- worker_pool_->ScheduleTasks();
- leaf_task_->WaitForTaskToStartRunning();
- worker_pool_->BuildTaskGraph(NULL);
- worker_pool_->ScheduleTasks();
- worker_pool_->CheckForCompletedTasks();
- leaf_task_->AllowTaskToFinish();
- } while (DidRun());
-
- AfterTest(test_name);
- }
-
- void RunExecuteTasksTest(const std::string test_name,
- unsigned max_depth,
- unsigned num_children_per_node) {
- start_time_ = base::TimeTicks();
- num_runs_ = 0;
- do {
- internal::WorkerPoolTask::TaskVector children;
- CreateTasks(&children, 0, max_depth, num_children_per_node);
- scoped_refptr<PerfControlTaskImpl> root_task(
- make_scoped_refptr(new PerfControlTaskImpl(&children)));
-
- worker_pool_->BuildTaskGraph(root_task.get());
- worker_pool_->ScheduleTasks();
- root_task->WaitForTaskToStartRunning();
- root_task->AllowTaskToFinish();
- worker_pool_->CheckForCompletedTasks();
- } while (DidRun());
-
- AfterTest(test_name);
- }
-
- protected:
- scoped_ptr<PerfWorkerPool> worker_pool_;
- scoped_refptr<PerfControlTaskImpl> leaf_task_;
- base::TimeTicks start_time_;
- base::TimeDelta elapsed_;
- int num_runs_;
-};
-
-TEST_F(WorkerPoolPerfTest, BuildTaskGraph) {
- RunBuildTaskGraphTest("build_task_graph_1_10", 1, 10);
- RunBuildTaskGraphTest("build_task_graph_1_1000", 1, 1000);
- RunBuildTaskGraphTest("build_task_graph_2_10", 2, 10);
- RunBuildTaskGraphTest("build_task_graph_5_5", 5, 5);
- RunBuildTaskGraphTest("build_task_graph_10_2", 10, 2);
- RunBuildTaskGraphTest("build_task_graph_1000_1", 1000, 1);
- RunBuildTaskGraphTest("build_task_graph_10_1", 10, 1);
-}
-
-TEST_F(WorkerPoolPerfTest, ScheduleTasks) {
- RunScheduleTasksTest("schedule_tasks_1_10", 1, 10);
- RunScheduleTasksTest("schedule_tasks_1_1000", 1, 1000);
- RunScheduleTasksTest("schedule_tasks_2_10", 2, 10);
- RunScheduleTasksTest("schedule_tasks_5_5", 5, 5);
- RunScheduleTasksTest("schedule_tasks_10_2", 10, 2);
- RunScheduleTasksTest("schedule_tasks_1000_1", 1000, 1);
- RunScheduleTasksTest("schedule_tasks_10_1", 10, 1);
-}
-
-TEST_F(WorkerPoolPerfTest, ExecuteTasks) {
- RunExecuteTasksTest("execute_tasks_1_10", 1, 10);
- RunExecuteTasksTest("execute_tasks_1_1000", 1, 1000);
- RunExecuteTasksTest("execute_tasks_2_10", 2, 10);
- RunExecuteTasksTest("execute_tasks_5_5", 5, 5);
- RunExecuteTasksTest("execute_tasks_10_2", 10, 2);
- RunExecuteTasksTest("execute_tasks_1000_1", 1000, 1);
- RunExecuteTasksTest("execute_tasks_10_1", 10, 1);
-}
-
-} // namespace
-
-} // namespace cc
diff --git a/cc/base/worker_pool_unittest.cc b/cc/base/worker_pool_unittest.cc
deleted file mode 100644
index 1a48ec4..0000000
--- a/cc/base/worker_pool_unittest.cc
+++ /dev/null
@@ -1,206 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/base/worker_pool.h"
-
-#include <vector>
-
-#include "cc/base/completion_event.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace cc {
-
-namespace {
-
-class FakeTaskImpl : public internal::WorkerPoolTask {
- public:
- FakeTaskImpl(const base::Closure& callback,
- const base::Closure& reply,
- internal::WorkerPoolTask::TaskVector* dependencies)
- : internal::WorkerPoolTask(dependencies),
- callback_(callback),
- reply_(reply) {
- }
- FakeTaskImpl(const base::Closure& callback, const base::Closure& reply)
- : callback_(callback),
- reply_(reply) {
- }
-
- // Overridden from internal::WorkerPoolTask:
- virtual void RunOnThread(unsigned thread_index) OVERRIDE {
- if (!callback_.is_null())
- callback_.Run();
- }
- virtual void DispatchCompletionCallback() OVERRIDE {
- if (!reply_.is_null())
- reply_.Run();
- }
-
- private:
- virtual ~FakeTaskImpl() {}
-
- const base::Closure callback_;
- const base::Closure reply_;
-};
-
-class FakeWorkerPool : public WorkerPool {
- public:
- FakeWorkerPool() : WorkerPool(1, "test") {}
- virtual ~FakeWorkerPool() {}
-
- static scoped_ptr<FakeWorkerPool> Create() {
- return make_scoped_ptr(new FakeWorkerPool);
- }
-
- void ScheduleTasks(const base::Closure& callback,
- const base::Closure& reply,
- const base::Closure& dependency,
- int count) {
- scoped_refptr<FakeTaskImpl> dependency_task(
- new FakeTaskImpl(dependency, base::Closure()));
-
- internal::WorkerPoolTask::TaskVector tasks;
- for (int i = 0; i < count; ++i) {
- internal::WorkerPoolTask::TaskVector dependencies(1, dependency_task);
- tasks.push_back(new FakeTaskImpl(callback, reply, &dependencies));
- }
- scoped_refptr<FakeTaskImpl> completion_task(
- new FakeTaskImpl(base::Bind(&FakeWorkerPool::OnTasksCompleted,
- base::Unretained(this)),
- base::Closure(),
- &tasks));
-
- scheduled_tasks_completion_.reset(new CompletionEvent);
-
- TaskGraph graph;
- BuildTaskGraph(completion_task.get(), &graph);
- WorkerPool::SetTaskGraph(&graph);
- root_.swap(completion_task);
- }
-
- void WaitForTasksToComplete() {
- DCHECK(scheduled_tasks_completion_);
- scheduled_tasks_completion_->Wait();
- }
-
- private:
- void OnTasksCompleted() {
- DCHECK(scheduled_tasks_completion_);
- scheduled_tasks_completion_->Signal();
- }
-
- scoped_refptr<FakeTaskImpl> root_;
- scoped_ptr<CompletionEvent> scheduled_tasks_completion_;
-};
-
-class WorkerPoolTest : public testing::Test {
- public:
- WorkerPoolTest() {}
- virtual ~WorkerPoolTest() {}
-
- // Overridden from testing::Test:
- virtual void SetUp() OVERRIDE {
- Reset();
- }
- virtual void TearDown() OVERRIDE {
- worker_pool_->Shutdown();
- }
-
- void Reset() {
- worker_pool_ = FakeWorkerPool::Create();
- }
-
- void RunAllTasksAndReset() {
- worker_pool_->WaitForTasksToComplete();
- worker_pool_->Shutdown();
- worker_pool_->CheckForCompletedTasks();
- Reset();
- }
-
- FakeWorkerPool* worker_pool() {
- return worker_pool_.get();
- }
-
- void RunTask(unsigned id) {
- run_task_ids_.push_back(id);
- }
-
- void OnTaskCompleted(unsigned id) {
- on_task_completed_ids_.push_back(id);
- }
-
- const std::vector<unsigned>& run_task_ids() {
- return run_task_ids_;
- }
-
- const std::vector<unsigned>& on_task_completed_ids() {
- return on_task_completed_ids_;
- }
-
- private:
- scoped_ptr<FakeWorkerPool> worker_pool_;
- std::vector<unsigned> run_task_ids_;
- std::vector<unsigned> on_task_completed_ids_;
-};
-
-TEST_F(WorkerPoolTest, Basic) {
- EXPECT_EQ(0u, run_task_ids().size());
- EXPECT_EQ(0u, on_task_completed_ids().size());
-
- worker_pool()->ScheduleTasks(
- base::Bind(&WorkerPoolTest::RunTask, base::Unretained(this), 0u),
- base::Bind(&WorkerPoolTest::OnTaskCompleted, base::Unretained(this), 0u),
- base::Closure(),
- 1);
- RunAllTasksAndReset();
-
- EXPECT_EQ(1u, run_task_ids().size());
- EXPECT_EQ(1u, on_task_completed_ids().size());
-
- worker_pool()->ScheduleTasks(
- base::Bind(&WorkerPoolTest::RunTask, base::Unretained(this), 0u),
- base::Bind(&WorkerPoolTest::OnTaskCompleted, base::Unretained(this), 0u),
- base::Closure(),
- 2);
- RunAllTasksAndReset();
-
- EXPECT_EQ(3u, run_task_ids().size());
- EXPECT_EQ(3u, on_task_completed_ids().size());
-}
-
-TEST_F(WorkerPoolTest, Dependencies) {
- worker_pool()->ScheduleTasks(
- base::Bind(&WorkerPoolTest::RunTask, base::Unretained(this), 1u),
- base::Bind(&WorkerPoolTest::OnTaskCompleted, base::Unretained(this), 1u),
- base::Bind(&WorkerPoolTest::RunTask, base::Unretained(this), 0u),
- 1);
- RunAllTasksAndReset();
-
- // Check if dependency ran before task.
- ASSERT_EQ(2u, run_task_ids().size());
- EXPECT_EQ(0u, run_task_ids()[0]);
- EXPECT_EQ(1u, run_task_ids()[1]);
- ASSERT_EQ(1u, on_task_completed_ids().size());
- EXPECT_EQ(1u, on_task_completed_ids()[0]);
-
- worker_pool()->ScheduleTasks(
- base::Bind(&WorkerPoolTest::RunTask, base::Unretained(this), 1u),
- base::Bind(&WorkerPoolTest::OnTaskCompleted, base::Unretained(this), 1u),
- base::Bind(&WorkerPoolTest::RunTask, base::Unretained(this), 0u),
- 2);
- RunAllTasksAndReset();
-
- // Dependency should only run once.
- ASSERT_EQ(5u, run_task_ids().size());
- EXPECT_EQ(0u, run_task_ids()[2]);
- EXPECT_EQ(1u, run_task_ids()[3]);
- EXPECT_EQ(1u, run_task_ids()[4]);
- ASSERT_EQ(3u, on_task_completed_ids().size());
- EXPECT_EQ(1u, on_task_completed_ids()[1]);
- EXPECT_EQ(1u, on_task_completed_ids()[2]);
-}
-
-} // namespace
-
-} // namespace cc