| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef CC_RESOURCES_TASK_GRAPH_RUNNER_H_ | 5 #ifndef CC_RESOURCES_TASK_GRAPH_RUNNER_H_ |
| 6 #define CC_RESOURCES_TASK_GRAPH_RUNNER_H_ | 6 #define CC_RESOURCES_TASK_GRAPH_RUNNER_H_ |
| 7 | 7 |
| 8 #include <queue> | |
| 9 #include <string> | 8 #include <string> |
| 10 #include <vector> | 9 #include <vector> |
| 11 | 10 |
| 12 #include "base/containers/scoped_ptr_hash_map.h" | 11 #include "base/containers/scoped_ptr_hash_map.h" |
| 13 #include "base/memory/ref_counted.h" | 12 #include "base/memory/ref_counted.h" |
| 14 #include "base/memory/scoped_ptr.h" | |
| 15 #include "base/synchronization/condition_variable.h" | 13 #include "base/synchronization/condition_variable.h" |
| 16 #include "base/threading/simple_thread.h" | 14 #include "base/threading/simple_thread.h" |
| 17 #include "cc/base/cc_export.h" | 15 #include "cc/base/cc_export.h" |
| 18 #include "cc/base/scoped_ptr_deque.h" | 16 #include "cc/base/scoped_ptr_deque.h" |
| 19 | 17 |
| 20 namespace cc { | 18 namespace cc { |
| 21 namespace internal { | 19 namespace internal { |
| 22 | 20 |
| 23 class CC_EXPORT Task : public base::RefCountedThreadSafe<Task> { | 21 class CC_EXPORT Task : public base::RefCountedThreadSafe<Task> { |
| 24 public: | 22 public: |
| 25 typedef std::vector<scoped_refptr<Task> > Vector; | 23 typedef std::vector<scoped_refptr<Task> > Vector; |
| 26 | 24 |
| 27 virtual void RunOnWorkerThread(unsigned thread_index) = 0; | 25 virtual void RunOnWorkerThread(unsigned thread_index) = 0; |
| 28 | 26 |
| 29 void WillRun(); | 27 void WillRun(); |
| 30 void DidRun(); | 28 void DidRun(); |
| 31 bool HasFinishedRunning() const; | 29 bool HasFinishedRunning() const; |
| 32 | 30 |
| 33 protected: | 31 protected: |
| 34 friend class base::RefCountedThreadSafe<Task>; | 32 friend class base::RefCountedThreadSafe<Task>; |
| 35 | 33 |
| 36 Task(); | 34 Task(); |
| 37 virtual ~Task(); | 35 virtual ~Task(); |
| 38 | 36 |
| 39 bool did_run_; | 37 bool did_run_; |
| 40 }; | 38 }; |
| 41 | 39 |
| 42 } // namespace internal | 40 // Dependencies are represented as edges in a task graph. Each graph node |
| 43 } // namespace cc | 41 // is assigned a priority and a run count that matches the number of |
| 42 // dependencies. |
| 43 struct CC_EXPORT TaskGraph { |
| 44 struct Node { |
| 45 class TaskComparator { |
| 46 public: |
| 47 explicit TaskComparator(const Task* task) : task_(task) {} |
| 44 | 48 |
| 45 #if defined(COMPILER_GCC) | 49 bool operator()(const Node& node) const { return node.task == task_; } |
| 46 namespace BASE_HASH_NAMESPACE { | |
| 47 template <> | |
| 48 struct hash<cc::internal::Task*> { | |
| 49 size_t operator()(cc::internal::Task* ptr) const { | |
| 50 return hash<size_t>()(reinterpret_cast<size_t>(ptr)); | |
| 51 } | |
| 52 }; | |
| 53 } // namespace BASE_HASH_NAMESPACE | |
| 54 #endif // COMPILER | |
| 55 | 50 |
| 56 namespace cc { | 51 private: |
| 57 namespace internal { | 52 const Task* task_; |
| 53 }; |
| 58 | 54 |
| 59 // Dependencies are represented by edges in a task graph. A graph node | 55 typedef std::vector<Node> Vector; |
| 60 // store edges as a vector of dependents. Each graph node is assigned | |
| 61 // a priority and a run count that matches the number of dependencies. | |
| 62 class CC_EXPORT GraphNode { | |
| 63 public: | |
| 64 typedef std::vector<GraphNode*> Vector; | |
| 65 typedef base::ScopedPtrHashMap<Task*, GraphNode> Map; | |
| 66 | 56 |
| 67 GraphNode(Task* task, unsigned priority); | 57 Node(Task* task, unsigned priority, size_t dependencies) |
| 68 ~GraphNode(); | 58 : task(task), priority(priority), dependencies(dependencies) {} |
| 69 | 59 |
| 70 Task* task() { return task_; } | 60 Task* task; |
| 61 unsigned priority; |
| 62 size_t dependencies; |
| 63 }; |
| 71 | 64 |
| 72 void add_dependent(GraphNode* dependent) { | 65 struct Edge { |
| 73 DCHECK(dependent); | 66 typedef std::vector<Edge> Vector; |
| 74 dependents_.push_back(dependent); | |
| 75 } | |
| 76 const Vector& dependents() const { return dependents_; } | |
| 77 | 67 |
| 78 unsigned priority() const { return priority_; } | 68 Edge(const Task* task, Task* dependent) |
| 69 : task(task), dependent(dependent) {} |
| 79 | 70 |
| 80 unsigned num_dependencies() const { return num_dependencies_; } | 71 const Task* task; |
| 81 void add_dependency() { ++num_dependencies_; } | 72 Task* dependent; |
| 82 void remove_dependency() { | 73 }; |
| 83 DCHECK(num_dependencies_); | |
| 84 --num_dependencies_; | |
| 85 } | |
| 86 | 74 |
| 87 private: | 75 TaskGraph(); |
| 88 Task* task_; | 76 ~TaskGraph(); |
| 89 Vector dependents_; | |
| 90 unsigned priority_; | |
| 91 unsigned num_dependencies_; | |
| 92 | 77 |
| 93 DISALLOW_COPY_AND_ASSIGN(GraphNode); | 78 void Swap(TaskGraph* other); |
| 79 void Reset(); |
| 80 |
| 81 Node::Vector nodes; |
| 82 Edge::Vector edges; |
| 94 }; | 83 }; |
| 95 | 84 |
| 96 class TaskGraphRunner; | 85 class TaskGraphRunner; |
| 97 | 86 |
| 98 // Opaque identifier that defines a namespace of tasks. | 87 // Opaque identifier that defines a namespace of tasks. |
| 99 class CC_EXPORT NamespaceToken { | 88 class CC_EXPORT NamespaceToken { |
| 100 public: | 89 public: |
| 101 NamespaceToken() : id_(0) {} | 90 NamespaceToken() : id_(0) {} |
| 102 ~NamespaceToken() {} | 91 ~NamespaceToken() {} |
| 103 | 92 |
| 104 bool IsValid() const { return id_ != 0; } | 93 bool IsValid() const { return id_ != 0; } |
| 105 | 94 |
| 106 private: | 95 private: |
| 107 friend class TaskGraphRunner; | 96 friend class TaskGraphRunner; |
| 108 | 97 |
| 109 explicit NamespaceToken(int id) : id_(id) {} | 98 explicit NamespaceToken(int id) : id_(id) {} |
| 110 | 99 |
| 111 int id_; | 100 int id_; |
| 112 }; | 101 }; |
| 113 | 102 |
| 114 // A worker thread pool that runs tasks provided by task graph. Destructor | 103 // A worker thread pool that runs tasks provided by task graph. Destructor |
| 115 // might block and should not be used on a thread that needs to be responsive. | 104 // might block and should not be used on a thread that needs to be responsive. |
| 116 class CC_EXPORT TaskGraphRunner : public base::DelegateSimpleThread::Delegate { | 105 class CC_EXPORT TaskGraphRunner : public base::DelegateSimpleThread::Delegate { |
| 117 public: | 106 public: |
| 118 typedef GraphNode::Map TaskGraph; | |
| 119 | |
| 120 TaskGraphRunner(size_t num_threads, const std::string& thread_name_prefix); | 107 TaskGraphRunner(size_t num_threads, const std::string& thread_name_prefix); |
| 121 virtual ~TaskGraphRunner(); | 108 virtual ~TaskGraphRunner(); |
| 122 | 109 |
| 123 // Returns a unique token that can be used to pass a task graph to | 110 // Returns a unique token that can be used to pass a task graph to |
| 124 // SetTaskGraph(). Valid tokens are always nonzero. | 111 // SetTaskGraph(). Valid tokens are always nonzero. |
| 125 NamespaceToken GetNamespaceToken(); | 112 NamespaceToken GetNamespaceToken(); |
| 126 | 113 |
| 127 // Schedule running of tasks in |graph|. Tasks previously scheduled but | 114 // Schedule running of tasks in |graph|. Tasks previously scheduled but |
| 128 // no longer needed will be canceled unless already running. Canceled | 115 // no longer needed will be canceled unless already running. Canceled |
| 129 // tasks are moved to |completed_tasks| without being run. The result | 116 // tasks are moved to |completed_tasks| without being run. The result |
| 130 // is that once scheduled, a task is guaranteed to end up in the | 117 // is that once scheduled, a task is guaranteed to end up in the |
| 131 // |completed_tasks| queue even if it later get canceled by another | 118 // |completed_tasks| queue even if it later gets canceled by another |
| 132 // call to SetTaskGraph(). | 119 // call to SetTaskGraph(). |
| 133 void SetTaskGraph(NamespaceToken token, TaskGraph* graph); | 120 void SetTaskGraph(NamespaceToken token, TaskGraph* graph); |
| 134 | 121 |
| 135 // Wait for all scheduled tasks to finish running. | 122 // Wait for all scheduled tasks to finish running. |
| 136 void WaitForTasksToFinishRunning(NamespaceToken token); | 123 void WaitForTasksToFinishRunning(NamespaceToken token); |
| 137 | 124 |
| 138 // Collect all completed tasks in |completed_tasks|. | 125 // Collect all completed tasks in |completed_tasks|. |
| 139 void CollectCompletedTasks(NamespaceToken token, | 126 void CollectCompletedTasks(NamespaceToken token, |
| 140 Task::Vector* completed_tasks); | 127 Task::Vector* completed_tasks); |
| 141 | 128 |
| 142 // Run one task on current thread. Returns false if no tasks are ready | 129 // Run one task on current thread. Returns false if no tasks are ready |
| 143 // to run. This should only be used by tests. | 130 // to run. This should only be used by tests. |
| 144 bool RunTaskForTesting(); | 131 bool RunTaskForTesting(); |
| 145 | 132 |
| 146 private: | 133 private: |
| 134 struct PrioritizedTask { |
| 135 typedef std::vector<PrioritizedTask> Vector; |
| 136 |
| 137 PrioritizedTask(Task* task, unsigned priority) |
| 138 : task(task), priority(priority) {} |
| 139 |
| 140 Task* task; |
| 141 unsigned priority; |
| 142 }; |
| 143 |
| 147 struct TaskNamespace { | 144 struct TaskNamespace { |
| 148 typedef std::vector<TaskNamespace*> Vector; | 145 typedef std::vector<TaskNamespace*> Vector; |
| 149 | 146 |
| 150 TaskNamespace(); | 147 TaskNamespace(); |
| 151 ~TaskNamespace(); | 148 ~TaskNamespace(); |
| 152 | 149 |
| 153 // This set contains all pending tasks. | 150 // Current task graph. |
| 154 TaskGraph pending_tasks; | 151 TaskGraph graph; |
| 155 // This set contains all currently running tasks. | 152 |
| 156 TaskGraph running_tasks; | 153 // Ordered set of tasks that are ready to run. |
| 154 PrioritizedTask::Vector ready_to_run_tasks; |
| 155 |
| 157 // Completed tasks not yet collected by origin thread. | 156 // Completed tasks not yet collected by origin thread. |
| 158 Task::Vector completed_tasks; | 157 Task::Vector completed_tasks; |
| 159 // Ordered set of tasks that are ready to run. | 158 |
| 160 internal::GraphNode::Vector ready_to_run_tasks; | 159 // Number of currently running tasks. |
| 160 size_t num_running_tasks; |
| 161 }; | 161 }; |
| 162 | 162 |
| 163 typedef base::ScopedPtrHashMap<int, TaskNamespace> TaskNamespaceMap; | 163 typedef base::ScopedPtrHashMap<int, TaskNamespace> TaskNamespaceMap; |
| 164 | 164 |
| 165 static bool CompareTaskPriority(const internal::GraphNode* a, | 165 static bool CompareTaskPriority(const PrioritizedTask& a, |
| 166 const internal::GraphNode* b) { | 166 const PrioritizedTask& b) { |
| 167 // In this system, numerically lower priority is run first. | 167 // In this system, numerically lower priority is run first. |
| 168 if (a->priority() != b->priority()) | 168 return a.priority > b.priority; |
| 169 return a->priority() > b->priority(); | |
| 170 | |
| 171 // Run task with most dependents first when priority is the same. | |
| 172 return a->dependents().size() < b->dependents().size(); | |
| 173 } | 169 } |
| 174 | 170 |
| 175 static bool CompareTaskNamespacePriority(const TaskNamespace* a, | 171 static bool CompareTaskNamespacePriority(const TaskNamespace* a, |
| 176 const TaskNamespace* b) { | 172 const TaskNamespace* b) { |
| 177 DCHECK(!a->ready_to_run_tasks.empty()); | 173 DCHECK(!a->ready_to_run_tasks.empty()); |
| 178 DCHECK(!b->ready_to_run_tasks.empty()); | 174 DCHECK(!b->ready_to_run_tasks.empty()); |
| 179 | 175 |
| 180 // Compare based on task priority of the ready_to_run_tasks heap | 176 // Compare based on task priority of the ready_to_run_tasks heap |
| 181 // .front() will hold the max element of the heap, | 177 // .front() will hold the max element of the heap, |
| 182 // except after pop_heap, when max element is moved to .back(). | 178 // except after pop_heap, when max element is moved to .back(). |
| 183 return CompareTaskPriority(a->ready_to_run_tasks.front(), | 179 return CompareTaskPriority(a->ready_to_run_tasks.front(), |
| 184 b->ready_to_run_tasks.front()); | 180 b->ready_to_run_tasks.front()); |
| 185 } | 181 } |
| 186 | 182 |
| 187 static bool HasFinishedRunningTasksInNamespace( | 183 static bool HasFinishedRunningTasksInNamespace( |
| 188 TaskNamespace* task_namespace) { | 184 const TaskNamespace* task_namespace) { |
| 189 return task_namespace->pending_tasks.empty() && | 185 return !task_namespace->num_running_tasks && |
| 190 task_namespace->running_tasks.empty(); | 186 task_namespace->ready_to_run_tasks.empty(); |
| 191 } | 187 } |
| 192 | 188 |
| 193 // Overridden from base::DelegateSimpleThread: | 189 // Overridden from base::DelegateSimpleThread: |
| 194 virtual void Run() OVERRIDE; | 190 virtual void Run() OVERRIDE; |
| 195 | 191 |
| 196 // Run next task. Caller must acquire |lock_| prior to calling this | 192 // Run next task. Caller must acquire |lock_| prior to calling this |
| 197 // function and make sure at least one task is ready to run. | 193 // function and make sure at least one task is ready to run. |
| 198 void RunTaskWithLockAcquired(int thread_index); | 194 void RunTaskWithLockAcquired(int thread_index); |
| 199 | 195 |
| 200 // This lock protects all members of this class. Do not read or modify | 196 // This lock protects all members of this class. Do not read or modify |
| (...skipping 16 matching lines...) Expand all Loading... |
| 217 // tasks not yet collected. | 213 // tasks not yet collected. |
| 218 TaskNamespaceMap namespaces_; | 214 TaskNamespaceMap namespaces_; |
| 219 | 215 |
| 220 // Ordered set of task namespaces that have ready to run tasks. | 216 // Ordered set of task namespaces that have ready to run tasks. |
| 221 TaskNamespace::Vector ready_to_run_namespaces_; | 217 TaskNamespace::Vector ready_to_run_namespaces_; |
| 222 | 218 |
| 223 // Provides each running thread loop with a unique index. First thread | 219 // Provides each running thread loop with a unique index. First thread |
| 224 // loop index is 0. | 220 // loop index is 0. |
| 225 unsigned next_thread_index_; | 221 unsigned next_thread_index_; |
| 226 | 222 |
| 223 // This set contains all currently running tasks. |
| 224 typedef std::vector<const Task*> TaskVector; |
| 225 TaskVector running_tasks_; |
| 226 |
| 227 // Set during shutdown. Tells workers to exit when no more tasks | 227 // Set during shutdown. Tells workers to exit when no more tasks |
| 228 // are pending. | 228 // are pending. |
| 229 bool shutdown_; | 229 bool shutdown_; |
| 230 | 230 |
| 231 ScopedPtrDeque<base::DelegateSimpleThread> workers_; | 231 ScopedPtrDeque<base::DelegateSimpleThread> workers_; |
| 232 | 232 |
| 233 DISALLOW_COPY_AND_ASSIGN(TaskGraphRunner); | 233 DISALLOW_COPY_AND_ASSIGN(TaskGraphRunner); |
| 234 }; | 234 }; |
| 235 | 235 |
| 236 } // namespace internal | 236 } // namespace internal |
| 237 } // namespace cc | 237 } // namespace cc |
| 238 | 238 |
| 239 #endif // CC_RESOURCES_TASK_GRAPH_RUNNER_H_ | 239 #endif // CC_RESOURCES_TASK_GRAPH_RUNNER_H_ |
| OLD | NEW |