Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(334)

Side by Side Diff: cc/resources/worker_pool.cc

Issue 73923003: Shared Raster Worker Threads (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: WIP - code review changes Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « cc/resources/worker_pool.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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 #include "cc/resources/worker_pool.h" 5 #include "cc/resources/worker_pool.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <queue> 8 #include <queue>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/command_line.h"
11 #include "base/containers/hash_tables.h" 12 #include "base/containers/hash_tables.h"
12 #include "base/debug/trace_event.h" 13 #include "base/debug/trace_event.h"
14 #include "base/lazy_instance.h"
15 #include "base/memory/linked_ptr.h"
13 #include "base/strings/stringprintf.h" 16 #include "base/strings/stringprintf.h"
14 #include "base/synchronization/condition_variable.h" 17 #include "base/synchronization/condition_variable.h"
15 #include "base/threading/simple_thread.h" 18 #include "base/threading/simple_thread.h"
16 #include "base/threading/thread_restrictions.h" 19 #include "base/threading/thread_restrictions.h"
17 #include "cc/base/scoped_ptr_deque.h" 20 #include "cc/base/scoped_ptr_deque.h"
21 #include "cc/base/switches.h"
18 22
19 namespace cc { 23 namespace cc {
20 24
21 namespace internal { 25 namespace {
22 26
23 WorkerPoolTask::WorkerPoolTask() 27 // TaskGraphRunner will be able to run task graphs
24 : did_schedule_(false), 28 // from multiple workerpool instances. All members are guarded
25 did_run_(false), 29 // by |lock_|.
reveman 2013/12/20 01:53:24 nit: s/will be able to/can process/ and I think yo
sohanjg 2013/12/20 10:09:29 Done.
26 did_complete_(false) { 30 class TaskGraphRunner : public base::DelegateSimpleThread::Delegate {
27 } 31 public:
32 TaskGraphRunner(size_t num_threads, const std::string& thread_name_prefix);
33 virtual ~TaskGraphRunner();
reveman 2013/12/20 01:53:24 nit: blankline between ctor/dtor and other member
sohanjg 2013/12/20 10:09:29 Done.
34 void Register(const WorkerPool* worker_pool);
35 void Unregister(const WorkerPool* worker_pool);
36 void Shutdown();
28 37
29 WorkerPoolTask::~WorkerPoolTask() { 38 typedef WorkerPool::TaskGraph TaskGraph;
30 DCHECK_EQ(did_schedule_, did_complete_);
31 DCHECK(!did_run_ || did_schedule_);
32 DCHECK(!did_run_ || did_complete_);
33 }
34 39
35 void WorkerPoolTask::DidSchedule() { 40 typedef WorkerPool::TaskVector TaskVector;
reveman 2013/12/20 01:53:24 can these typedefs be private?
sohanjg 2013/12/20 10:09:29 SetTaskGraph, CollectCompletedTasks will need the
reveman 2013/12/20 16:16:02 Current code is fine. Just move the typedefs above
36 DCHECK(!did_complete_);
37 did_schedule_ = true;
38 }
39
40 void WorkerPoolTask::WillRun() {
41 DCHECK(did_schedule_);
42 DCHECK(!did_complete_);
43 DCHECK(!did_run_);
44 }
45
46 void WorkerPoolTask::DidRun() {
47 did_run_ = true;
48 }
49
50 void WorkerPoolTask::WillComplete() {
51 DCHECK(!did_complete_);
52 }
53
54 void WorkerPoolTask::DidComplete() {
55 DCHECK(did_schedule_);
56 DCHECK(!did_complete_);
57 did_complete_ = true;
58 }
59
60 bool WorkerPoolTask::HasFinishedRunning() const {
61 return did_run_;
62 }
63
64 bool WorkerPoolTask::HasCompleted() const {
65 return did_complete_;
66 }
67
68 GraphNode::GraphNode(internal::WorkerPoolTask* task, unsigned priority)
69 : task_(task),
70 priority_(priority),
71 num_dependencies_(0) {
72 }
73
74 GraphNode::~GraphNode() {
75 }
76
77 } // namespace internal
78
79 // Internal to the worker pool. Any data or logic that needs to be
80 // shared between threads lives in this class. All members are guarded
81 // by |lock_|.
82 class WorkerPool::Inner : public base::DelegateSimpleThread::Delegate {
83 public:
84 Inner(size_t num_threads, const std::string& thread_name_prefix);
85 virtual ~Inner();
86
87 void Shutdown();
88 41
89 // Schedule running of tasks in |graph|. Tasks previously scheduled but 42 // Schedule running of tasks in |graph|. Tasks previously scheduled but
90 // no longer needed will be canceled unless already running. Canceled 43 // no longer needed will be canceled unless already running. Canceled
91 // tasks are moved to |completed_tasks_| without being run. The result 44 // tasks are moved to |completed_tasks| without being run. The result
92 // is that once scheduled, a task is guaranteed to end up in the 45 // is that once scheduled, a task is guaranteed to end up in the
93 // |completed_tasks_| queue even if they later get canceled by another 46 // |completed_tasks| queue even if they later get canceled by another
94 // call to SetTaskGraph(). 47 // call to SetTaskGraph().
95 void SetTaskGraph(TaskGraph* graph); 48 void SetTaskGraph(const WorkerPool* worker_pool, TaskGraph* graph);
96 49
97 // Collect all completed tasks in |completed_tasks|. 50 // Collect all completed tasks in |completed_tasks|.
98 void CollectCompletedTasks(TaskVector* completed_tasks); 51 void CollectCompletedTasks(const WorkerPool* worker_pool,
52 TaskVector* completed_tasks);
reveman 2013/12/20 01:53:24 nit: "TaskVector* co.." should vertically align wi
sohanjg 2013/12/20 10:09:29 Done.
99 53
100 private: 54 private:
101 class PriorityComparator { 55 class TaskPriorityComparator {
102 public: 56 public:
103 bool operator()(const internal::GraphNode* a, 57 bool operator()(internal::GraphNode* a,
104 const internal::GraphNode* b) { 58 internal::GraphNode* b) {
105 // In this system, numerically lower priority is run first. 59 // In this system, numerically lower priority is run first.
106 if (a->priority() != b->priority()) 60 if (a->priority() != b->priority())
107 return a->priority() > b->priority(); 61 return a->priority() > b->priority();
108 62
109 // Run task with most dependents first when priority is the same. 63 // Run task with most dependents first when priority is the same.
110 return a->dependents().size() < b->dependents().size(); 64 return a->dependents().size() < b->dependents().size();
111 } 65 }
112 }; 66 };
113 67
68 // Ordered set of tasks that are ready to run.
69 typedef std::priority_queue<internal::GraphNode*,
70 std::vector<internal::GraphNode*>,
71 TaskPriorityComparator> TaskQueue;
72
73 struct TaskNamespace {
74 TaskGraph pending_tasks;
75 TaskGraph running_tasks;
76 TaskVector completed_tasks;
77 TaskQueue ready_to_run_tasks;
78 };
79
80 class TaskNamespacePriorityComparator {
reveman 2013/12/19 19:35:49 nit: remove one space between class and TaskNamesp
sohanjg 2013/12/20 10:09:29 Done.
81 public:
reveman 2013/12/19 19:35:49 nit: "public:" should be indented one space.
sohanjg 2013/12/20 10:09:29 Done.
82 bool operator()(TaskNamespace* a,
83 TaskNamespace* b) {
reveman 2013/12/19 19:35:49 nit: "TaskNamespace* b" vertically aligned with "T
sohanjg 2013/12/20 10:09:29 Done.
84 return comparator_.operator()(a->ready_to_run_tasks.top(),
85 b->ready_to_run_tasks.top());
reveman 2013/12/19 19:35:49 nit: "b->ready_to_run_tasks.top()" veritcally alig
sohanjg 2013/12/20 10:09:29 Done.
86 }
87 TaskPriorityComparator comparator_;
reveman 2013/12/19 19:35:49 nit: s/comparator_/task_comparator_/
sohanjg 2013/12/20 10:09:29 Done.
88 };
89
90 typedef std::map<const WorkerPool*,
91 linked_ptr<TaskNamespace> > TaskNamespaceMap;
reveman 2013/12/19 19:35:49 nit: fix style: typedef std::map<const WorkerPool
sohanjg 2013/12/20 10:09:29 Done.
92
93 typedef std::priority_queue<TaskNamespace*,
reveman 2013/12/20 01:53:24 please add this comment above this: // Ordered set
sohanjg 2013/12/20 10:09:29 Done.
94 std::vector<TaskNamespace*>,
95 TaskNamespacePriorityComparator> NamespaceQueue;
reveman 2013/12/19 19:35:49 nit: TaskNamespaceQueue
sohanjg 2013/12/20 10:09:29 Done.
96
114 // Overridden from base::DelegateSimpleThread: 97 // Overridden from base::DelegateSimpleThread:
115 virtual void Run() OVERRIDE; 98 virtual void Run() OVERRIDE;
116 99
117 // This lock protects all members of this class except 100 // This lock protects all members of this class except
118 // |worker_pool_on_origin_thread_|. Do not read or modify anything 101 // |worker_pool_on_origin_thread_|. Do not read or modify anything
119 // without holding this lock. Do not block while holding this lock. 102 // without holding this lock. Do not block while holding this lock.
120 mutable base::Lock lock_; 103 mutable base::Lock lock_;
121 104
122 // Condition variable that is waited on by worker threads until new 105 // Condition variable that is waited on by worker threads until new
123 // tasks are ready to run or shutdown starts. 106 // tasks are ready to run or shutdown starts.
124 base::ConditionVariable has_ready_to_run_tasks_cv_; 107 base::ConditionVariable has_ready_to_run_tasks_cv_;
125 108
126 // Provides each running thread loop with a unique index. First thread 109 // Provides each running thread loop with a unique index. First thread
127 // loop index is 0. 110 // loop index is 0.
128 unsigned next_thread_index_; 111 unsigned next_thread_index_;
129 112
130 // Set during shutdown. Tells workers to exit when no more tasks 113 // Set during shutdown. Tells workers to exit when no more tasks
131 // are pending. 114 // are pending.
132 bool shutdown_; 115 bool shutdown_;
133 116
134 // This set contains all pending tasks.
135 GraphNodeMap pending_tasks_;
136
137 // Ordered set of tasks that are ready to run.
138 typedef std::priority_queue<internal::GraphNode*,
139 std::vector<internal::GraphNode*>,
140 PriorityComparator> TaskQueue;
141 TaskQueue ready_to_run_tasks_;
142
143 // This set contains all currently running tasks.
144 GraphNodeMap running_tasks_;
145
146 // Completed tasks not yet collected by origin thread.
147 TaskVector completed_tasks_;
148
149 ScopedPtrDeque<base::DelegateSimpleThread> workers_; 117 ScopedPtrDeque<base::DelegateSimpleThread> workers_;
150 118
151 DISALLOW_COPY_AND_ASSIGN(Inner); 119 TaskNamespaceMap namespaces_;
120
121 NamespaceQueue ready_to_run_namespaces_;
122
123 DISALLOW_COPY_AND_ASSIGN(TaskGraphRunner);
152 }; 124 };
153 125
154 WorkerPool::Inner::Inner( 126 class CC_EXPORT DerivedInner : public TaskGraphRunner {
reveman 2013/12/20 01:53:24 This needs a better name. I think CompositorRaster
sohanjg 2013/12/20 10:09:29 Done.
127 public:
128 DerivedInner();
reveman 2013/12/20 01:53:24 the implementation of this can be inlined.
sohanjg 2013/12/20 10:09:29 Done.
129 };
reveman 2013/12/20 01:53:24 please move this class below the TaskGraphRunner i
sohanjg 2013/12/20 10:09:29 Done.
130
131 base::LazyInstance<DerivedInner> g_workerpool_inner;
reveman 2013/12/20 01:53:24 I think this should be "g_task_graph_runner = LAZY
sohanjg 2013/12/20 10:09:29 Done.
132
133
134 TaskGraphRunner::TaskGraphRunner(
155 size_t num_threads, const std::string& thread_name_prefix) 135 size_t num_threads, const std::string& thread_name_prefix)
156 : lock_(), 136 : lock_(),
157 has_ready_to_run_tasks_cv_(&lock_), 137 has_ready_to_run_tasks_cv_(&lock_),
158 next_thread_index_(0), 138 next_thread_index_(0),
159 shutdown_(false) { 139 shutdown_(false) {
160 base::AutoLock lock(lock_); 140 base::AutoLock lock(lock_);
161 141
162 while (workers_.size() < num_threads) { 142 while (workers_.size() < num_threads) {
163 scoped_ptr<base::DelegateSimpleThread> worker = make_scoped_ptr( 143 scoped_ptr<base::DelegateSimpleThread> worker = make_scoped_ptr(
164 new base::DelegateSimpleThread( 144 new base::DelegateSimpleThread(
165 this, 145 this,
166 thread_name_prefix + 146 thread_name_prefix +
167 base::StringPrintf( 147 base::StringPrintf(
168 "Worker%u", 148 "Worker%u",
169 static_cast<unsigned>(workers_.size() + 1)).c_str())); 149 static_cast<unsigned>(workers_.size() + 1)).c_str()));
170 worker->Start(); 150 worker->Start();
171 #if defined(OS_ANDROID) || defined(OS_LINUX) 151 #if defined(OS_ANDROID) || defined(OS_LINUX)
172 worker->SetThreadPriority(base::kThreadPriority_Background); 152 worker->SetThreadPriority(base::kThreadPriority_Background);
173 #endif 153 #endif
174 workers_.push_back(worker.Pass()); 154 workers_.push_back(worker.Pass());
175 } 155 }
176 } 156 }
177 157
178 WorkerPool::Inner::~Inner() { 158 TaskGraphRunner::~TaskGraphRunner() {
179 base::AutoLock lock(lock_); 159 base::AutoLock lock(lock_);
180 160
181 DCHECK(shutdown_); 161 DCHECK(shutdown_);
182 162 DCHECK_EQ(0u, ready_to_run_namespaces_.size());
183 DCHECK_EQ(0u, pending_tasks_.size());
184 DCHECK_EQ(0u, ready_to_run_tasks_.size());
185 DCHECK_EQ(0u, running_tasks_.size());
186 DCHECK_EQ(0u, completed_tasks_.size());
187 } 163 }
188 164
189 void WorkerPool::Inner::Shutdown() { 165 void TaskGraphRunner::Register(const WorkerPool* worker_pool) {
166 base::AutoLock lock(lock_);
167
168 DCHECK(namespaces_.find(worker_pool) == namespaces_.end());
169 linked_ptr<TaskNamespace> task_set = make_linked_ptr(new TaskNamespace());
170 namespaces_[worker_pool] = task_set;
171 }
reveman 2013/12/20 01:53:24 nit: add blank line between these functions
sohanjg 2013/12/20 10:09:29 Done.
172 void TaskGraphRunner::Unregister(const WorkerPool* worker_pool) {
173 base::AutoLock lock(lock_);
174
175 DCHECK(namespaces_.find(worker_pool) != namespaces_.end());
176 namespaces_.erase(worker_pool);
177 }
178
179 void TaskGraphRunner::Shutdown() {
190 { 180 {
191 base::AutoLock lock(lock_); 181 base::AutoLock lock(lock_);
192 182
193 DCHECK(!shutdown_); 183 DCHECK(!shutdown_);
194 shutdown_ = true; 184 shutdown_ = true;
195
196 // Wake up a worker so it knows it should exit. This will cause all workers 185 // Wake up a worker so it knows it should exit. This will cause all workers
197 // to exit as each will wake up another worker before exiting. 186 // to exit as each will wake up another worker before exiting.
198 has_ready_to_run_tasks_cv_.Signal(); 187 has_ready_to_run_tasks_cv_.Signal();
199 } 188 }
200 189
201 while (workers_.size()) { 190 while (workers_.size()) {
202 scoped_ptr<base::DelegateSimpleThread> worker = workers_.take_front(); 191 scoped_ptr<base::DelegateSimpleThread> worker = workers_.take_front();
203 // http://crbug.com/240453 - Join() is considered IO and will block this 192 // http://crbug.com/240453 - Join() is considered IO and will block this
204 // thread. See also http://crbug.com/239423 for further ideas. 193 // thread. See also http://crbug.com/239423 for further ideas.
205 base::ThreadRestrictions::ScopedAllowIO allow_io; 194 base::ThreadRestrictions::ScopedAllowIO allow_io;
206 worker->Join(); 195 worker->Join();
207 } 196 }
208 } 197 }
209 198
210 void WorkerPool::Inner::SetTaskGraph(TaskGraph* graph) { 199 void TaskGraphRunner::SetTaskGraph(const WorkerPool* worker_pool,
200 TaskGraph* graph) {
reveman 2013/12/19 19:35:49 nit: "TaskGraph* graph" vertically aligned with "c
sohanjg 2013/12/20 10:09:29 Done.
211 // It is OK to call SetTaskGraph() after shutdown if |graph| is empty. 201 // It is OK to call SetTaskGraph() after shutdown if |graph| is empty.
212 DCHECK(graph->empty() || !shutdown_); 202 DCHECK(graph->empty() || !shutdown_);
213 203
214 GraphNodeMap new_pending_tasks; 204 TaskGraph new_pending_tasks;
215 GraphNodeMap new_running_tasks; 205 TaskGraph new_running_tasks;
216 TaskQueue new_ready_to_run_tasks; 206 TaskQueue new_ready_to_run_tasks;
207 NamespaceQueue new_ready_to_run_namespaces;
217 208
218 new_pending_tasks.swap(*graph); 209 new_pending_tasks.swap(*graph);
219 210
220 { 211 {
221 base::AutoLock lock(lock_); 212 base::AutoLock lock(lock_);
222 213
214 DCHECK(namespaces_.find(worker_pool) != namespaces_.end());
215 linked_ptr<TaskNamespace> task_namespace = namespaces_[worker_pool];
reveman 2013/12/19 19:35:49 This can be a raw pointer: TaskNamespace* task_nam
sohanjg 2013/12/20 10:09:29 Done.
216
223 // First remove all completed tasks from |new_pending_tasks| and 217 // First remove all completed tasks from |new_pending_tasks| and
224 // adjust number of dependencies. 218 // adjust number of dependencies.
225 for (TaskVector::iterator it = completed_tasks_.begin(); 219 for (TaskVector::iterator it = task_namespace->completed_tasks.begin();
226 it != completed_tasks_.end(); ++it) { 220 it != task_namespace->completed_tasks.end(); ++it) {
227 internal::WorkerPoolTask* task = it->get(); 221 internal::WorkerPoolTask* task = it->get();
228
229 scoped_ptr<internal::GraphNode> node = new_pending_tasks.take_and_erase( 222 scoped_ptr<internal::GraphNode> node = new_pending_tasks.take_and_erase(
230 task); 223 task);
231 if (node) { 224 if (node) {
232 for (internal::GraphNode::Vector::const_iterator it = 225 for (internal::GraphNode::Vector::const_iterator it =
233 node->dependents().begin(); 226 node->dependents().begin();
234 it != node->dependents().end(); ++it) { 227 it != node->dependents().end(); ++it) {
235 internal::GraphNode* dependent_node = *it; 228 internal::GraphNode* dependent_node = *it;
236 dependent_node->remove_dependency(); 229 dependent_node->remove_dependency();
237 } 230 }
238 } 231 }
239 } 232 }
240
241 // Build new running task set. 233 // Build new running task set.
242 for (GraphNodeMap::iterator it = running_tasks_.begin(); 234 for (TaskGraph::iterator it =
243 it != running_tasks_.end(); ++it) { 235 task_namespace->running_tasks.begin();
reveman 2013/12/19 19:35:49 nit: move to previous line if it fits. otherwise 4
sohanjg 2013/12/20 10:09:29 Done.
236 it != task_namespace->running_tasks.end(); ++it) {
reveman 2013/12/19 19:35:49 nit: "it != task_n..." vertically aligned with "Ta
sohanjg 2013/12/20 10:09:29 Done.
244 internal::WorkerPoolTask* task = it->first; 237 internal::WorkerPoolTask* task = it->first;
245 // Transfer scheduled task value from |new_pending_tasks| to 238 // Transfer scheduled task value from |new_pending_tasks| to
246 // |new_running_tasks| if currently running. Value must be set to 239 // |new_running_tasks| if currently running. Value must be set to
247 // NULL if |new_pending_tasks| doesn't contain task. This does 240 // NULL if |new_pending_tasks| doesn't contain task. This does
248 // the right in both cases. 241 // the right in both cases.
249 new_running_tasks.set(task, new_pending_tasks.take_and_erase(task)); 242 new_running_tasks.set(task, new_pending_tasks.take_and_erase(task));
250 } 243 }
reveman 2013/12/19 19:35:49 nit: no need to add this space.
sohanjg 2013/12/20 10:09:29 Done.
251 244
252 // Build new "ready to run" tasks queue. 245 // Build new "ready to run" tasks queue.
253 // TODO(reveman): Create this queue when building the task graph instead. 246 // TODO(reveman): Create this queue when building the task graph instead.
254 for (GraphNodeMap::iterator it = new_pending_tasks.begin(); 247 for (TaskGraph::iterator it = new_pending_tasks.begin();
255 it != new_pending_tasks.end(); ++it) { 248 it != new_pending_tasks.end(); ++it) {
256 internal::WorkerPoolTask* task = it->first; 249 internal::WorkerPoolTask* task = it->first;
257 DCHECK(task); 250 DCHECK(task);
258 internal::GraphNode* node = it->second; 251 internal::GraphNode* node = it->second;
259 252
260 // Completed tasks should not exist in |new_pending_tasks|. 253 // Completed tasks should not exist in |new_pending_tasks|.
261 DCHECK(!task->HasFinishedRunning()); 254 DCHECK(!task->HasFinishedRunning());
262 255
263 // Call DidSchedule() to indicate that this task has been scheduled. 256 // Call DidSchedule() to indicate that this task has been scheduled.
264 // Note: This is only for debugging purposes. 257 // Note: This is only for debugging purposes.
265 task->DidSchedule(); 258 task->DidSchedule();
266 259
267 if (!node->num_dependencies()) 260 if (!node->num_dependencies())
268 new_ready_to_run_tasks.push(node); 261 new_ready_to_run_tasks.push(node);
269 262
270 // Erase the task from old pending tasks. 263 // Erase the task from old pending tasks.
271 pending_tasks_.erase(task); 264 task_namespace->pending_tasks.erase(task);
265
272 } 266 }
273 267
274 completed_tasks_.reserve(completed_tasks_.size() + pending_tasks_.size()); 268 task_namespace->completed_tasks.reserve(
269 task_namespace->completed_tasks.size() +
270 task_namespace->pending_tasks.size());
275 271
276 // The items left in |pending_tasks_| need to be canceled. 272 // The items left in |pending_tasks| need to be canceled.
277 for (GraphNodeMap::const_iterator it = pending_tasks_.begin(); 273 for (TaskGraph::const_iterator it =
278 it != pending_tasks_.end(); 274 task_namespace->pending_tasks.begin();
reveman 2013/12/19 19:35:49 nit: move to previous line if it fits. otherwise 4
sohanjg 2013/12/20 10:09:29 Done.
279 ++it) { 275 it != task_namespace->pending_tasks.end();
reveman 2013/12/19 19:35:49 nit: "it != task_n..." vertically aligned with "Ta
sohanjg 2013/12/20 10:09:29 Done.
280 completed_tasks_.push_back(it->first); 276 ++it) {
reveman 2013/12/19 19:35:49 please move this to previous line to be consistent
sohanjg 2013/12/20 10:09:29 Done.
277 task_namespace->completed_tasks.push_back(it->first);
reveman 2013/12/19 19:35:49 nit: this should be indented 2 spaces, not 4
sohanjg 2013/12/20 10:09:29 Done.
281 } 278 }
282 279
283 // Swap task sets. 280 // Swap task sets.
284 // Note: old tasks are intentionally destroyed after releasing |lock_|. 281 // Note: old tasks are intentionally destroyed after releasing |lock_|.
285 pending_tasks_.swap(new_pending_tasks); 282 task_namespace->pending_tasks.swap(new_pending_tasks);
286 running_tasks_.swap(new_running_tasks); 283 task_namespace->running_tasks.swap(new_running_tasks);
287 std::swap(ready_to_run_tasks_, new_ready_to_run_tasks); 284 std::swap(task_namespace->ready_to_run_tasks, new_ready_to_run_tasks);
288 285
289 // If |ready_to_run_tasks_| is empty, it means we either have 286 // Re-create the ready_to_run_namespaces_ and add new TaskNamespace
287 while (!ready_to_run_namespaces_.empty()) {
288 new_ready_to_run_namespaces.push(ready_to_run_namespaces_.top());
289 ready_to_run_namespaces_.pop();
290 }
reveman 2013/12/19 19:35:49 Please ignore ready_to_run_namespaces_ here and si
sohanjg 2013/12/20 10:09:29 Done.
291 std::swap(ready_to_run_namespaces_, new_ready_to_run_namespaces);
292 ready_to_run_namespaces_.push(task_namespace.get());
reveman 2013/12/19 19:35:49 this line should not be here if you do what I sugg
sohanjg 2013/12/20 10:09:29 Done.
293
294 // If |ready_to_run_tasks| is empty, it means we either have
290 // running tasks, or we have no pending tasks. 295 // running tasks, or we have no pending tasks.
291 DCHECK(!ready_to_run_tasks_.empty() || 296 DCHECK(!task_namespace->ready_to_run_tasks.empty() ||
292 (pending_tasks_.empty() || !running_tasks_.empty())); 297 (task_namespace->pending_tasks.empty() ||
298 !task_namespace->running_tasks.empty()));
reveman 2013/12/19 19:35:49 nit: this last line should be indented one more sp
sohanjg 2013/12/20 10:09:29 Done.
293 299
294 // If there is more work available, wake up worker thread. 300 // If there is more work available, wake up worker thread.
295 if (!ready_to_run_tasks_.empty()) 301 if (!task_namespace->ready_to_run_tasks.empty())
reveman 2013/12/19 19:35:49 Please change this to: if (!ready_to_run_namespac
sohanjg 2013/12/20 10:09:29 Done.
296 has_ready_to_run_tasks_cv_.Signal(); 302 has_ready_to_run_tasks_cv_.Signal();
297 } 303 }
298 } 304 }
299 305
300 void WorkerPool::Inner::CollectCompletedTasks(TaskVector* completed_tasks) { 306 void TaskGraphRunner::CollectCompletedTasks
307 (const WorkerPool* worker_pool, TaskVector* completed_tasks) {
reveman 2013/12/20 01:53:24 nit: "(" on previous line. "const WorkerPool* wor.
sohanjg 2013/12/20 10:09:29 Done.
301 base::AutoLock lock(lock_); 308 base::AutoLock lock(lock_);
302 309
303 DCHECK_EQ(0u, completed_tasks->size()); 310 DCHECK_EQ(0u, completed_tasks->size());
304 completed_tasks->swap(completed_tasks_); 311 if (!ready_to_run_namespaces_.empty())
reveman 2013/12/20 01:53:24 no need for this conditional.
sohanjg 2013/12/20 10:09:29 i am seeing a crash when we try to access top if i
312 completed_tasks->swap(ready_to_run_namespaces_.top()->completed_tasks);
305 } 313 }
306 314
307 void WorkerPool::Inner::Run() { 315 void TaskGraphRunner::Run() {
308 base::AutoLock lock(lock_); 316 base::AutoLock lock(lock_);
309 317
310 // Get a unique thread index. 318 // Get a unique thread index.
311 int thread_index = next_thread_index_++; 319 int thread_index = next_thread_index_++;
320 TaskNamespace* ready_to_run_task_set = NULL;
reveman 2013/12/20 01:53:24 move to "while (true) {" scope
sohanjg 2013/12/20 10:09:29 Done.
312 321
313 while (true) { 322 while (true) {
314 if (ready_to_run_tasks_.empty()) { 323 if ((ready_to_run_namespaces_.empty()) ||
reveman 2013/12/20 01:53:24 this check should only be "ready_to_run_namespaces
sohanjg 2013/12/20 10:09:29 Done.
315 // Exit when shutdown is set and no more tasks are pending. 324 (ready_to_run_task_set &&
316 if (shutdown_ && pending_tasks_.empty()) 325 ready_to_run_task_set->ready_to_run_tasks.empty())) {
317 break; 326 // Exit when shutdown is set and no more tasks are pending.
reveman 2013/12/20 01:53:24 nit: this and following lines are indented incorre
sohanjg 2013/12/20 10:09:29 Done.
318 327 if (shutdown_ && ready_to_run_task_set &&
reveman 2013/12/20 01:53:24 Let's just make this "if (shutdown_)". We'll make
sohanjg 2013/12/20 10:09:29 Done.
319 // Wait for more tasks. 328 ready_to_run_task_set->pending_tasks.empty()) {
320 has_ready_to_run_tasks_cv_.Wait(); 329 break;
reveman 2013/12/20 01:53:24 nit: wrong indent here too
sohanjg 2013/12/20 10:09:29 Done.
321 continue; 330 }
331 // Wait for more tasks.
332 has_ready_to_run_tasks_cv_.Wait();
333 continue;
322 } 334 }
323 335
324 // Take top priority task from |ready_to_run_tasks_|. 336 // Take top priority TaskNamespace from |ready_to_run_namespaces_|.
337 ready_to_run_task_set = ready_to_run_namespaces_.top();
reveman 2013/12/20 01:53:24 You need to pop the namespace too. Think this shou
sohanjg 2013/12/20 10:09:29 Done. The pop i had done in the end of the loop,
338
339 // Take top priority task from |ready_to_run_tasks|.
325 scoped_refptr<internal::WorkerPoolTask> task( 340 scoped_refptr<internal::WorkerPoolTask> task(
326 ready_to_run_tasks_.top()->task()); 341 ready_to_run_task_set->ready_to_run_tasks.top()->task());
327 ready_to_run_tasks_.pop(); 342 ready_to_run_task_set->ready_to_run_tasks.pop();
328 343
reveman 2013/12/20 01:53:24 Here after taking the top task off the queue, you
sohanjg 2013/12/20 10:09:29 Done.
329 // Move task from |pending_tasks_| to |running_tasks_|. 344
330 DCHECK(pending_tasks_.contains(task.get())); 345 // Move task from |pending_tasks| to |running_tasks|.
331 DCHECK(!running_tasks_.contains(task.get())); 346 DCHECK(ready_to_run_task_set->pending_tasks.contains(task.get()));
332 running_tasks_.set(task.get(), pending_tasks_.take_and_erase(task.get())); 347 DCHECK(!ready_to_run_task_set->running_tasks.contains(task.get()));
348
349 ready_to_run_task_set->running_tasks.set(
350 task.get(), ready_to_run_task_set->pending_tasks.take_and_erase
reveman 2013/12/20 01:53:24 nit: move "ready_to_run_task_set->pendi" to the ne
sohanjg 2013/12/20 10:09:29 Done.
351 (task.get()));
333 352
334 // There may be more work available, so wake up another worker thread. 353 // There may be more work available, so wake up another worker thread.
335 has_ready_to_run_tasks_cv_.Signal(); 354 has_ready_to_run_tasks_cv_.Signal();
336 355
356
reveman 2013/12/20 01:53:24 nit: no need to add this line
sohanjg 2013/12/20 10:09:29 Done.
337 // Call WillRun() before releasing |lock_| and running task. 357 // Call WillRun() before releasing |lock_| and running task.
338 task->WillRun(); 358 task->WillRun();
339 359
340 { 360 {
341 base::AutoUnlock unlock(lock_); 361 base::AutoUnlock unlock(lock_);
342
reveman 2013/12/20 01:53:24 nit: no need to remove this line
343 task->RunOnWorkerThread(thread_index); 362 task->RunOnWorkerThread(thread_index);
344 } 363 }
345 364
346 // This will mark task as finished running. 365 // This will mark task as finished running.
347 task->DidRun(); 366 task->DidRun();
348 367
349 // Now iterate over all dependents to remove dependency and check 368 // Now iterate over all dependents to remove dependency and check
350 // if they are ready to run. 369 // if they are ready to run.
351 scoped_ptr<internal::GraphNode> node = running_tasks_.take_and_erase( 370 scoped_ptr<internal::GraphNode> node =
371 ready_to_run_task_set->running_tasks.take_and_erase(
352 task.get()); 372 task.get());
353 if (node) { 373 if (node) {
reveman 2013/12/20 01:53:24 nit: not need to change indention of this and foll
sohanjg 2013/12/20 10:09:29 Done.
354 for (internal::GraphNode::Vector::const_iterator it = 374 for (internal::GraphNode::Vector::const_iterator it =
355 node->dependents().begin(); 375 node->dependents().begin();
356 it != node->dependents().end(); ++it) { 376 it != node->dependents().end(); ++it) {
357 internal::GraphNode* dependent_node = *it; 377 internal::GraphNode* dependent_node = *it;
358 378
359 dependent_node->remove_dependency(); 379 dependent_node->remove_dependency();
360 // Task is ready if it has no dependencies. Add it to 380 // Task is ready if it has no dependencies. Add it to
361 // |ready_to_run_tasks_|. 381 // |ready_to_run_tasks|.
362 if (!dependent_node->num_dependencies()) 382 if (!dependent_node->num_dependencies())
363 ready_to_run_tasks_.push(dependent_node); 383 ready_to_run_task_set->ready_to_run_tasks.push(dependent_node);
reveman 2013/12/20 01:53:24 you need to add the task namespace to |ready_to_ru
sohanjg 2013/12/20 10:09:29 Done. This could have been taken care of, if we p
384 }
364 } 385 }
386
387 // Pop when ready_to_run_tasks is empty
388 if (ready_to_run_task_set->ready_to_run_tasks.empty()) {
389 ready_to_run_namespaces_.pop();
reveman 2013/12/20 01:53:24 what's the purpose of these lines? I think they sh
sohanjg 2013/12/20 10:09:29 Done. purpose i have explained above.
365 } 390 }
366 391
367 // Finally add task to |completed_tasks_|. 392 // Finally add task to |completed_tasks|.
368 completed_tasks_.push_back(task); 393 ready_to_run_task_set->completed_tasks.push_back(task);
369 } 394 }
370 395
371 // We noticed we should exit. Wake up the next worker so it knows it should 396 // We noticed we should exit. Wake up the next worker so it knows it should
372 // exit as well (because the Shutdown() code only signals once). 397 // exit as well (because the Shutdown() code only signals once).
373 has_ready_to_run_tasks_cv_.Signal(); 398 has_ready_to_run_tasks_cv_.Signal();
374 } 399 }
375 400
401 // Derived TaskGraphRunner Ctor
402 DerivedInner::DerivedInner(): TaskGraphRunner
403 (switches::GetNumRasterThreads(), "CompositorRaster") {
404 }
405
406 } // namespace
407
408 namespace internal {
409
410 WorkerPoolTask::WorkerPoolTask()
411 : did_schedule_(false),
412 did_run_(false),
413 did_complete_(false) {
414 }
415
416 WorkerPoolTask::~WorkerPoolTask() {
417 DCHECK_EQ(did_schedule_, did_complete_);
418 DCHECK(!did_run_ || did_schedule_);
419 DCHECK(!did_run_ || did_complete_);
420 }
421
422 void WorkerPoolTask::DidSchedule() {
423 DCHECK(!did_complete_);
424 did_schedule_ = true;
425 }
426
427 void WorkerPoolTask::WillRun() {
428 DCHECK(did_schedule_);
429 DCHECK(!did_complete_);
430 DCHECK(!did_run_);
431 }
432
433 void WorkerPoolTask::DidRun() {
434 did_run_ = true;
435 }
436
437 void WorkerPoolTask::WillComplete() {
438 DCHECK(!did_complete_);
439 }
440
441 void WorkerPoolTask::DidComplete() {
442 DCHECK(did_schedule_);
443 DCHECK(!did_complete_);
444 did_complete_ = true;
445 }
446
447 bool WorkerPoolTask::HasFinishedRunning() const {
448 return did_run_;
449 }
450
451 bool WorkerPoolTask::HasCompleted() const {
452 return did_complete_;
453 }
454
455 GraphNode::GraphNode(internal::WorkerPoolTask* task, unsigned priority)
456 : task_(task),
457 priority_(priority),
458 num_dependencies_(0) {
459 }
460
461 GraphNode::~GraphNode() {
462 }
463
464 } // namespace internal
465
466
376 WorkerPool::WorkerPool(size_t num_threads, 467 WorkerPool::WorkerPool(size_t num_threads,
377 const std::string& thread_name_prefix) 468 const std::string& thread_name_prefix)
378 : in_dispatch_completion_callbacks_(false), 469 : in_dispatch_completion_callbacks_(false) {
379 inner_(make_scoped_ptr(new Inner(num_threads, thread_name_prefix))) { 470 g_workerpool_inner.Pointer()->Register(this);
380 } 471 }
381 472
382 WorkerPool::~WorkerPool() { 473 WorkerPool::~WorkerPool() {
474 g_workerpool_inner.Pointer()->Unregister(this);
383 } 475 }
384 476
385 void WorkerPool::Shutdown() { 477 void WorkerPool::Shutdown() {
386 TRACE_EVENT0("cc", "WorkerPool::Shutdown"); 478 TRACE_EVENT0("cc", "WorkerPool::Shutdown");
387 479
388 DCHECK(!in_dispatch_completion_callbacks_); 480 DCHECK(!in_dispatch_completion_callbacks_);
389 481 g_workerpool_inner.Pointer()->Shutdown();
390 inner_->Shutdown();
391 } 482 }
392 483
393 void WorkerPool::CheckForCompletedTasks() { 484 void WorkerPool::CheckForCompletedTasks() {
394 TRACE_EVENT0("cc", "WorkerPool::CheckForCompletedTasks"); 485 TRACE_EVENT0("cc", "WorkerPool::CheckForCompletedTasks");
395 486
396 DCHECK(!in_dispatch_completion_callbacks_); 487 DCHECK(!in_dispatch_completion_callbacks_);
397 488
398 TaskVector completed_tasks; 489 TaskVector completed_tasks;
399 inner_->CollectCompletedTasks(&completed_tasks); 490 g_workerpool_inner.Pointer()->CollectCompletedTasks(this, &completed_tasks);
400 ProcessCompletedTasks(completed_tasks); 491 ProcessCompletedTasks(completed_tasks);
401 } 492 }
402 493
403 void WorkerPool::ProcessCompletedTasks( 494 void WorkerPool::ProcessCompletedTasks(
404 const TaskVector& completed_tasks) { 495 const TaskVector& completed_tasks) {
405 TRACE_EVENT1("cc", "WorkerPool::ProcessCompletedTasks", 496 TRACE_EVENT1("cc", "WorkerPool::ProcessCompletedTasks",
406 "completed_task_count", completed_tasks.size()); 497 "completed_task_count", completed_tasks.size());
407 498
408 // Worker pool instance is not reentrant while processing completed tasks. 499 // Worker pool instance is not reentrant while processing completed tasks.
409 in_dispatch_completion_callbacks_ = true; 500 in_dispatch_completion_callbacks_ = true;
410 501
411 for (TaskVector::const_iterator it = completed_tasks.begin(); 502 for (TaskVector::const_iterator it = completed_tasks.begin();
412 it != completed_tasks.end(); 503 it != completed_tasks.end();
413 ++it) { 504 ++it) {
414 internal::WorkerPoolTask* task = it->get(); 505 internal::WorkerPoolTask* task = it->get();
415 506
416 task->WillComplete(); 507 task->WillComplete();
417 task->CompleteOnOriginThread(); 508 task->CompleteOnOriginThread();
418 task->DidComplete(); 509 task->DidComplete();
419 } 510 }
420 511
421 in_dispatch_completion_callbacks_ = false; 512 in_dispatch_completion_callbacks_ = false;
422 } 513 }
423 514
424 void WorkerPool::SetTaskGraph(TaskGraph* graph) { 515 void WorkerPool::SetTaskGraph(TaskGraph* graph) {
425 TRACE_EVENT1("cc", "WorkerPool::SetTaskGraph", 516 TRACE_EVENT1("cc", "WorkerPool::SetTaskGraph",
426 "num_tasks", graph->size()); 517 "num_tasks", graph->size());
427 518
428 DCHECK(!in_dispatch_completion_callbacks_); 519 DCHECK(!in_dispatch_completion_callbacks_);
429 520 g_workerpool_inner.Pointer()->SetTaskGraph(this, graph);
430 inner_->SetTaskGraph(graph);
431 } 521 }
432 522
433 } // namespace cc 523 } // namespace cc
OLDNEW
« no previous file with comments | « cc/resources/worker_pool.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698