| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 "cc/worker_pool.h" | 5 #include "cc/worker_pool.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/stl_util.h" | 10 #include "base/stl_util.h" |
| (...skipping 10 matching lines...) Expand all Loading... |
| 21 | 21 |
| 22 class WorkerPoolTaskImpl : public internal::WorkerPoolTask { | 22 class WorkerPoolTaskImpl : public internal::WorkerPoolTask { |
| 23 public: | 23 public: |
| 24 WorkerPoolTaskImpl(const WorkerPool::Callback& task, | 24 WorkerPoolTaskImpl(const WorkerPool::Callback& task, |
| 25 const base::Closure& reply) | 25 const base::Closure& reply) |
| 26 : internal::WorkerPoolTask(reply), | 26 : internal::WorkerPoolTask(reply), |
| 27 task_(task) {} | 27 task_(task) {} |
| 28 | 28 |
| 29 virtual void Run(RenderingStats* rendering_stats) OVERRIDE { | 29 virtual void Run(RenderingStats* rendering_stats) OVERRIDE { |
| 30 task_.Run(rendering_stats); | 30 task_.Run(rendering_stats); |
| 31 base::subtle::Release_Store(&completed_, 1); |
| 31 } | 32 } |
| 32 | 33 |
| 33 private: | 34 private: |
| 34 WorkerPool::Callback task_; | 35 WorkerPool::Callback task_; |
| 35 }; | 36 }; |
| 36 | 37 |
| 37 const char* kWorkerThreadNamePrefix = "Compositor"; | 38 const char* kWorkerThreadNamePrefix = "Compositor"; |
| 38 | 39 |
| 39 // Allow two pending tasks per worker. This keeps resource usage | 40 const int kCheckForCompletedTasksDelayMs = 6; |
| 40 // low while making sure workers aren't unnecessarily idle. | |
| 41 const int kNumPendingTasksPerWorker = 2; | |
| 42 | 41 |
| 43 } // namespace | 42 } // namespace |
| 44 | 43 |
| 45 namespace internal { | 44 namespace internal { |
| 46 | 45 |
| 47 WorkerPoolTask::WorkerPoolTask(const base::Closure& reply) | 46 WorkerPoolTask::WorkerPoolTask(const base::Closure& reply) : reply_(reply) { |
| 48 : reply_(reply) { | 47 base::subtle::Acquire_Store(&completed_, 0); |
| 49 } | 48 } |
| 50 | 49 |
| 51 WorkerPoolTask::~WorkerPoolTask() { | 50 WorkerPoolTask::~WorkerPoolTask() { |
| 52 } | 51 } |
| 53 | 52 |
| 54 void WorkerPoolTask::Completed() { | 53 bool WorkerPoolTask::HasCompleted() { |
| 54 return base::subtle::Acquire_Load(&completed_) == 0; |
| 55 } |
| 56 |
| 57 void WorkerPoolTask::DidComplete() { |
| 58 DCHECK_EQ(base::subtle::Acquire_Load(&completed_), 1); |
| 55 reply_.Run(); | 59 reply_.Run(); |
| 56 } | 60 } |
| 57 | 61 |
| 58 } // namespace internal | 62 } // namespace internal |
| 59 | 63 |
| 60 WorkerPool::Worker::Worker(WorkerPool* worker_pool, const std::string name) | 64 WorkerPool::Worker::Worker(WorkerPool* worker_pool, const std::string name) |
| 61 : base::Thread(name.c_str()), | 65 : base::Thread(name.c_str()), |
| 62 worker_pool_(worker_pool), | 66 worker_pool_(worker_pool), |
| 63 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), | |
| 64 rendering_stats_(make_scoped_ptr(new RenderingStats)), | 67 rendering_stats_(make_scoped_ptr(new RenderingStats)), |
| 65 record_rendering_stats_(false) { | 68 record_rendering_stats_(false) { |
| 66 Start(); | 69 Start(); |
| 67 DCHECK(IsRunning()); | 70 DCHECK(IsRunning()); |
| 68 } | 71 } |
| 69 | 72 |
| 70 WorkerPool::Worker::~Worker() { | 73 WorkerPool::Worker::~Worker() { |
| 71 DCHECK(!IsRunning()); | 74 DCHECK(!IsRunning()); |
| 72 DCHECK_EQ(pending_tasks_.size(), 0); | 75 DCHECK_EQ(pending_tasks_.size(), 0); |
| 73 } | 76 } |
| 74 | 77 |
| 75 void WorkerPool::Worker::StopAfterCompletingAllPendingTasks() { | 78 void WorkerPool::Worker::StopAfterCompletingAllPendingTasks() { |
| 76 // Signals the thread to exit and returns once all pending tasks have run. | 79 // Signals the thread to exit and returns once all pending tasks have run. |
| 77 Stop(); | 80 Stop(); |
| 78 | 81 |
| 79 // Complete all pending tasks. The Stop() call above guarantees that | 82 // Complete all pending tasks. The Stop() call above guarantees that |
| 80 // all tasks have finished running. | 83 // all tasks have finished running. |
| 81 while (!pending_tasks_.empty()) | 84 while (!pending_tasks_.empty()) |
| 82 OnTaskCompleted(); | 85 OnTaskCompleted(); |
| 83 | |
| 84 // Cancel all pending replies. | |
| 85 weak_ptr_factory_.InvalidateWeakPtrs(); | |
| 86 } | 86 } |
| 87 | 87 |
| 88 void WorkerPool::Worker::PostTask(scoped_ptr<internal::WorkerPoolTask> task) { | 88 void WorkerPool::Worker::PostTask(scoped_ptr<internal::WorkerPoolTask> task) { |
| 89 DCHECK_LT(num_pending_tasks(), kNumPendingTasksPerWorker); | |
| 90 | |
| 91 RenderingStats* stats = | 89 RenderingStats* stats = |
| 92 record_rendering_stats_ ? rendering_stats_.get() : NULL; | 90 record_rendering_stats_ ? rendering_stats_.get() : NULL; |
| 93 | 91 |
| 94 message_loop_proxy()->PostTaskAndReply( | 92 worker_pool_->WillPostTask(); |
| 93 |
| 94 message_loop_proxy()->PostTask( |
| 95 FROM_HERE, | 95 FROM_HERE, |
| 96 base::Bind(&Worker::RunTask, | 96 base::Bind(&Worker::RunTask, |
| 97 base::Unretained(task.get()), | 97 base::Unretained(task.get()), |
| 98 base::Unretained(stats)), | 98 base::Unretained(worker_pool_), |
| 99 base::Bind(&Worker::OnTaskCompleted, weak_ptr_factory_.GetWeakPtr())); | 99 base::Unretained(stats))); |
| 100 | 100 |
| 101 pending_tasks_.push_back(task.Pass()); | 101 pending_tasks_.push_back(task.Pass()); |
| 102 | |
| 103 worker_pool_->DidNumPendingTasksChange(); | |
| 104 } | 102 } |
| 105 | 103 |
| 106 void WorkerPool::Worker::Init() { | 104 void WorkerPool::Worker::Init() { |
| 107 #if defined(OS_ANDROID) | 105 #if defined(OS_ANDROID) |
| 108 // TODO(epenner): Move thread priorities to base. (crbug.com/170549) | 106 // TODO(epenner): Move thread priorities to base. (crbug.com/170549) |
| 109 int nice_value = 10; // Idle priority. | 107 int nice_value = 10; // Idle priority. |
| 110 setpriority(PRIO_PROCESS, base::PlatformThread::CurrentId(), nice_value); | 108 setpriority(PRIO_PROCESS, base::PlatformThread::CurrentId(), nice_value); |
| 111 #endif | 109 #endif |
| 112 } | 110 } |
| 113 | 111 |
| 114 // static | 112 // static |
| 115 void WorkerPool::Worker::RunTask( | 113 void WorkerPool::Worker::RunTask( |
| 116 internal::WorkerPoolTask* task, RenderingStats* rendering_stats) { | 114 internal::WorkerPoolTask* task, |
| 115 WorkerPool* worker_pool, |
| 116 RenderingStats* rendering_stats) { |
| 117 task->Run(rendering_stats); | 117 task->Run(rendering_stats); |
| 118 worker_pool->OnWorkCompletedOnWorkerThread(); |
| 118 } | 119 } |
| 119 | 120 |
| 120 void WorkerPool::Worker::OnTaskCompleted() { | 121 void WorkerPool::Worker::OnTaskCompleted() { |
| 121 CHECK(!pending_tasks_.empty()); | 122 CHECK(!pending_tasks_.empty()); |
| 122 | 123 |
| 123 scoped_ptr<internal::WorkerPoolTask> task = pending_tasks_.take_front(); | 124 scoped_ptr<internal::WorkerPoolTask> task = pending_tasks_.take_front(); |
| 124 task->Completed(); | |
| 125 | 125 |
| 126 worker_pool_->DidNumPendingTasksChange(); | 126 // Notify worker pool of task completion. |
| 127 worker_pool_->OnTaskCompleted(); |
| 128 |
| 129 task->DidComplete(); |
| 127 } | 130 } |
| 128 | 131 |
| 129 WorkerPool::WorkerPool(size_t num_threads) | 132 void WorkerPool::Worker::CheckForCompletedTasks() { |
| 130 : workers_need_sorting_(false), | 133 while (!pending_tasks_.empty()) { |
| 131 shutdown_(false) { | 134 if (pending_tasks_.front()->HasCompleted()) |
| 135 return; |
| 136 |
| 137 OnTaskCompleted(); |
| 138 } |
| 139 } |
| 140 |
| 141 WorkerPool::WorkerPool(WorkerPoolClient* client, size_t num_threads) |
| 142 : client_(client), |
| 143 origin_loop_(base::MessageLoopProxy::current()), |
| 144 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), |
| 145 workers_need_sorting_(false), |
| 146 pending_task_count_(0), |
| 147 shutdown_(false), |
| 148 check_for_completed_tasks_pending_(false), |
| 149 idle_callback_( |
| 150 base::Bind(&WorkerPool::OnIdle, weak_ptr_factory_.GetWeakPtr())) { |
| 132 const std::string thread_name_prefix = kWorkerThreadNamePrefix; | 151 const std::string thread_name_prefix = kWorkerThreadNamePrefix; |
| 133 while (workers_.size() < num_threads) { | 152 while (workers_.size() < num_threads) { |
| 134 int thread_number = workers_.size() + 1; | 153 int thread_number = workers_.size() + 1; |
| 135 workers_.push_back(new Worker( | 154 workers_.push_back(new Worker( |
| 136 this, | 155 this, |
| 137 thread_name_prefix + StringPrintf("Worker%d", thread_number).c_str())); | 156 thread_name_prefix + StringPrintf("Worker%d", thread_number).c_str())); |
| 138 } | 157 } |
| 158 base::subtle::Acquire_Store(&pending_task_count_, 0); |
| 139 } | 159 } |
| 140 | 160 |
| 141 WorkerPool::~WorkerPool() { | 161 WorkerPool::~WorkerPool() { |
| 142 Shutdown(); | 162 Shutdown(); |
| 143 STLDeleteElements(&workers_); | 163 STLDeleteElements(&workers_); |
| 164 // Cancel all pending callbacks. |
| 165 weak_ptr_factory_.InvalidateWeakPtrs(); |
| 166 DCHECK_EQ(base::subtle::Acquire_Load(&pending_task_count_), 0); |
| 144 } | 167 } |
| 145 | 168 |
| 146 void WorkerPool::Shutdown() { | 169 void WorkerPool::Shutdown() { |
| 147 DCHECK(!shutdown_); | 170 DCHECK(!shutdown_); |
| 148 shutdown_ = true; | 171 shutdown_ = true; |
| 149 | 172 |
| 150 for (WorkerVector::iterator it = workers_.begin(); | 173 for (WorkerVector::iterator it = workers_.begin(); |
| 151 it != workers_.end(); it++) { | 174 it != workers_.end(); it++) { |
| 152 Worker* worker = *it; | 175 Worker* worker = *it; |
| 153 worker->StopAfterCompletingAllPendingTasks(); | 176 worker->StopAfterCompletingAllPendingTasks(); |
| 154 } | 177 } |
| 155 } | 178 } |
| 156 | 179 |
| 157 void WorkerPool::PostTaskAndReply( | 180 void WorkerPool::PostTaskAndReply( |
| 158 const Callback& task, const base::Closure& reply) { | 181 const Callback& task, const base::Closure& reply) { |
| 159 Worker* worker = GetWorkerForNextTask(); | 182 Worker* worker = GetWorkerForNextTask(); |
| 160 | 183 |
| 161 worker->PostTask( | 184 worker->PostTask( |
| 162 make_scoped_ptr(new WorkerPoolTaskImpl( | 185 make_scoped_ptr(new WorkerPoolTaskImpl( |
| 163 task, | 186 task, |
| 164 reply)).PassAs<internal::WorkerPoolTask>()); | 187 reply)).PassAs<internal::WorkerPoolTask>()); |
| 165 } | 188 } |
| 166 | 189 |
| 167 bool WorkerPool::IsBusy() { | |
| 168 Worker* worker = GetWorkerForNextTask(); | |
| 169 | |
| 170 return worker->num_pending_tasks() >= kNumPendingTasksPerWorker; | |
| 171 } | |
| 172 | |
| 173 void WorkerPool::SetRecordRenderingStats(bool record_rendering_stats) { | 190 void WorkerPool::SetRecordRenderingStats(bool record_rendering_stats) { |
| 174 for (WorkerVector::iterator it = workers_.begin(); | 191 for (WorkerVector::iterator it = workers_.begin(); |
| 175 it != workers_.end(); ++it) { | 192 it != workers_.end(); ++it) { |
| 176 Worker* worker = *it; | 193 Worker* worker = *it; |
| 177 worker->set_record_rendering_stats(record_rendering_stats); | 194 worker->set_record_rendering_stats(record_rendering_stats); |
| 178 } | 195 } |
| 179 } | 196 } |
| 180 | 197 |
| 181 void WorkerPool::GetRenderingStats(RenderingStats* stats) { | 198 void WorkerPool::GetRenderingStats(RenderingStats* stats) { |
| 182 stats->totalRasterizeTime = base::TimeDelta(); | 199 stats->totalRasterizeTime = base::TimeDelta(); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 197 worker->rendering_stats()->totalDeferredImageDecodeTime; | 214 worker->rendering_stats()->totalDeferredImageDecodeTime; |
| 198 } | 215 } |
| 199 } | 216 } |
| 200 | 217 |
| 201 WorkerPool::Worker* WorkerPool::GetWorkerForNextTask() { | 218 WorkerPool::Worker* WorkerPool::GetWorkerForNextTask() { |
| 202 CHECK(!shutdown_); | 219 CHECK(!shutdown_); |
| 203 SortWorkersIfNeeded(); | 220 SortWorkersIfNeeded(); |
| 204 return workers_.front(); | 221 return workers_.front(); |
| 205 } | 222 } |
| 206 | 223 |
| 207 void WorkerPool::DidNumPendingTasksChange() { | 224 void WorkerPool::ScheduleCheckForCompletedTasks() { |
| 225 if (check_for_completed_tasks_pending_) |
| 226 return; |
| 227 |
| 228 check_for_completed_tasks_callback_.Reset( |
| 229 base::Bind(&WorkerPool::CheckForCompletedTasks, |
| 230 weak_ptr_factory_.GetWeakPtr())); |
| 231 origin_loop_->PostDelayedTask( |
| 232 FROM_HERE, |
| 233 check_for_completed_tasks_callback_.callback(), |
| 234 base::TimeDelta::FromMilliseconds(kCheckForCompletedTasksDelayMs)); |
| 235 check_for_completed_tasks_pending_ = true; |
| 236 } |
| 237 |
| 238 void WorkerPool::WillPostTask() { |
| 239 base::subtle::Barrier_AtomicIncrement(&pending_task_count_, 1); |
| 240 ScheduleCheckForCompletedTasks(); |
| 208 workers_need_sorting_ = true; | 241 workers_need_sorting_ = true; |
| 209 } | 242 } |
| 210 | 243 |
| 244 void WorkerPool::OnWorkCompletedOnWorkerThread() { |
| 245 // Post idle handler task when pool work count reaches 0. |
| 246 if (base::subtle::Barrier_AtomicIncrement(&pending_task_count_, -1) == 0) { |
| 247 origin_loop_->PostTask(FROM_HERE, idle_callback_); |
| 248 } |
| 249 } |
| 250 |
| 251 void WorkerPool::OnIdle() { |
| 252 if (base::subtle::Acquire_Load(&pending_task_count_) == 0) { |
| 253 check_for_completed_tasks_callback_.Cancel(); |
| 254 CheckForCompletedTasks(); |
| 255 } |
| 256 } |
| 257 |
| 258 void WorkerPool::CheckForCompletedTasks() { |
| 259 check_for_completed_tasks_pending_ = false; |
| 260 |
| 261 for (WorkerVector::iterator it = workers_.begin(); |
| 262 it != workers_.end(); it++) { |
| 263 Worker* worker = *it; |
| 264 worker->CheckForCompletedTasks(); |
| 265 } |
| 266 |
| 267 client_->DidFinishDispatchingCompletionCallbacks(); |
| 268 |
| 269 if (base::subtle::Acquire_Load(&pending_task_count_)) |
| 270 ScheduleCheckForCompletedTasks(); |
| 271 } |
| 272 |
| 273 void WorkerPool::OnTaskCompleted() { |
| 274 workers_need_sorting_ = true; |
| 275 } |
| 276 |
| 211 void WorkerPool::SortWorkersIfNeeded() { | 277 void WorkerPool::SortWorkersIfNeeded() { |
| 212 if (!workers_need_sorting_) | 278 if (!workers_need_sorting_) |
| 213 return; | 279 return; |
| 214 | 280 |
| 215 std::sort(workers_.begin(), workers_.end(), NumPendingTasksComparator()); | 281 std::sort(workers_.begin(), workers_.end(), NumPendingTasksComparator()); |
| 216 workers_need_sorting_ = false; | 282 workers_need_sorting_ = false; |
| 217 } | 283 } |
| 218 | 284 |
| 219 } // namespace cc | 285 } // namespace cc |
| OLD | NEW |