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 // If we've enabled the use of a single thread for background tasks, only | |
140 // the first thread will run background tasks. Otherwise all threads may run | |
141 // them. | |
reveman
2016/01/21 17:12:24
nit: Please update this comment. Simply "The last
ericrk
2016/01/21 17:30:30
yup
| |
142 if (threads_.size() == (static_cast<size_t>(num_threads) - 1)) { | |
143 task_categories.push_back(cc::TASK_CATEGORY_BACKGROUND); | |
144 } | |
145 | |
146 scoped_ptr<base::SimpleThread> thread(new RasterWorkerPoolThread( | |
147 base::StringPrintf("CompositorTileWorker%u", | |
148 static_cast<unsigned>(threads_.size() + 1)) | |
149 .c_str(), | |
150 thread_options, this, task_categories)); | |
108 thread->Start(); | 151 thread->Start(); |
109 threads_.push_back(std::move(thread)); | 152 threads_.push_back(std::move(thread)); |
110 } | 153 } |
111 } | 154 } |
112 | 155 |
113 void RasterWorkerPool::Shutdown() { | 156 void RasterWorkerPool::Shutdown() { |
114 WaitForTasksToFinishRunning(namespace_token_); | 157 WaitForTasksToFinishRunning(namespace_token_); |
115 CollectCompletedTasks(namespace_token_, &completed_tasks_); | 158 CollectCompletedTasks(namespace_token_, &completed_tasks_); |
116 // Shutdown raster threads. | 159 // Shutdown raster threads. |
117 { | 160 { |
(...skipping 28 matching lines...) Expand all Loading... | |
146 cc::Task::Vector::iterator end = std::remove_if( | 189 cc::Task::Vector::iterator end = std::remove_if( |
147 tasks_.begin(), tasks_.end(), [this](const scoped_refptr<cc::Task>& e) { | 190 tasks_.begin(), tasks_.end(), [this](const scoped_refptr<cc::Task>& e) { |
148 return std::find(this->completed_tasks_.begin(), | 191 return std::find(this->completed_tasks_.begin(), |
149 this->completed_tasks_.end(), | 192 this->completed_tasks_.end(), |
150 e) != this->completed_tasks_.end(); | 193 e) != this->completed_tasks_.end(); |
151 }); | 194 }); |
152 tasks_.erase(end, tasks_.end()); | 195 tasks_.erase(end, tasks_.end()); |
153 | 196 |
154 tasks_.push_back(make_scoped_refptr(new ClosureTask(task))); | 197 tasks_.push_back(make_scoped_refptr(new ClosureTask(task))); |
155 graph_.Reset(); | 198 graph_.Reset(); |
156 for (const auto& graph_task : tasks_) | 199 for (const auto& graph_task : tasks_) { |
200 // Delayed tasks are assigned FOREGROUND category, ensuring that they run as | |
201 // soon as possible once their delay has expired. | |
157 graph_.nodes.push_back( | 202 graph_.nodes.push_back( |
158 cc::TaskGraph::Node(graph_task.get(), 0u /* category */, | 203 cc::TaskGraph::Node(graph_task.get(), cc::TASK_CATEGORY_FOREGROUND, |
159 0u /* priority */, 0u /* dependencies */)); | 204 0u /* priority */, 0u /* dependencies */)); |
205 } | |
160 | 206 |
161 ScheduleTasksWithLockAcquired(namespace_token_, &graph_); | 207 ScheduleTasksWithLockAcquired(namespace_token_, &graph_); |
162 completed_tasks_.clear(); | 208 completed_tasks_.clear(); |
163 return true; | 209 return true; |
164 } | 210 } |
165 | 211 |
166 bool RasterWorkerPool::RunsTasksOnCurrentThread() const { | 212 bool RasterWorkerPool::RunsTasksOnCurrentThread() const { |
167 return true; | 213 return true; |
168 } | 214 } |
169 | 215 |
170 // Overridden from base::DelegateSimpleThread::Delegate: | 216 void RasterWorkerPool::Run(const std::vector<cc::TaskCategory>& categories) { |
171 void RasterWorkerPool::Run() { | |
172 base::AutoLock lock(lock_); | 217 base::AutoLock lock(lock_); |
173 | 218 |
174 while (true) { | 219 while (true) { |
175 if (!RunTaskWithLockAcquired()) { | 220 if (!RunTaskWithLockAcquired(categories)) { |
176 // Exit when shutdown is set and no more tasks are pending. | 221 // Exit when shutdown is set and no more tasks are pending. |
177 if (shutdown_) | 222 if (shutdown_) |
178 break; | 223 break; |
179 | 224 |
180 // Wait for more tasks. | 225 // Wait for more tasks. |
181 has_ready_to_run_tasks_cv_.Wait(); | 226 has_ready_to_run_tasks_cv_.Wait(); |
182 continue; | 227 continue; |
183 } | 228 } |
184 } | 229 } |
185 } | 230 } |
(...skipping 29 matching lines...) Expand all Loading... | |
215 } | 260 } |
216 | 261 |
217 void RasterWorkerPool::ScheduleTasksWithLockAcquired(cc::NamespaceToken token, | 262 void RasterWorkerPool::ScheduleTasksWithLockAcquired(cc::NamespaceToken token, |
218 cc::TaskGraph* graph) { | 263 cc::TaskGraph* graph) { |
219 DCHECK(token.IsValid()); | 264 DCHECK(token.IsValid()); |
220 DCHECK(!cc::TaskGraphWorkQueue::DependencyMismatch(graph)); | 265 DCHECK(!cc::TaskGraphWorkQueue::DependencyMismatch(graph)); |
221 DCHECK(!shutdown_); | 266 DCHECK(!shutdown_); |
222 | 267 |
223 work_queue_.ScheduleTasks(token, graph); | 268 work_queue_.ScheduleTasks(token, graph); |
224 | 269 |
225 // If there is more work available, wake up worker thread. | 270 // If there is more work available, wake up the other worker threads. |
226 if (work_queue_.HasReadyToRunTasks()) | 271 if (work_queue_.HasReadyToRunTasks()) |
227 has_ready_to_run_tasks_cv_.Signal(); | 272 has_ready_to_run_tasks_cv_.Broadcast(); |
228 } | 273 } |
229 | 274 |
230 void RasterWorkerPool::WaitForTasksToFinishRunning(cc::NamespaceToken token) { | 275 void RasterWorkerPool::WaitForTasksToFinishRunning(cc::NamespaceToken token) { |
231 TRACE_EVENT0("cc", "RasterWorkerPool::WaitForTasksToFinishRunning"); | 276 TRACE_EVENT0("cc", "RasterWorkerPool::WaitForTasksToFinishRunning"); |
232 | 277 |
233 DCHECK(token.IsValid()); | 278 DCHECK(token.IsValid()); |
234 | 279 |
235 { | 280 { |
236 base::AutoLock lock(lock_); | 281 base::AutoLock lock(lock_); |
237 base::ThreadRestrictions::ScopedAllowWait allow_wait; | 282 base::ThreadRestrictions::ScopedAllowWait allow_wait; |
(...skipping 19 matching lines...) Expand all Loading... | |
257 } | 302 } |
258 } | 303 } |
259 | 304 |
260 void RasterWorkerPool::CollectCompletedTasksWithLockAcquired( | 305 void RasterWorkerPool::CollectCompletedTasksWithLockAcquired( |
261 cc::NamespaceToken token, | 306 cc::NamespaceToken token, |
262 cc::Task::Vector* completed_tasks) { | 307 cc::Task::Vector* completed_tasks) { |
263 DCHECK(token.IsValid()); | 308 DCHECK(token.IsValid()); |
264 work_queue_.CollectCompletedTasks(token, completed_tasks); | 309 work_queue_.CollectCompletedTasks(token, completed_tasks); |
265 } | 310 } |
266 | 311 |
267 bool RasterWorkerPool::RunTaskWithLockAcquired() { | 312 bool RasterWorkerPool::RunTaskWithLockAcquired( |
313 const std::vector<cc::TaskCategory>& categories) { | |
314 for (const auto& category : categories) { | |
315 if (work_queue_.HasReadyToRunTasksForCategory(category)) { | |
316 RunTaskInCategoryWithLockAcquired(category); | |
317 return true; | |
318 } | |
319 } | |
320 return false; | |
321 } | |
322 | |
323 void RasterWorkerPool::RunTaskInCategoryWithLockAcquired( | |
324 cc::TaskCategory category) { | |
268 TRACE_EVENT0("toplevel", "TaskGraphRunner::RunTask"); | 325 TRACE_EVENT0("toplevel", "TaskGraphRunner::RunTask"); |
269 | 326 |
270 lock_.AssertAcquired(); | 327 lock_.AssertAcquired(); |
271 | 328 |
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); | 329 auto prioritized_task = work_queue_.GetNextTaskToRun(category); |
289 cc::Task* task = prioritized_task.task; | 330 cc::Task* task = prioritized_task.task; |
290 | 331 |
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. | 332 // Call WillRun() before releasing |lock_| and running task. |
296 task->WillRun(); | 333 task->WillRun(); |
297 | 334 |
298 { | 335 { |
299 base::AutoUnlock unlock(lock_); | 336 base::AutoUnlock unlock(lock_); |
300 | 337 |
301 task->RunOnWorkerThread(); | 338 task->RunOnWorkerThread(); |
302 } | 339 } |
303 | 340 |
304 // This will mark task as finished running. | 341 // This will mark task as finished running. |
305 task->DidRun(); | 342 task->DidRun(); |
306 | 343 |
307 work_queue_.CompleteTask(prioritized_task); | 344 work_queue_.CompleteTask(prioritized_task); |
308 | 345 |
346 // We may have just dequeued more tasks, wake up the other worker threads. | |
347 if (work_queue_.HasReadyToRunTasks()) | |
348 has_ready_to_run_tasks_cv_.Broadcast(); | |
349 | |
309 // If namespace has finished running all tasks, wake up origin threads. | 350 // If namespace has finished running all tasks, wake up origin threads. |
310 if (work_queue_.HasFinishedRunningTasksInNamespace( | 351 if (work_queue_.HasFinishedRunningTasksInNamespace( |
311 prioritized_task.task_namespace)) | 352 prioritized_task.task_namespace)) |
312 has_namespaces_with_finished_running_tasks_cv_.Broadcast(); | 353 has_namespaces_with_finished_running_tasks_cv_.Broadcast(); |
313 | |
314 return true; | |
315 } | 354 } |
316 | 355 |
317 RasterWorkerPool::ClosureTask::ClosureTask(const base::Closure& closure) | 356 RasterWorkerPool::ClosureTask::ClosureTask(const base::Closure& closure) |
318 : closure_(closure) {} | 357 : closure_(closure) {} |
319 | 358 |
320 // Overridden from cc::Task: | 359 // Overridden from cc::Task: |
321 void RasterWorkerPool::ClosureTask::RunOnWorkerThread() { | 360 void RasterWorkerPool::ClosureTask::RunOnWorkerThread() { |
322 closure_.Run(); | 361 closure_.Run(); |
323 closure_.Reset(); | 362 closure_.Reset(); |
324 } | 363 } |
325 | 364 |
326 RasterWorkerPool::ClosureTask::~ClosureTask() {} | 365 RasterWorkerPool::ClosureTask::~ClosureTask() {} |
327 | 366 |
328 } // namespace content | 367 } // namespace content |
OLD | NEW |