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 23 matching lines...) Expand all Loading... | |
89 }; | 115 }; |
90 | 116 |
91 RasterWorkerPool::RasterWorkerPool() | 117 RasterWorkerPool::RasterWorkerPool() |
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, |
125 bool use_single_thread_for_background_raster_tasks, | |
99 const base::SimpleThread::Options& thread_options) { | 126 const base::SimpleThread::Options& thread_options) { |
100 DCHECK(threads_.empty()); | 127 DCHECK(threads_.empty()); |
101 while (threads_.size() < static_cast<size_t>(num_threads)) { | 128 while (threads_.size() < static_cast<size_t>(num_threads)) { |
102 scoped_ptr<base::DelegateSimpleThread> thread( | 129 // Determine the categories that each thread can run. |
103 new base::DelegateSimpleThread( | 130 std::vector<cc::TaskCategory> task_categories; |
104 this, base::StringPrintf("CompositorTileWorker%u", | 131 |
105 static_cast<unsigned>(threads_.size() + 1)) | 132 // The first thread can run nonconcurrent tasks. |
106 .c_str(), | 133 if (threads_.size() == 0) { |
107 thread_options)); | 134 task_categories.push_back(cc::TASK_CATEGORY_NONCONCURRENT_FOREGROUND); |
135 } | |
136 | |
137 // All threads can run foreground tasks. | |
138 task_categories.push_back(cc::TASK_CATEGORY_FOREGROUND); | |
139 | |
140 // If we've enabled the use of a single thread for background tasks, only | |
141 // the first thread will run background tasks. Otherwise all threads may run | |
142 // them. | |
143 if (threads_.size() == 0 || | |
reveman
2016/01/13 23:09:30
hm, should we avoid using the same thread as NONCO
ericrk
2016/01/21 01:19:44
with this setup, low priority tasks will never run
reveman
2016/01/21 17:12:24
Sgtm
| |
144 !use_single_thread_for_background_raster_tasks) { | |
145 task_categories.push_back(cc::TASK_CATEGORY_BACKGROUND); | |
146 } | |
147 | |
148 scoped_ptr<base::SimpleThread> thread(new RasterWorkerPoolThread( | |
149 base::StringPrintf("CompositorTileWorker%u", | |
150 static_cast<unsigned>(threads_.size() + 1)) | |
151 .c_str(), | |
152 thread_options, this, task_categories)); | |
108 thread->Start(); | 153 thread->Start(); |
109 threads_.push_back(std::move(thread)); | 154 threads_.push_back(std::move(thread)); |
110 } | 155 } |
111 } | 156 } |
112 | 157 |
113 void RasterWorkerPool::Shutdown() { | 158 void RasterWorkerPool::Shutdown() { |
114 WaitForTasksToFinishRunning(namespace_token_); | 159 WaitForTasksToFinishRunning(namespace_token_); |
115 CollectCompletedTasks(namespace_token_, &completed_tasks_); | 160 CollectCompletedTasks(namespace_token_, &completed_tasks_); |
116 // Shutdown raster threads. | 161 // Shutdown raster threads. |
117 { | 162 { |
(...skipping 28 matching lines...) Expand all Loading... | |
146 cc::Task::Vector::iterator end = std::remove_if( | 191 cc::Task::Vector::iterator end = std::remove_if( |
147 tasks_.begin(), tasks_.end(), [this](const scoped_refptr<cc::Task>& e) { | 192 tasks_.begin(), tasks_.end(), [this](const scoped_refptr<cc::Task>& e) { |
148 return std::find(this->completed_tasks_.begin(), | 193 return std::find(this->completed_tasks_.begin(), |
149 this->completed_tasks_.end(), | 194 this->completed_tasks_.end(), |
150 e) != this->completed_tasks_.end(); | 195 e) != this->completed_tasks_.end(); |
151 }); | 196 }); |
152 tasks_.erase(end, tasks_.end()); | 197 tasks_.erase(end, tasks_.end()); |
153 | 198 |
154 tasks_.push_back(make_scoped_refptr(new ClosureTask(task))); | 199 tasks_.push_back(make_scoped_refptr(new ClosureTask(task))); |
155 graph_.Reset(); | 200 graph_.Reset(); |
156 for (const auto& graph_task : tasks_) | 201 for (const auto& graph_task : tasks_) { |
202 // Delayed tasks are assigned FOREGROUND category, ensuring that they run as | |
203 // soon as possible once their delay has expired. | |
157 graph_.nodes.push_back( | 204 graph_.nodes.push_back( |
158 cc::TaskGraph::Node(graph_task.get(), 0u /* category */, | 205 cc::TaskGraph::Node(graph_task.get(), cc::TASK_CATEGORY_FOREGROUND, |
159 0u /* priority */, 0u /* dependencies */)); | 206 0u /* priority */, 0u /* dependencies */)); |
207 } | |
160 | 208 |
161 ScheduleTasksWithLockAcquired(namespace_token_, &graph_); | 209 ScheduleTasksWithLockAcquired(namespace_token_, &graph_); |
162 completed_tasks_.clear(); | 210 completed_tasks_.clear(); |
163 return true; | 211 return true; |
164 } | 212 } |
165 | 213 |
166 bool RasterWorkerPool::RunsTasksOnCurrentThread() const { | 214 bool RasterWorkerPool::RunsTasksOnCurrentThread() const { |
167 return true; | 215 return true; |
168 } | 216 } |
169 | 217 |
170 // Overridden from base::DelegateSimpleThread::Delegate: | 218 void RasterWorkerPool::Run(const std::vector<cc::TaskCategory>& categories) { |
171 void RasterWorkerPool::Run() { | |
172 base::AutoLock lock(lock_); | 219 base::AutoLock lock(lock_); |
173 | 220 |
174 while (true) { | 221 while (true) { |
175 if (!RunTaskWithLockAcquired()) { | 222 cc::TaskCategory category_to_run; |
223 bool should_run = false; | |
224 for (const auto& category : categories) { | |
225 if (work_queue_.HasReadyToRunTasksForCategory(category)) { | |
226 should_run = true; | |
227 category_to_run = category; | |
228 } | |
229 } | |
reveman
2016/01/13 23:09:30
nit: move this code into a new utility function th
ericrk
2016/01/21 01:19:44
Good suggestion.
| |
230 | |
231 if (!should_run) { | |
176 // Exit when shutdown is set and no more tasks are pending. | 232 // Exit when shutdown is set and no more tasks are pending. |
177 if (shutdown_) | 233 if (shutdown_) |
178 break; | 234 break; |
179 | 235 |
180 // Wait for more tasks. | 236 // Wait for more tasks. |
181 has_ready_to_run_tasks_cv_.Wait(); | 237 has_ready_to_run_tasks_cv_.Wait(); |
182 continue; | 238 continue; |
183 } | 239 } |
240 RunTaskWithLockAcquired(category_to_run); | |
184 } | 241 } |
185 } | 242 } |
186 | 243 |
187 void RasterWorkerPool::FlushForTesting() { | 244 void RasterWorkerPool::FlushForTesting() { |
188 base::AutoLock lock(lock_); | 245 base::AutoLock lock(lock_); |
189 | 246 |
190 while (!work_queue_.HasFinishedRunningTasksInAllNamespaces()) { | 247 while (!work_queue_.HasFinishedRunningTasksInAllNamespaces()) { |
191 has_namespaces_with_finished_running_tasks_cv_.Wait(); | 248 has_namespaces_with_finished_running_tasks_cv_.Wait(); |
192 } | 249 } |
193 } | 250 } |
(...skipping 21 matching lines...) Expand all Loading... | |
215 } | 272 } |
216 | 273 |
217 void RasterWorkerPool::ScheduleTasksWithLockAcquired(cc::NamespaceToken token, | 274 void RasterWorkerPool::ScheduleTasksWithLockAcquired(cc::NamespaceToken token, |
218 cc::TaskGraph* graph) { | 275 cc::TaskGraph* graph) { |
219 DCHECK(token.IsValid()); | 276 DCHECK(token.IsValid()); |
220 DCHECK(!cc::TaskGraphWorkQueue::DependencyMismatch(graph)); | 277 DCHECK(!cc::TaskGraphWorkQueue::DependencyMismatch(graph)); |
221 DCHECK(!shutdown_); | 278 DCHECK(!shutdown_); |
222 | 279 |
223 work_queue_.ScheduleTasks(token, graph); | 280 work_queue_.ScheduleTasks(token, graph); |
224 | 281 |
225 // If there is more work available, wake up worker thread. | 282 // If there is more work available, wake up the other worker threads. |
226 if (work_queue_.HasReadyToRunTasks()) | 283 if (work_queue_.HasReadyToRunTasks()) |
227 has_ready_to_run_tasks_cv_.Signal(); | 284 has_ready_to_run_tasks_cv_.Broadcast(); |
228 } | 285 } |
229 | 286 |
230 void RasterWorkerPool::WaitForTasksToFinishRunning(cc::NamespaceToken token) { | 287 void RasterWorkerPool::WaitForTasksToFinishRunning(cc::NamespaceToken token) { |
231 TRACE_EVENT0("cc", "RasterWorkerPool::WaitForTasksToFinishRunning"); | 288 TRACE_EVENT0("cc", "RasterWorkerPool::WaitForTasksToFinishRunning"); |
232 | 289 |
233 DCHECK(token.IsValid()); | 290 DCHECK(token.IsValid()); |
234 | 291 |
235 { | 292 { |
236 base::AutoLock lock(lock_); | 293 base::AutoLock lock(lock_); |
237 base::ThreadRestrictions::ScopedAllowWait allow_wait; | 294 base::ThreadRestrictions::ScopedAllowWait allow_wait; |
(...skipping 19 matching lines...) Expand all Loading... | |
257 } | 314 } |
258 } | 315 } |
259 | 316 |
260 void RasterWorkerPool::CollectCompletedTasksWithLockAcquired( | 317 void RasterWorkerPool::CollectCompletedTasksWithLockAcquired( |
261 cc::NamespaceToken token, | 318 cc::NamespaceToken token, |
262 cc::Task::Vector* completed_tasks) { | 319 cc::Task::Vector* completed_tasks) { |
263 DCHECK(token.IsValid()); | 320 DCHECK(token.IsValid()); |
264 work_queue_.CollectCompletedTasks(token, completed_tasks); | 321 work_queue_.CollectCompletedTasks(token, completed_tasks); |
265 } | 322 } |
266 | 323 |
267 bool RasterWorkerPool::RunTaskWithLockAcquired() { | 324 void RasterWorkerPool::RunTaskWithLockAcquired(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 |