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 <stddef.h> | 7 #include <string> |
8 #include <stdint.h> | |
9 | |
10 #include <utility> | 8 #include <utility> |
| 9 #include <vector> |
11 | 10 |
12 #include "base/strings/stringprintf.h" | 11 #include "base/strings/stringprintf.h" |
13 #include "base/threading/thread_restrictions.h" | 12 #include "base/threading/thread_restrictions.h" |
14 #include "base/trace_event/trace_event.h" | 13 #include "base/trace_event/trace_event.h" |
| 14 #include "cc/base/math_util.h" |
| 15 #include "cc/raster/task_category.h" |
15 | 16 |
16 namespace content { | 17 namespace content { |
| 18 namespace { |
| 19 |
| 20 // A thread which forwards to RasterWorkerPool::Run with the runnable |
| 21 // categories. |
| 22 class RasterWorkerPoolThread : public base::SimpleThread { |
| 23 public: |
| 24 explicit RasterWorkerPoolThread(const std::string& name_prefix, |
| 25 const Options& options, |
| 26 RasterWorkerPool* pool, |
| 27 std::vector<cc::TaskCategory> categories) |
| 28 : SimpleThread(name_prefix, options), |
| 29 pool_(pool), |
| 30 categories_(categories) {} |
| 31 |
| 32 void Run() override { pool_->Run(categories_); } |
| 33 |
| 34 private: |
| 35 RasterWorkerPool* const pool_; |
| 36 const std::vector<cc::TaskCategory> categories_; |
| 37 }; |
| 38 |
| 39 } // namespace |
17 | 40 |
18 // A sequenced task runner which posts tasks to a RasterWorkerPool. | 41 // A sequenced task runner which posts tasks to a RasterWorkerPool. |
19 class RasterWorkerPool::RasterWorkerPoolSequencedTaskRunner | 42 class RasterWorkerPool::RasterWorkerPoolSequencedTaskRunner |
20 : public base::SequencedTaskRunner { | 43 : public base::SequencedTaskRunner { |
21 public: | 44 public: |
22 explicit RasterWorkerPoolSequencedTaskRunner( | 45 explicit RasterWorkerPoolSequencedTaskRunner( |
23 cc::TaskGraphRunner* task_graph_runner) | 46 cc::TaskGraphRunner* task_graph_runner) |
24 : task_graph_runner_(task_graph_runner), | 47 : task_graph_runner_(task_graph_runner), |
25 namespace_token_(task_graph_runner->GetNamespaceToken()) {} | 48 namespace_token_(task_graph_runner->GetNamespaceToken()) {} |
26 | 49 |
(...skipping 18 matching lines...) Expand all Loading... |
45 | 68 |
46 tasks_.erase(tasks_.begin(), tasks_.begin() + completed_tasks_.size()); | 69 tasks_.erase(tasks_.begin(), tasks_.begin() + completed_tasks_.size()); |
47 | 70 |
48 tasks_.push_back(make_scoped_refptr(new ClosureTask(task))); | 71 tasks_.push_back(make_scoped_refptr(new ClosureTask(task))); |
49 graph_.Reset(); | 72 graph_.Reset(); |
50 for (const auto& graph_task : tasks_) { | 73 for (const auto& graph_task : tasks_) { |
51 int dependencies = 0; | 74 int dependencies = 0; |
52 if (!graph_.nodes.empty()) | 75 if (!graph_.nodes.empty()) |
53 dependencies = 1; | 76 dependencies = 1; |
54 | 77 |
55 cc::TaskGraph::Node node(graph_task.get(), 0u /* category */, | 78 // Treat any tasks that are enqueued through the SequencedTaskRunner as |
| 79 // FOREGROUND priority. We don't have enough information to know the |
| 80 // actual priority of such tasks, so we run them as soon as possible. |
| 81 cc::TaskGraph::Node node(graph_task.get(), cc::TASK_CATEGORY_FOREGROUND, |
56 0u /* priority */, dependencies); | 82 0u /* priority */, dependencies); |
57 if (dependencies) { | 83 if (dependencies) { |
58 graph_.edges.push_back( | 84 graph_.edges.push_back( |
59 cc::TaskGraph::Edge(graph_.nodes.back().task, node.task)); | 85 cc::TaskGraph::Edge(graph_.nodes.back().task, node.task)); |
60 } | 86 } |
61 graph_.nodes.push_back(node); | 87 graph_.nodes.push_back(node); |
62 } | 88 } |
63 task_graph_runner_->ScheduleTasks(namespace_token_, &graph_); | 89 task_graph_runner_->ScheduleTasks(namespace_token_, &graph_); |
64 completed_tasks_.clear(); | 90 completed_tasks_.clear(); |
65 return true; | 91 return true; |
(...skipping 26 matching lines...) Expand all Loading... |
92 : namespace_token_(GetNamespaceToken()), | 118 : namespace_token_(GetNamespaceToken()), |
93 has_ready_to_run_tasks_cv_(&lock_), | 119 has_ready_to_run_tasks_cv_(&lock_), |
94 has_namespaces_with_finished_running_tasks_cv_(&lock_), | 120 has_namespaces_with_finished_running_tasks_cv_(&lock_), |
95 shutdown_(false) {} | 121 shutdown_(false) {} |
96 | 122 |
97 void RasterWorkerPool::Start( | 123 void RasterWorkerPool::Start( |
98 int num_threads, | 124 int num_threads, |
99 const base::SimpleThread::Options& thread_options) { | 125 const base::SimpleThread::Options& thread_options) { |
100 DCHECK(threads_.empty()); | 126 DCHECK(threads_.empty()); |
101 while (threads_.size() < static_cast<size_t>(num_threads)) { | 127 while (threads_.size() < static_cast<size_t>(num_threads)) { |
102 scoped_ptr<base::DelegateSimpleThread> thread( | 128 // Determine the categories that each thread can run. |
103 new base::DelegateSimpleThread( | 129 std::vector<cc::TaskCategory> task_categories; |
104 this, base::StringPrintf("CompositorTileWorker%u", | 130 |
105 static_cast<unsigned>(threads_.size() + 1)) | 131 // The first thread can run nonconcurrent tasks. |
106 .c_str(), | 132 if (threads_.size() == 0) { |
107 thread_options)); | 133 task_categories.push_back(cc::TASK_CATEGORY_NONCONCURRENT_FOREGROUND); |
| 134 } |
| 135 |
| 136 // All threads can run foreground tasks. |
| 137 task_categories.push_back(cc::TASK_CATEGORY_FOREGROUND); |
| 138 |
| 139 // The last thread can run background tasks. |
| 140 if (threads_.size() == (static_cast<size_t>(num_threads) - 1)) { |
| 141 task_categories.push_back(cc::TASK_CATEGORY_BACKGROUND); |
| 142 } |
| 143 |
| 144 scoped_ptr<base::SimpleThread> thread(new RasterWorkerPoolThread( |
| 145 base::StringPrintf("CompositorTileWorker%u", |
| 146 static_cast<unsigned>(threads_.size() + 1)) |
| 147 .c_str(), |
| 148 thread_options, this, task_categories)); |
108 thread->Start(); | 149 thread->Start(); |
109 threads_.push_back(std::move(thread)); | 150 threads_.push_back(std::move(thread)); |
110 } | 151 } |
111 } | 152 } |
112 | 153 |
113 void RasterWorkerPool::Shutdown() { | 154 void RasterWorkerPool::Shutdown() { |
114 WaitForTasksToFinishRunning(namespace_token_); | 155 WaitForTasksToFinishRunning(namespace_token_); |
115 CollectCompletedTasks(namespace_token_, &completed_tasks_); | 156 CollectCompletedTasks(namespace_token_, &completed_tasks_); |
116 // Shutdown raster threads. | 157 // Shutdown raster threads. |
117 { | 158 { |
(...skipping 28 matching lines...) Expand all Loading... |
146 cc::Task::Vector::iterator end = std::remove_if( | 187 cc::Task::Vector::iterator end = std::remove_if( |
147 tasks_.begin(), tasks_.end(), [this](const scoped_refptr<cc::Task>& e) { | 188 tasks_.begin(), tasks_.end(), [this](const scoped_refptr<cc::Task>& e) { |
148 return std::find(this->completed_tasks_.begin(), | 189 return std::find(this->completed_tasks_.begin(), |
149 this->completed_tasks_.end(), | 190 this->completed_tasks_.end(), |
150 e) != this->completed_tasks_.end(); | 191 e) != this->completed_tasks_.end(); |
151 }); | 192 }); |
152 tasks_.erase(end, tasks_.end()); | 193 tasks_.erase(end, tasks_.end()); |
153 | 194 |
154 tasks_.push_back(make_scoped_refptr(new ClosureTask(task))); | 195 tasks_.push_back(make_scoped_refptr(new ClosureTask(task))); |
155 graph_.Reset(); | 196 graph_.Reset(); |
156 for (const auto& graph_task : tasks_) | 197 for (const auto& graph_task : tasks_) { |
| 198 // Delayed tasks are assigned FOREGROUND category, ensuring that they run as |
| 199 // soon as possible once their delay has expired. |
157 graph_.nodes.push_back( | 200 graph_.nodes.push_back( |
158 cc::TaskGraph::Node(graph_task.get(), 0u /* category */, | 201 cc::TaskGraph::Node(graph_task.get(), cc::TASK_CATEGORY_FOREGROUND, |
159 0u /* priority */, 0u /* dependencies */)); | 202 0u /* priority */, 0u /* dependencies */)); |
| 203 } |
160 | 204 |
161 ScheduleTasksWithLockAcquired(namespace_token_, &graph_); | 205 ScheduleTasksWithLockAcquired(namespace_token_, &graph_); |
162 completed_tasks_.clear(); | 206 completed_tasks_.clear(); |
163 return true; | 207 return true; |
164 } | 208 } |
165 | 209 |
166 bool RasterWorkerPool::RunsTasksOnCurrentThread() const { | 210 bool RasterWorkerPool::RunsTasksOnCurrentThread() const { |
167 return true; | 211 return true; |
168 } | 212 } |
169 | 213 |
170 // Overridden from base::DelegateSimpleThread::Delegate: | 214 void RasterWorkerPool::Run(const std::vector<cc::TaskCategory>& categories) { |
171 void RasterWorkerPool::Run() { | |
172 base::AutoLock lock(lock_); | 215 base::AutoLock lock(lock_); |
173 | 216 |
174 while (true) { | 217 while (true) { |
175 if (!RunTaskWithLockAcquired()) { | 218 if (!RunTaskWithLockAcquired(categories)) { |
176 // Exit when shutdown is set and no more tasks are pending. | 219 // Exit when shutdown is set and no more tasks are pending. |
177 if (shutdown_) | 220 if (shutdown_) |
178 break; | 221 break; |
179 | 222 |
180 // Wait for more tasks. | 223 // Wait for more tasks. |
181 has_ready_to_run_tasks_cv_.Wait(); | 224 has_ready_to_run_tasks_cv_.Wait(); |
182 continue; | 225 continue; |
183 } | 226 } |
184 } | 227 } |
185 } | 228 } |
(...skipping 29 matching lines...) Expand all Loading... |
215 } | 258 } |
216 | 259 |
217 void RasterWorkerPool::ScheduleTasksWithLockAcquired(cc::NamespaceToken token, | 260 void RasterWorkerPool::ScheduleTasksWithLockAcquired(cc::NamespaceToken token, |
218 cc::TaskGraph* graph) { | 261 cc::TaskGraph* graph) { |
219 DCHECK(token.IsValid()); | 262 DCHECK(token.IsValid()); |
220 DCHECK(!cc::TaskGraphWorkQueue::DependencyMismatch(graph)); | 263 DCHECK(!cc::TaskGraphWorkQueue::DependencyMismatch(graph)); |
221 DCHECK(!shutdown_); | 264 DCHECK(!shutdown_); |
222 | 265 |
223 work_queue_.ScheduleTasks(token, graph); | 266 work_queue_.ScheduleTasks(token, graph); |
224 | 267 |
225 // If there is more work available, wake up worker thread. | 268 // If there is more work available, wake up the other worker threads. |
226 if (work_queue_.HasReadyToRunTasks()) | 269 if (work_queue_.HasReadyToRunTasks()) |
227 has_ready_to_run_tasks_cv_.Signal(); | 270 has_ready_to_run_tasks_cv_.Broadcast(); |
228 } | 271 } |
229 | 272 |
230 void RasterWorkerPool::WaitForTasksToFinishRunning(cc::NamespaceToken token) { | 273 void RasterWorkerPool::WaitForTasksToFinishRunning(cc::NamespaceToken token) { |
231 TRACE_EVENT0("cc", "RasterWorkerPool::WaitForTasksToFinishRunning"); | 274 TRACE_EVENT0("cc", "RasterWorkerPool::WaitForTasksToFinishRunning"); |
232 | 275 |
233 DCHECK(token.IsValid()); | 276 DCHECK(token.IsValid()); |
234 | 277 |
235 { | 278 { |
236 base::AutoLock lock(lock_); | 279 base::AutoLock lock(lock_); |
237 base::ThreadRestrictions::ScopedAllowWait allow_wait; | 280 base::ThreadRestrictions::ScopedAllowWait allow_wait; |
(...skipping 19 matching lines...) Expand all Loading... |
257 } | 300 } |
258 } | 301 } |
259 | 302 |
260 void RasterWorkerPool::CollectCompletedTasksWithLockAcquired( | 303 void RasterWorkerPool::CollectCompletedTasksWithLockAcquired( |
261 cc::NamespaceToken token, | 304 cc::NamespaceToken token, |
262 cc::Task::Vector* completed_tasks) { | 305 cc::Task::Vector* completed_tasks) { |
263 DCHECK(token.IsValid()); | 306 DCHECK(token.IsValid()); |
264 work_queue_.CollectCompletedTasks(token, completed_tasks); | 307 work_queue_.CollectCompletedTasks(token, completed_tasks); |
265 } | 308 } |
266 | 309 |
267 bool RasterWorkerPool::RunTaskWithLockAcquired() { | 310 bool RasterWorkerPool::RunTaskWithLockAcquired( |
| 311 const std::vector<cc::TaskCategory>& categories) { |
| 312 for (const auto& category : categories) { |
| 313 if (work_queue_.HasReadyToRunTasksForCategory(category)) { |
| 314 RunTaskInCategoryWithLockAcquired(category); |
| 315 return true; |
| 316 } |
| 317 } |
| 318 return false; |
| 319 } |
| 320 |
| 321 void RasterWorkerPool::RunTaskInCategoryWithLockAcquired( |
| 322 cc::TaskCategory category) { |
268 TRACE_EVENT0("toplevel", "TaskGraphRunner::RunTask"); | 323 TRACE_EVENT0("toplevel", "TaskGraphRunner::RunTask"); |
269 | 324 |
270 lock_.AssertAcquired(); | 325 lock_.AssertAcquired(); |
271 | 326 |
272 // Find the first category with any tasks to run. This task graph runner | |
273 // treats categories as an additional priority. | |
274 // TODO(ericrk): Add more category/thread logic. | |
275 const auto& ready_to_run_namespaces = work_queue_.ready_to_run_namespaces(); | |
276 auto found = std::find_if( | |
277 ready_to_run_namespaces.cbegin(), ready_to_run_namespaces.cend(), | |
278 [](const std::pair<uint16_t, | |
279 cc::TaskGraphWorkQueue::TaskNamespace::Vector>& pair) { | |
280 return !pair.second.empty(); | |
281 }); | |
282 | |
283 if (found == ready_to_run_namespaces.cend()) { | |
284 return false; | |
285 } | |
286 | |
287 const uint16_t category = found->first; | |
288 auto prioritized_task = work_queue_.GetNextTaskToRun(category); | 327 auto prioritized_task = work_queue_.GetNextTaskToRun(category); |
289 cc::Task* task = prioritized_task.task; | 328 cc::Task* task = prioritized_task.task; |
290 | 329 |
291 // There may be more work available, so wake up another worker thread. | |
292 if (work_queue_.HasReadyToRunTasks()) | |
293 has_ready_to_run_tasks_cv_.Signal(); | |
294 | |
295 // Call WillRun() before releasing |lock_| and running task. | 330 // Call WillRun() before releasing |lock_| and running task. |
296 task->WillRun(); | 331 task->WillRun(); |
297 | 332 |
298 { | 333 { |
299 base::AutoUnlock unlock(lock_); | 334 base::AutoUnlock unlock(lock_); |
300 | 335 |
301 task->RunOnWorkerThread(); | 336 task->RunOnWorkerThread(); |
302 } | 337 } |
303 | 338 |
304 // This will mark task as finished running. | 339 // This will mark task as finished running. |
305 task->DidRun(); | 340 task->DidRun(); |
306 | 341 |
307 work_queue_.CompleteTask(prioritized_task); | 342 work_queue_.CompleteTask(prioritized_task); |
308 | 343 |
| 344 // We may have just dequeued more tasks, wake up the other worker threads. |
| 345 if (work_queue_.HasReadyToRunTasks()) |
| 346 has_ready_to_run_tasks_cv_.Broadcast(); |
| 347 |
309 // If namespace has finished running all tasks, wake up origin threads. | 348 // If namespace has finished running all tasks, wake up origin threads. |
310 if (work_queue_.HasFinishedRunningTasksInNamespace( | 349 if (work_queue_.HasFinishedRunningTasksInNamespace( |
311 prioritized_task.task_namespace)) | 350 prioritized_task.task_namespace)) |
312 has_namespaces_with_finished_running_tasks_cv_.Broadcast(); | 351 has_namespaces_with_finished_running_tasks_cv_.Broadcast(); |
313 | |
314 return true; | |
315 } | 352 } |
316 | 353 |
317 RasterWorkerPool::ClosureTask::ClosureTask(const base::Closure& closure) | 354 RasterWorkerPool::ClosureTask::ClosureTask(const base::Closure& closure) |
318 : closure_(closure) {} | 355 : closure_(closure) {} |
319 | 356 |
320 // Overridden from cc::Task: | 357 // Overridden from cc::Task: |
321 void RasterWorkerPool::ClosureTask::RunOnWorkerThread() { | 358 void RasterWorkerPool::ClosureTask::RunOnWorkerThread() { |
322 closure_.Run(); | 359 closure_.Run(); |
323 closure_.Reset(); | 360 closure_.Reset(); |
324 } | 361 } |
325 | 362 |
326 RasterWorkerPool::ClosureTask::~ClosureTask() {} | 363 RasterWorkerPool::ClosureTask::~ClosureTask() {} |
327 | 364 |
328 } // namespace content | 365 } // namespace content |
OLD | NEW |