Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(339)

Side by Side Diff: cc/worker_pool.cc

Issue 12217105: cc: Check for completed raster tasks at interval. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix race condition Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « cc/worker_pool.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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 #if defined(OS_ANDROID)
40 // low while making sure workers aren't unnecessarily idle. 41 const int kNumPendingTasksPerWorker = 8;
41 const int kNumPendingTasksPerWorker = 2; 42 #else
43 const int kNumPendingTasksPerWorker = 40;
44 #endif
45
46 const int kCheckForCompletedTasksDelayMs = 6;
42 47
43 } // namespace 48 } // namespace
44 49
45 namespace internal { 50 namespace internal {
46 51
47 WorkerPoolTask::WorkerPoolTask(const base::Closure& reply) 52 WorkerPoolTask::WorkerPoolTask(const base::Closure& reply) : reply_(reply) {
48 : reply_(reply) { 53 base::subtle::Acquire_Store(&completed_, 0);
49 } 54 }
50 55
51 WorkerPoolTask::~WorkerPoolTask() { 56 WorkerPoolTask::~WorkerPoolTask() {
52 } 57 }
53 58
54 void WorkerPoolTask::Completed() { 59 bool WorkerPoolTask::HasCompleted() {
60 return base::subtle::Acquire_Load(&completed_) == 1;
61 }
62
63 void WorkerPoolTask::DidComplete() {
64 DCHECK_EQ(base::subtle::Acquire_Load(&completed_), 1);
55 reply_.Run(); 65 reply_.Run();
56 } 66 }
57 67
58 } // namespace internal 68 } // namespace internal
59 69
60 WorkerPool::Worker::Worker(WorkerPool* worker_pool, const std::string name) 70 WorkerPool::Worker::Worker(WorkerPool* worker_pool, const std::string name)
61 : base::Thread(name.c_str()), 71 : base::Thread(name.c_str()),
62 worker_pool_(worker_pool), 72 worker_pool_(worker_pool),
63 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
64 rendering_stats_(make_scoped_ptr(new RenderingStats)), 73 rendering_stats_(make_scoped_ptr(new RenderingStats)),
65 record_rendering_stats_(false) { 74 record_rendering_stats_(false) {
66 Start(); 75 Start();
67 DCHECK(IsRunning()); 76 DCHECK(IsRunning());
68 } 77 }
69 78
70 WorkerPool::Worker::~Worker() { 79 WorkerPool::Worker::~Worker() {
71 DCHECK(!IsRunning()); 80 DCHECK(!IsRunning());
72 DCHECK_EQ(pending_tasks_.size(), 0); 81 DCHECK_EQ(pending_tasks_.size(), 0);
73 } 82 }
74 83
75 void WorkerPool::Worker::StopAfterCompletingAllPendingTasks() { 84 void WorkerPool::Worker::StopAfterCompletingAllPendingTasks() {
76 // Signals the thread to exit and returns once all pending tasks have run. 85 // Signals the thread to exit and returns once all pending tasks have run.
77 Stop(); 86 Stop();
78 87
79 // Complete all pending tasks. The Stop() call above guarantees that 88 // Complete all pending tasks. The Stop() call above guarantees that
80 // all tasks have finished running. 89 // all tasks have finished running.
81 while (!pending_tasks_.empty()) 90 while (!pending_tasks_.empty())
82 OnTaskCompleted(); 91 OnTaskCompleted();
83
84 // Cancel all pending replies.
85 weak_ptr_factory_.InvalidateWeakPtrs();
86 } 92 }
87 93
88 void WorkerPool::Worker::PostTask(scoped_ptr<internal::WorkerPoolTask> task) { 94 void WorkerPool::Worker::PostTask(scoped_ptr<internal::WorkerPoolTask> task) {
89 DCHECK_LT(num_pending_tasks(), kNumPendingTasksPerWorker);
90
91 RenderingStats* stats = 95 RenderingStats* stats =
92 record_rendering_stats_ ? rendering_stats_.get() : NULL; 96 record_rendering_stats_ ? rendering_stats_.get() : NULL;
93 97
94 message_loop_proxy()->PostTaskAndReply( 98 worker_pool_->WillPostTask();
99
100 message_loop_proxy()->PostTask(
95 FROM_HERE, 101 FROM_HERE,
96 base::Bind(&Worker::RunTask, 102 base::Bind(&Worker::RunTask,
97 base::Unretained(task.get()), 103 base::Unretained(task.get()),
98 base::Unretained(stats)), 104 base::Unretained(worker_pool_),
99 base::Bind(&Worker::OnTaskCompleted, weak_ptr_factory_.GetWeakPtr())); 105 base::Unretained(stats)));
100 106
101 pending_tasks_.push_back(task.Pass()); 107 pending_tasks_.push_back(task.Pass());
102
103 worker_pool_->DidNumPendingTasksChange();
104 } 108 }
105 109
106 void WorkerPool::Worker::Init() { 110 void WorkerPool::Worker::Init() {
107 #if defined(OS_ANDROID) 111 #if defined(OS_ANDROID)
108 // TODO(epenner): Move thread priorities to base. (crbug.com/170549) 112 // TODO(epenner): Move thread priorities to base. (crbug.com/170549)
109 int nice_value = 10; // Idle priority. 113 int nice_value = 10; // Idle priority.
110 setpriority(PRIO_PROCESS, base::PlatformThread::CurrentId(), nice_value); 114 setpriority(PRIO_PROCESS, base::PlatformThread::CurrentId(), nice_value);
111 #endif 115 #endif
112 } 116 }
113 117
114 // static 118 // static
115 void WorkerPool::Worker::RunTask( 119 void WorkerPool::Worker::RunTask(
116 internal::WorkerPoolTask* task, RenderingStats* rendering_stats) { 120 internal::WorkerPoolTask* task,
121 WorkerPool* worker_pool,
122 RenderingStats* rendering_stats) {
117 task->Run(rendering_stats); 123 task->Run(rendering_stats);
124 worker_pool->OnWorkCompletedOnWorkerThread();
118 } 125 }
119 126
120 void WorkerPool::Worker::OnTaskCompleted() { 127 void WorkerPool::Worker::OnTaskCompleted() {
121 CHECK(!pending_tasks_.empty()); 128 CHECK(!pending_tasks_.empty());
122 129
123 scoped_ptr<internal::WorkerPoolTask> task = pending_tasks_.take_front(); 130 scoped_ptr<internal::WorkerPoolTask> task = pending_tasks_.take_front();
124 task->Completed();
125 131
126 worker_pool_->DidNumPendingTasksChange(); 132 // Notify worker pool of task completion.
133 worker_pool_->OnTaskCompleted();
134
135 task->DidComplete();
127 } 136 }
128 137
129 WorkerPool::WorkerPool(size_t num_threads) 138 void WorkerPool::Worker::CheckForCompletedTasks() {
130 : workers_need_sorting_(false), 139 while (!pending_tasks_.empty()) {
131 shutdown_(false) { 140 if (!pending_tasks_.front()->HasCompleted())
141 return;
142
143 OnTaskCompleted();
144 }
145 }
146
147 WorkerPool::WorkerPool(WorkerPoolClient* client, size_t num_threads)
148 : client_(client),
149 origin_loop_(base::MessageLoopProxy::current()),
150 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
151 workers_need_sorting_(false),
152 pending_task_count_(0),
153 shutdown_(false),
154 check_for_completed_tasks_pending_(false),
155 idle_callback_(
156 base::Bind(&WorkerPool::OnIdle, weak_ptr_factory_.GetWeakPtr())) {
132 const std::string thread_name_prefix = kWorkerThreadNamePrefix; 157 const std::string thread_name_prefix = kWorkerThreadNamePrefix;
133 while (workers_.size() < num_threads) { 158 while (workers_.size() < num_threads) {
134 int thread_number = workers_.size() + 1; 159 int thread_number = workers_.size() + 1;
135 workers_.push_back(new Worker( 160 workers_.push_back(new Worker(
136 this, 161 this,
137 thread_name_prefix + StringPrintf("Worker%d", thread_number).c_str())); 162 thread_name_prefix + StringPrintf("Worker%d", thread_number).c_str()));
138 } 163 }
164 base::subtle::Acquire_Store(&pending_task_count_, 0);
139 } 165 }
140 166
141 WorkerPool::~WorkerPool() { 167 WorkerPool::~WorkerPool() {
142 Shutdown(); 168 Shutdown();
143 STLDeleteElements(&workers_); 169 STLDeleteElements(&workers_);
170 // Cancel all pending callbacks.
171 weak_ptr_factory_.InvalidateWeakPtrs();
172 DCHECK_EQ(base::subtle::Acquire_Load(&pending_task_count_), 0);
144 } 173 }
145 174
146 void WorkerPool::Shutdown() { 175 void WorkerPool::Shutdown() {
147 DCHECK(!shutdown_); 176 DCHECK(!shutdown_);
148 shutdown_ = true; 177 shutdown_ = true;
149 178
150 for (WorkerVector::iterator it = workers_.begin(); 179 for (WorkerVector::iterator it = workers_.begin();
151 it != workers_.end(); it++) { 180 it != workers_.end(); it++) {
152 Worker* worker = *it; 181 Worker* worker = *it;
153 worker->StopAfterCompletingAllPendingTasks(); 182 worker->StopAfterCompletingAllPendingTasks();
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
197 worker->rendering_stats()->totalDeferredImageDecodeTime; 226 worker->rendering_stats()->totalDeferredImageDecodeTime;
198 } 227 }
199 } 228 }
200 229
201 WorkerPool::Worker* WorkerPool::GetWorkerForNextTask() { 230 WorkerPool::Worker* WorkerPool::GetWorkerForNextTask() {
202 CHECK(!shutdown_); 231 CHECK(!shutdown_);
203 SortWorkersIfNeeded(); 232 SortWorkersIfNeeded();
204 return workers_.front(); 233 return workers_.front();
205 } 234 }
206 235
207 void WorkerPool::DidNumPendingTasksChange() { 236 void WorkerPool::ScheduleCheckForCompletedTasks() {
237 if (check_for_completed_tasks_pending_)
238 return;
239
240 check_for_completed_tasks_callback_.Reset(
241 base::Bind(&WorkerPool::CheckForCompletedTasks,
242 weak_ptr_factory_.GetWeakPtr()));
243 origin_loop_->PostDelayedTask(
244 FROM_HERE,
245 check_for_completed_tasks_callback_.callback(),
246 base::TimeDelta::FromMilliseconds(kCheckForCompletedTasksDelayMs));
247 check_for_completed_tasks_pending_ = true;
248 }
249
250 void WorkerPool::WillPostTask() {
251 base::subtle::Barrier_AtomicIncrement(&pending_task_count_, 1);
252 ScheduleCheckForCompletedTasks();
208 workers_need_sorting_ = true; 253 workers_need_sorting_ = true;
209 } 254 }
210 255
256 void WorkerPool::OnWorkCompletedOnWorkerThread() {
257 // Post idle handler task when pool work count reaches 0.
258 if (base::subtle::Barrier_AtomicIncrement(&pending_task_count_, -1) == 0) {
259 origin_loop_->PostTask(FROM_HERE, idle_callback_);
260 }
261 }
262
263 void WorkerPool::OnIdle() {
264 if (base::subtle::Acquire_Load(&pending_task_count_) == 0) {
265 check_for_completed_tasks_callback_.Cancel();
266 CheckForCompletedTasks();
267 }
268 }
269
270 void WorkerPool::CheckForCompletedTasks() {
271 check_for_completed_tasks_pending_ = false;
272
273 for (WorkerVector::iterator it = workers_.begin();
274 it != workers_.end(); it++) {
275 Worker* worker = *it;
276 worker->CheckForCompletedTasks();
277 }
278
279 client_->DidFinishDispatchingWorkerPoolCompletionCallbacks();
280
281 for (WorkerVector::iterator it = workers_.begin();
282 it != workers_.end(); it++) {
283 Worker* worker = *it;
284 if (worker->num_pending_tasks()) {
brianderson 2013/02/14 01:12:07 No race condition and no unnecessary checks schedu
285 ScheduleCheckForCompletedTasks();
286 break;
287 }
288 }
289 }
290
291 void WorkerPool::OnTaskCompleted() {
292 workers_need_sorting_ = true;
293 }
294
211 void WorkerPool::SortWorkersIfNeeded() { 295 void WorkerPool::SortWorkersIfNeeded() {
212 if (!workers_need_sorting_) 296 if (!workers_need_sorting_)
213 return; 297 return;
214 298
215 std::sort(workers_.begin(), workers_.end(), NumPendingTasksComparator()); 299 std::sort(workers_.begin(), workers_.end(), NumPendingTasksComparator());
216 workers_need_sorting_ = false; 300 workers_need_sorting_ = false;
217 } 301 }
218 302
219 } // namespace cc 303 } // namespace cc
OLDNEW
« no previous file with comments | « cc/worker_pool.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698