Chromium Code Reviews| 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 |