OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 "content/renderer/raster_worker_pool.h" | 5 #include "content/renderer/raster_worker_pool.h" |
6 | 6 |
7 #include "base/strings/stringprintf.h" | 7 #include "base/strings/stringprintf.h" |
8 #include "base/threading/thread_restrictions.h" | |
9 #include "base/trace_event/trace_event.h" | |
8 | 10 |
9 namespace content { | 11 namespace content { |
10 | 12 |
11 // A sequenced task runner which posts tasks to a RasterWorkerPool. | 13 // A sequenced task runner which posts tasks to a RasterWorkerPool. |
12 class RasterWorkerPool::RasterWorkerPoolSequencedTaskRunner | 14 class RasterWorkerPool::RasterWorkerPoolSequencedTaskRunner |
13 : public base::SequencedTaskRunner { | 15 : public base::SequencedTaskRunner { |
14 public: | 16 public: |
15 RasterWorkerPoolSequencedTaskRunner(cc::TaskGraphRunner* task_graph_runner) | 17 explicit RasterWorkerPoolSequencedTaskRunner( |
18 cc::TaskGraphRunner* task_graph_runner) | |
16 : task_graph_runner_(task_graph_runner), | 19 : task_graph_runner_(task_graph_runner), |
17 namespace_token_(task_graph_runner->GetNamespaceToken()) {} | 20 namespace_token_(task_graph_runner->GetNamespaceToken()) {} |
18 | 21 |
19 // Overridden from base::TaskRunner: | 22 // Overridden from base::TaskRunner: |
20 bool PostDelayedTask(const tracked_objects::Location& from_here, | 23 bool PostDelayedTask(const tracked_objects::Location& from_here, |
21 const base::Closure& task, | 24 const base::Closure& task, |
22 base::TimeDelta delay) override { | 25 base::TimeDelta delay) override { |
23 return PostNonNestableDelayedTask(from_here, task, delay); | 26 return PostNonNestableDelayedTask(from_here, task, delay); |
24 } | 27 } |
25 bool RunsTasksOnCurrentThread() const override { return true; } | 28 bool RunsTasksOnCurrentThread() const override { return true; } |
(...skipping 30 matching lines...) Expand all Loading... | |
56 return true; | 59 return true; |
57 } | 60 } |
58 | 61 |
59 private: | 62 private: |
60 ~RasterWorkerPoolSequencedTaskRunner() override { | 63 ~RasterWorkerPoolSequencedTaskRunner() override { |
61 task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_); | 64 task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_); |
62 task_graph_runner_->CollectCompletedTasks(namespace_token_, | 65 task_graph_runner_->CollectCompletedTasks(namespace_token_, |
63 &completed_tasks_); | 66 &completed_tasks_); |
64 }; | 67 }; |
65 | 68 |
66 cc::TaskGraphRunner* const task_graph_runner_; | |
67 | |
68 // Lock to exclusively access all the following members that are used to | 69 // Lock to exclusively access all the following members that are used to |
69 // implement the SequencedTaskRunner interfaces. | 70 // implement the SequencedTaskRunner interfaces. |
70 base::Lock lock_; | 71 base::Lock lock_; |
72 | |
73 cc::TaskGraphRunner* task_graph_runner_; | |
71 // Namespace used to schedule tasks in the task graph runner. | 74 // Namespace used to schedule tasks in the task graph runner. |
72 cc::NamespaceToken namespace_token_; | 75 cc::NamespaceToken namespace_token_; |
73 // List of tasks currently queued up for execution. | 76 // List of tasks currently queued up for execution. |
74 cc::Task::Vector tasks_; | 77 cc::Task::Vector tasks_; |
75 // Graph object used for scheduling tasks. | 78 // Graph object used for scheduling tasks. |
76 cc::TaskGraph graph_; | 79 cc::TaskGraph graph_; |
77 // Cached vector to avoid allocation when getting the list of complete | 80 // Cached vector to avoid allocation when getting the list of complete |
78 // tasks. | 81 // tasks. |
79 cc::Task::Vector completed_tasks_; | 82 cc::Task::Vector completed_tasks_; |
80 }; | 83 }; |
81 | 84 |
82 RasterWorkerPool::RasterWorkerPool() | 85 RasterWorkerPool::RasterWorkerPool() |
83 : namespace_token_(task_graph_runner_.GetNamespaceToken()) {} | 86 : namespace_token_(GetNamespaceToken()), |
87 has_ready_to_run_tasks_cv_(&lock_), | |
88 has_namespaces_with_finished_running_tasks_cv_(&lock_), | |
89 shutdown_(false) {} | |
84 | 90 |
85 void RasterWorkerPool::Start( | 91 void RasterWorkerPool::Start( |
86 int num_threads, | 92 int num_threads, |
87 const base::SimpleThread::Options& thread_options) { | 93 const base::SimpleThread::Options& thread_options) { |
88 DCHECK(threads_.empty()); | 94 DCHECK(threads_.empty()); |
89 while (threads_.size() < static_cast<size_t>(num_threads)) { | 95 while (threads_.size() < static_cast<size_t>(num_threads)) { |
90 scoped_ptr<base::DelegateSimpleThread> thread( | 96 scoped_ptr<base::DelegateSimpleThread> thread( |
91 new base::DelegateSimpleThread( | 97 new base::DelegateSimpleThread( |
92 this, base::StringPrintf("CompositorTileWorker%u", | 98 this, base::StringPrintf("CompositorTileWorker%u", |
93 static_cast<unsigned>(threads_.size() + 1)) | 99 static_cast<unsigned>(threads_.size() + 1)) |
94 .c_str(), | 100 .c_str(), |
95 thread_options)); | 101 thread_options)); |
96 thread->Start(); | 102 thread->Start(); |
97 threads_.push_back(thread.Pass()); | 103 threads_.push_back(thread.Pass()); |
98 } | 104 } |
99 } | 105 } |
100 | 106 |
101 void RasterWorkerPool::Shutdown() { | 107 void RasterWorkerPool::Shutdown() { |
102 task_graph_runner_.WaitForTasksToFinishRunning(namespace_token_); | 108 WaitForTasksToFinishRunning(namespace_token_); |
103 task_graph_runner_.CollectCompletedTasks(namespace_token_, &completed_tasks_); | 109 CollectCompletedTasks(namespace_token_, &completed_tasks_); |
104 // Shutdown raster threads. | 110 // Shutdown raster threads. |
105 task_graph_runner_.Shutdown(); | 111 { |
112 base::AutoLock lock(lock_); | |
113 | |
114 DCHECK(!work_queue_.HasReadyToRunTasks()); | |
115 DCHECK(!work_queue_.HasAnyNamespaces()); | |
116 | |
117 DCHECK(!shutdown_); | |
118 shutdown_ = true; | |
119 | |
120 // Wake up a worker so it knows it should exit. This will cause all workers | |
121 // to exit as each will wake up another worker before exiting. | |
122 has_ready_to_run_tasks_cv_.Signal(); | |
no sievers
2015/11/25 00:03:34
why not Broadcast()?
ericrk
2015/11/25 02:09:52
no reason - that does clean things up a bit.
| |
123 } | |
106 while (!threads_.empty()) { | 124 while (!threads_.empty()) { |
107 threads_.back()->Join(); | 125 threads_.back()->Join(); |
108 threads_.pop_back(); | 126 threads_.pop_back(); |
109 } | 127 } |
110 } | 128 } |
111 | 129 |
112 // Overridden from base::TaskRunner: | 130 // Overridden from base::TaskRunner: |
113 bool RasterWorkerPool::PostDelayedTask( | 131 bool RasterWorkerPool::PostDelayedTask( |
114 const tracked_objects::Location& from_here, | 132 const tracked_objects::Location& from_here, |
115 const base::Closure& task, | 133 const base::Closure& task, |
116 base::TimeDelta delay) { | 134 base::TimeDelta delay) { |
117 base::AutoLock lock(lock_); | 135 base::AutoLock lock(lock_); |
118 | 136 |
119 // Remove completed tasks. | 137 // Remove completed tasks. |
120 DCHECK(completed_tasks_.empty()); | 138 DCHECK(completed_tasks_.empty()); |
121 task_graph_runner_.CollectCompletedTasks(namespace_token_, &completed_tasks_); | 139 CollectCompletedTasksWithLockAcquired(namespace_token_, &completed_tasks_); |
122 | 140 |
123 cc::Task::Vector::iterator end = std::remove_if( | 141 cc::Task::Vector::iterator end = std::remove_if( |
124 tasks_.begin(), tasks_.end(), [this](const scoped_refptr<cc::Task>& e) { | 142 tasks_.begin(), tasks_.end(), [this](const scoped_refptr<cc::Task>& e) { |
125 return std::find(this->completed_tasks_.begin(), | 143 return std::find(this->completed_tasks_.begin(), |
126 this->completed_tasks_.end(), | 144 this->completed_tasks_.end(), |
127 e) != this->completed_tasks_.end(); | 145 e) != this->completed_tasks_.end(); |
128 }); | 146 }); |
129 tasks_.erase(end, tasks_.end()); | 147 tasks_.erase(end, tasks_.end()); |
130 | 148 |
131 tasks_.push_back(make_scoped_refptr(new ClosureTask(task))); | 149 tasks_.push_back(make_scoped_refptr(new ClosureTask(task))); |
132 graph_.Reset(); | 150 graph_.Reset(); |
133 for (const auto& graph_task : tasks_) | 151 for (const auto& graph_task : tasks_) |
134 graph_.nodes.push_back(cc::TaskGraph::Node(graph_task.get(), 0, 0)); | 152 graph_.nodes.push_back(cc::TaskGraph::Node(graph_task.get(), 0, 0)); |
135 | 153 |
136 task_graph_runner_.ScheduleTasks(namespace_token_, &graph_); | 154 ScheduleTasksWithLockAcquired(namespace_token_, &graph_); |
137 completed_tasks_.clear(); | 155 completed_tasks_.clear(); |
138 return true; | 156 return true; |
139 } | 157 } |
140 | 158 |
141 bool RasterWorkerPool::RunsTasksOnCurrentThread() const { | 159 bool RasterWorkerPool::RunsTasksOnCurrentThread() const { |
142 return true; | 160 return true; |
143 } | 161 } |
144 | 162 |
145 // Overridden from base::DelegateSimpleThread::Delegate: | 163 // Overridden from base::DelegateSimpleThread::Delegate: |
146 void RasterWorkerPool::Run() { | 164 void RasterWorkerPool::Run() { |
147 task_graph_runner_.Run(); | 165 base::AutoLock lock(lock_); |
166 | |
167 while (true) { | |
168 if (!work_queue_.HasReadyToRunTasks()) { | |
169 // Exit when shutdown is set and no more tasks are pending. | |
170 if (shutdown_) | |
171 break; | |
172 | |
173 // Wait for more tasks. | |
174 has_ready_to_run_tasks_cv_.Wait(); | |
175 continue; | |
176 } | |
177 | |
178 RunTaskWithLockAcquired(); | |
179 } | |
180 | |
181 // We noticed we should exit. Wake up the next worker so it knows it should | |
182 // exit as well (because the Shutdown() code only signals once). | |
183 has_ready_to_run_tasks_cv_.Signal(); | |
ericrk
2015/11/25 02:09:52
We no longer need this with the broadcast.
| |
184 } | |
185 | |
186 void RasterWorkerPool::FlushForTesting() { | |
187 base::AutoLock lock(lock_); | |
188 | |
189 while (!work_queue_.HasFinishedRunningTasksInAllNamespaces()) { | |
190 has_namespaces_with_finished_running_tasks_cv_.Wait(); | |
191 } | |
148 } | 192 } |
149 | 193 |
150 scoped_refptr<base::SequencedTaskRunner> | 194 scoped_refptr<base::SequencedTaskRunner> |
151 RasterWorkerPool::CreateSequencedTaskRunner() { | 195 RasterWorkerPool::CreateSequencedTaskRunner() { |
152 return new RasterWorkerPoolSequencedTaskRunner(&task_graph_runner_); | 196 return new RasterWorkerPoolSequencedTaskRunner(this); |
153 } | 197 } |
154 | 198 |
155 RasterWorkerPool::~RasterWorkerPool() {} | 199 RasterWorkerPool::~RasterWorkerPool() {} |
156 | 200 |
201 cc::NamespaceToken RasterWorkerPool::GetNamespaceToken() { | |
202 base::AutoLock lock(lock_); | |
203 return work_queue_.GetNamespaceToken(); | |
204 } | |
205 | |
206 void RasterWorkerPool::ScheduleTasks(cc::NamespaceToken token, | |
207 cc::TaskGraph* graph) { | |
208 TRACE_EVENT2("cc", "RasterWorkerPool::ScheduleTasks", "num_nodes", | |
209 graph->nodes.size(), "num_edges", graph->edges.size()); | |
210 { | |
211 base::AutoLock lock(lock_); | |
212 ScheduleTasksWithLockAcquired(token, graph); | |
213 } | |
214 } | |
215 | |
216 void RasterWorkerPool::ScheduleTasksWithLockAcquired(cc::NamespaceToken token, | |
217 cc::TaskGraph* graph) { | |
218 DCHECK(token.IsValid()); | |
219 DCHECK(!cc::TaskGraphWorkQueue::DependencyMismatch(graph)); | |
220 DCHECK(!shutdown_); | |
221 | |
222 work_queue_.ScheduleTasks(token, graph); | |
223 | |
224 // If there is more work available, wake up worker thread. | |
225 if (work_queue_.HasReadyToRunTasks()) | |
226 has_ready_to_run_tasks_cv_.Signal(); | |
227 } | |
228 | |
229 void RasterWorkerPool::WaitForTasksToFinishRunning(cc::NamespaceToken token) { | |
230 TRACE_EVENT0("cc", "RasterWorkerPool::WaitForTasksToFinishRunning"); | |
231 | |
232 DCHECK(token.IsValid()); | |
233 | |
234 { | |
235 base::AutoLock lock(lock_); | |
236 base::ThreadRestrictions::ScopedAllowWait allow_wait; | |
237 | |
238 auto* task_namespace = work_queue_.GetNamespaceForToken(token); | |
239 | |
240 if (!task_namespace) | |
241 return; | |
242 | |
243 while (!work_queue_.HasFinishedRunningTasksInNamespace(task_namespace)) | |
244 has_namespaces_with_finished_running_tasks_cv_.Wait(); | |
245 | |
246 // There may be other namespaces that have finished running tasks, so wake | |
247 // up another origin thread. | |
248 has_namespaces_with_finished_running_tasks_cv_.Signal(); | |
249 } | |
250 } | |
251 | |
252 void RasterWorkerPool::CollectCompletedTasks( | |
253 cc::NamespaceToken token, | |
254 cc::Task::Vector* completed_tasks) { | |
255 TRACE_EVENT0("cc", "RasterWorkerPool::CollectCompletedTasks"); | |
256 | |
257 { | |
258 base::AutoLock lock(lock_); | |
259 CollectCompletedTasksWithLockAcquired(token, completed_tasks); | |
260 } | |
261 } | |
262 | |
263 void RasterWorkerPool::CollectCompletedTasksWithLockAcquired( | |
264 cc::NamespaceToken token, | |
265 cc::Task::Vector* completed_tasks) { | |
266 DCHECK(token.IsValid()); | |
267 work_queue_.CollectCompletedTasks(token, completed_tasks); | |
268 } | |
269 | |
270 void RasterWorkerPool::RunTaskWithLockAcquired() { | |
271 TRACE_EVENT0("toplevel", "TaskGraphRunner::RunTask"); | |
272 | |
273 lock_.AssertAcquired(); | |
274 | |
275 auto prioritized_task = work_queue_.GetNextTaskToRun(); | |
276 cc::Task* task = prioritized_task.task; | |
277 | |
278 // There may be more work available, so wake up another worker thread. | |
no sievers
2015/11/25 00:03:34
can you check if there is actually more work? seem
ericrk
2015/11/25 02:09:52
Done.
| |
279 has_ready_to_run_tasks_cv_.Signal(); | |
280 | |
281 // Call WillRun() before releasing |lock_| and running task. | |
282 task->WillRun(); | |
283 | |
284 { | |
285 base::AutoUnlock unlock(lock_); | |
286 | |
287 task->RunOnWorkerThread(); | |
288 } | |
289 | |
290 // This will mark task as finished running. | |
291 task->DidRun(); | |
292 | |
293 work_queue_.CompleteTask(prioritized_task); | |
294 | |
295 // If namespace has finished running all tasks, wake up origin thread. | |
no sievers
2015/11/25 00:03:34
there will only ever be one thread waiting right?
ericrk
2015/11/25 02:09:52
Right now there's nothing that stops multiple thre
reveman
2015/11/25 02:30:07
There can be multiple threads waiting. I would rec
| |
296 if (work_queue_.HasFinishedRunningTasksInNamespace( | |
297 prioritized_task.task_namespace)) | |
298 has_namespaces_with_finished_running_tasks_cv_.Signal(); | |
299 } | |
300 | |
157 RasterWorkerPool::ClosureTask::ClosureTask(const base::Closure& closure) | 301 RasterWorkerPool::ClosureTask::ClosureTask(const base::Closure& closure) |
158 : closure_(closure) {} | 302 : closure_(closure) {} |
159 | 303 |
160 // Overridden from cc::Task: | 304 // Overridden from cc::Task: |
161 void RasterWorkerPool::ClosureTask::RunOnWorkerThread() { | 305 void RasterWorkerPool::ClosureTask::RunOnWorkerThread() { |
162 closure_.Run(); | 306 closure_.Run(); |
163 closure_.Reset(); | 307 closure_.Reset(); |
164 }; | 308 } |
165 | 309 |
166 RasterWorkerPool::ClosureTask::~ClosureTask() {} | 310 RasterWorkerPool::ClosureTask::~ClosureTask() {} |
167 | 311 |
168 } // namespace content | 312 } // namespace content |
OLD | NEW |