blob: 0924c0a5118b24e3a97717b8e842d3045fe55286 [file] [log] [blame]
dcastagna4517a182015-08-05 19:51:031// Copyright 2015 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
tfarinab62c25192015-10-27 03:14:485#include "content/renderer/raster_worker_pool.h"
dcastagna4517a182015-08-05 19:51:036
ericrk7795c7002016-01-21 22:49:187#include <string>
ericrk5a1188c62015-12-18 22:04:048#include <utility>
ericrk7795c7002016-01-21 22:49:189#include <vector>
ericrk5a1188c62015-12-18 22:04:0410
dcastagna4517a182015-08-05 19:51:0311#include "base/strings/stringprintf.h"
ericrk4e3aa5a2015-12-01 03:53:5612#include "base/threading/thread_restrictions.h"
13#include "base/trace_event/trace_event.h"
ericrk7795c7002016-01-21 22:49:1814#include "cc/base/math_util.h"
15#include "cc/raster/task_category.h"
dcastagna4517a182015-08-05 19:51:0316
17namespace content {
ericrk7795c7002016-01-21 22:49:1818namespace {
19
20// A thread which forwards to RasterWorkerPool::Run with the runnable
21// categories.
22class RasterWorkerPoolThread : public base::SimpleThread {
23 public:
skyostila1c7eb72016-02-12 17:14:0824 explicit RasterWorkerPoolThread(const std::string& name_prefix,
25 const Options& options,
26 RasterWorkerPool* pool,
27 std::vector<cc::TaskCategory> categories)
ericrk7795c7002016-01-21 22:49:1828 : SimpleThread(name_prefix, options),
29 pool_(pool),
skyostila1c7eb72016-02-12 17:14:0830 categories_(categories) {}
ericrk7795c7002016-01-21 22:49:1831
skyostila1c7eb72016-02-12 17:14:0832 void Run() override { pool_->Run(categories_); }
ericrk7795c7002016-01-21 22:49:1833
34 private:
35 RasterWorkerPool* const pool_;
36 const std::vector<cc::TaskCategory> categories_;
37};
38
39} // namespace
dcastagna4517a182015-08-05 19:51:0340
41// A sequenced task runner which posts tasks to a RasterWorkerPool.
42class RasterWorkerPool::RasterWorkerPoolSequencedTaskRunner
43 : public base::SequencedTaskRunner {
44 public:
ericrk4e3aa5a2015-12-01 03:53:5645 explicit RasterWorkerPoolSequencedTaskRunner(
46 cc::TaskGraphRunner* task_graph_runner)
dcastagna4517a182015-08-05 19:51:0347 : task_graph_runner_(task_graph_runner),
48 namespace_token_(task_graph_runner->GetNamespaceToken()) {}
49
50 // Overridden from base::TaskRunner:
51 bool PostDelayedTask(const tracked_objects::Location& from_here,
52 const base::Closure& task,
53 base::TimeDelta delay) override {
54 return PostNonNestableDelayedTask(from_here, task, delay);
55 }
56 bool RunsTasksOnCurrentThread() const override { return true; }
57
58 // Overridden from base::SequencedTaskRunner:
59 bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
60 const base::Closure& task,
61 base::TimeDelta delay) override {
62 base::AutoLock lock(lock_);
63
64 // Remove completed tasks.
65 DCHECK(completed_tasks_.empty());
66 task_graph_runner_->CollectCompletedTasks(namespace_token_,
67 &completed_tasks_);
68
69 tasks_.erase(tasks_.begin(), tasks_.begin() + completed_tasks_.size());
70
71 tasks_.push_back(make_scoped_refptr(new ClosureTask(task)));
72 graph_.Reset();
dcastagnad3ecba52015-08-06 21:37:2573 for (const auto& graph_task : tasks_) {
dcastagna4517a182015-08-05 19:51:0374 int dependencies = 0;
75 if (!graph_.nodes.empty())
76 dependencies = 1;
77
ericrk7795c7002016-01-21 22:49:1878 // 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,
ericrk5a1188c62015-12-18 22:04:0482 0u /* priority */, dependencies);
dcastagna4517a182015-08-05 19:51:0383 if (dependencies) {
84 graph_.edges.push_back(
85 cc::TaskGraph::Edge(graph_.nodes.back().task, node.task));
86 }
87 graph_.nodes.push_back(node);
88 }
89 task_graph_runner_->ScheduleTasks(namespace_token_, &graph_);
90 completed_tasks_.clear();
91 return true;
92 }
93
94 private:
95 ~RasterWorkerPoolSequencedTaskRunner() override {
96 task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_);
97 task_graph_runner_->CollectCompletedTasks(namespace_token_,
98 &completed_tasks_);
99 };
100
dcastagna4517a182015-08-05 19:51:03101 // Lock to exclusively access all the following members that are used to
102 // implement the SequencedTaskRunner interfaces.
103 base::Lock lock_;
ericrk4e3aa5a2015-12-01 03:53:56104
105 cc::TaskGraphRunner* task_graph_runner_;
dcastagna4517a182015-08-05 19:51:03106 // Namespace used to schedule tasks in the task graph runner.
107 cc::NamespaceToken namespace_token_;
108 // List of tasks currently queued up for execution.
109 cc::Task::Vector tasks_;
110 // Graph object used for scheduling tasks.
111 cc::TaskGraph graph_;
112 // Cached vector to avoid allocation when getting the list of complete
113 // tasks.
114 cc::Task::Vector completed_tasks_;
115};
116
117RasterWorkerPool::RasterWorkerPool()
ericrk4e3aa5a2015-12-01 03:53:56118 : namespace_token_(GetNamespaceToken()),
skyostila1c7eb72016-02-12 17:14:08119 has_ready_to_run_tasks_cv_(&lock_),
ericrk4e3aa5a2015-12-01 03:53:56120 has_namespaces_with_finished_running_tasks_cv_(&lock_),
121 shutdown_(false) {}
dcastagna4517a182015-08-05 19:51:03122
123void RasterWorkerPool::Start(
124 int num_threads,
125 const base::SimpleThread::Options& thread_options) {
126 DCHECK(threads_.empty());
skyostila1c7eb72016-02-12 17:14:08127 while (threads_.size() < static_cast<size_t>(num_threads)) {
128 // Determine the categories that each thread can run.
129 std::vector<cc::TaskCategory> task_categories;
ericrk7795c7002016-01-21 22:49:18130
skyostila1c7eb72016-02-12 17:14:08131 // The first thread can run nonconcurrent tasks.
132 if (threads_.size() == 0) {
133 task_categories.push_back(cc::TASK_CATEGORY_NONCONCURRENT_FOREGROUND);
134 }
ericrk7795c7002016-01-21 22:49:18135
skyostila1c7eb72016-02-12 17:14:08136 // All threads can run foreground tasks.
137 task_categories.push_back(cc::TASK_CATEGORY_FOREGROUND);
138
139 // The last thread can run background tasks.
140 if (threads_.size() == (static_cast<size_t>(num_threads) - 1)) {
141 task_categories.push_back(cc::TASK_CATEGORY_BACKGROUND);
142 }
143
ericrk7795c7002016-01-21 22:49:18144 scoped_ptr<base::SimpleThread> thread(new RasterWorkerPoolThread(
145 base::StringPrintf("CompositorTileWorker%u",
146 static_cast<unsigned>(threads_.size() + 1))
147 .c_str(),
skyostila1c7eb72016-02-12 17:14:08148 thread_options, this, task_categories));
dcastagna4517a182015-08-05 19:51:03149 thread->Start();
dcheng07945f632015-12-26 07:59:32150 threads_.push_back(std::move(thread));
dcastagna4517a182015-08-05 19:51:03151 }
152}
153
154void RasterWorkerPool::Shutdown() {
ericrk4e3aa5a2015-12-01 03:53:56155 WaitForTasksToFinishRunning(namespace_token_);
156 CollectCompletedTasks(namespace_token_, &completed_tasks_);
dcastagna4517a182015-08-05 19:51:03157 // Shutdown raster threads.
ericrk4e3aa5a2015-12-01 03:53:56158 {
159 base::AutoLock lock(lock_);
160
161 DCHECK(!work_queue_.HasReadyToRunTasks());
162 DCHECK(!work_queue_.HasAnyNamespaces());
163
164 DCHECK(!shutdown_);
165 shutdown_ = true;
166
ericrke3e5b6f2015-12-02 00:00:37167 // Wake up all workers so they exit.
skyostila1c7eb72016-02-12 17:14:08168 has_ready_to_run_tasks_cv_.Broadcast();
ericrk4e3aa5a2015-12-01 03:53:56169 }
dcastagna4517a182015-08-05 19:51:03170 while (!threads_.empty()) {
171 threads_.back()->Join();
172 threads_.pop_back();
173 }
174}
175
176// Overridden from base::TaskRunner:
177bool RasterWorkerPool::PostDelayedTask(
178 const tracked_objects::Location& from_here,
179 const base::Closure& task,
180 base::TimeDelta delay) {
181 base::AutoLock lock(lock_);
182
183 // Remove completed tasks.
184 DCHECK(completed_tasks_.empty());
ericrk4e3aa5a2015-12-01 03:53:56185 CollectCompletedTasksWithLockAcquired(namespace_token_, &completed_tasks_);
dcastagna4517a182015-08-05 19:51:03186
187 cc::Task::Vector::iterator end = std::remove_if(
188 tasks_.begin(), tasks_.end(), [this](const scoped_refptr<cc::Task>& e) {
189 return std::find(this->completed_tasks_.begin(),
190 this->completed_tasks_.end(),
191 e) != this->completed_tasks_.end();
192 });
193 tasks_.erase(end, tasks_.end());
194
195 tasks_.push_back(make_scoped_refptr(new ClosureTask(task)));
196 graph_.Reset();
ericrk7795c7002016-01-21 22:49:18197 for (const auto& graph_task : tasks_) {
198 // Delayed tasks are assigned FOREGROUND category, ensuring that they run as
199 // soon as possible once their delay has expired.
ericrk5a1188c62015-12-18 22:04:04200 graph_.nodes.push_back(
ericrk7795c7002016-01-21 22:49:18201 cc::TaskGraph::Node(graph_task.get(), cc::TASK_CATEGORY_FOREGROUND,
ericrk5a1188c62015-12-18 22:04:04202 0u /* priority */, 0u /* dependencies */));
ericrk7795c7002016-01-21 22:49:18203 }
dcastagna4517a182015-08-05 19:51:03204
ericrk4e3aa5a2015-12-01 03:53:56205 ScheduleTasksWithLockAcquired(namespace_token_, &graph_);
dcastagna4517a182015-08-05 19:51:03206 completed_tasks_.clear();
207 return true;
208}
209
210bool RasterWorkerPool::RunsTasksOnCurrentThread() const {
211 return true;
212}
213
skyostila1c7eb72016-02-12 17:14:08214void RasterWorkerPool::Run(const std::vector<cc::TaskCategory>& categories) {
ericrk4e3aa5a2015-12-01 03:53:56215 base::AutoLock lock(lock_);
216
217 while (true) {
ericrk7795c7002016-01-21 22:49:18218 if (!RunTaskWithLockAcquired(categories)) {
ericrk4e3aa5a2015-12-01 03:53:56219 // Exit when shutdown is set and no more tasks are pending.
220 if (shutdown_)
221 break;
222
223 // Wait for more tasks.
skyostila1c7eb72016-02-12 17:14:08224 has_ready_to_run_tasks_cv_.Wait();
ericrk4e3aa5a2015-12-01 03:53:56225 continue;
226 }
ericrk4e3aa5a2015-12-01 03:53:56227 }
ericrk4e3aa5a2015-12-01 03:53:56228}
229
230void RasterWorkerPool::FlushForTesting() {
231 base::AutoLock lock(lock_);
232
233 while (!work_queue_.HasFinishedRunningTasksInAllNamespaces()) {
234 has_namespaces_with_finished_running_tasks_cv_.Wait();
235 }
dcastagna4517a182015-08-05 19:51:03236}
237
238scoped_refptr<base::SequencedTaskRunner>
239RasterWorkerPool::CreateSequencedTaskRunner() {
ericrk4e3aa5a2015-12-01 03:53:56240 return new RasterWorkerPoolSequencedTaskRunner(this);
dcastagna4517a182015-08-05 19:51:03241}
242
243RasterWorkerPool::~RasterWorkerPool() {}
244
ericrk4e3aa5a2015-12-01 03:53:56245cc::NamespaceToken RasterWorkerPool::GetNamespaceToken() {
246 base::AutoLock lock(lock_);
247 return work_queue_.GetNamespaceToken();
248}
249
250void RasterWorkerPool::ScheduleTasks(cc::NamespaceToken token,
251 cc::TaskGraph* graph) {
vmpstr2d80f2ac2016-01-26 22:16:52252 TRACE_EVENT2("disabled-by-default-cc.debug",
253 "RasterWorkerPool::ScheduleTasks", "num_nodes",
ericrk4e3aa5a2015-12-01 03:53:56254 graph->nodes.size(), "num_edges", graph->edges.size());
255 {
256 base::AutoLock lock(lock_);
257 ScheduleTasksWithLockAcquired(token, graph);
258 }
259}
260
261void RasterWorkerPool::ScheduleTasksWithLockAcquired(cc::NamespaceToken token,
262 cc::TaskGraph* graph) {
263 DCHECK(token.IsValid());
264 DCHECK(!cc::TaskGraphWorkQueue::DependencyMismatch(graph));
265 DCHECK(!shutdown_);
266
267 work_queue_.ScheduleTasks(token, graph);
268
skyostila1c7eb72016-02-12 17:14:08269 // If there is more work available, wake up the other worker threads.
270 if (work_queue_.HasReadyToRunTasks())
271 has_ready_to_run_tasks_cv_.Broadcast();
ericrk4e3aa5a2015-12-01 03:53:56272}
273
274void RasterWorkerPool::WaitForTasksToFinishRunning(cc::NamespaceToken token) {
vmpstr2d80f2ac2016-01-26 22:16:52275 TRACE_EVENT0("disabled-by-default-cc.debug",
276 "RasterWorkerPool::WaitForTasksToFinishRunning");
ericrk4e3aa5a2015-12-01 03:53:56277
278 DCHECK(token.IsValid());
279
280 {
281 base::AutoLock lock(lock_);
282 base::ThreadRestrictions::ScopedAllowWait allow_wait;
283
284 auto* task_namespace = work_queue_.GetNamespaceForToken(token);
285
286 if (!task_namespace)
287 return;
288
289 while (!work_queue_.HasFinishedRunningTasksInNamespace(task_namespace))
290 has_namespaces_with_finished_running_tasks_cv_.Wait();
ericrk4e3aa5a2015-12-01 03:53:56291 }
292}
293
294void RasterWorkerPool::CollectCompletedTasks(
295 cc::NamespaceToken token,
296 cc::Task::Vector* completed_tasks) {
vmpstr2d80f2ac2016-01-26 22:16:52297 TRACE_EVENT0("disabled-by-default-cc.debug",
298 "RasterWorkerPool::CollectCompletedTasks");
ericrk4e3aa5a2015-12-01 03:53:56299
300 {
301 base::AutoLock lock(lock_);
302 CollectCompletedTasksWithLockAcquired(token, completed_tasks);
303 }
304}
305
306void RasterWorkerPool::CollectCompletedTasksWithLockAcquired(
307 cc::NamespaceToken token,
308 cc::Task::Vector* completed_tasks) {
309 DCHECK(token.IsValid());
310 work_queue_.CollectCompletedTasks(token, completed_tasks);
311}
312
ericrk7795c7002016-01-21 22:49:18313bool RasterWorkerPool::RunTaskWithLockAcquired(
314 const std::vector<cc::TaskCategory>& categories) {
315 for (const auto& category : categories) {
skyostila1c7eb72016-02-12 17:14:08316 if (work_queue_.HasReadyToRunTasksForCategory(category)) {
ericrk7795c7002016-01-21 22:49:18317 RunTaskInCategoryWithLockAcquired(category);
318 return true;
319 }
320 }
321 return false;
322}
323
324void RasterWorkerPool::RunTaskInCategoryWithLockAcquired(
325 cc::TaskCategory category) {
ericrk4e3aa5a2015-12-01 03:53:56326 TRACE_EVENT0("toplevel", "TaskGraphRunner::RunTask");
327
328 lock_.AssertAcquired();
329
ericrk5a1188c62015-12-18 22:04:04330 auto prioritized_task = work_queue_.GetNextTaskToRun(category);
ericrk4e3aa5a2015-12-01 03:53:56331 cc::Task* task = prioritized_task.task;
332
ericrk4e3aa5a2015-12-01 03:53:56333 // Call WillRun() before releasing |lock_| and running task.
334 task->WillRun();
335
336 {
337 base::AutoUnlock unlock(lock_);
338
339 task->RunOnWorkerThread();
340 }
341
342 // This will mark task as finished running.
343 task->DidRun();
344
345 work_queue_.CompleteTask(prioritized_task);
346
skyostila1c7eb72016-02-12 17:14:08347 // We may have just dequeued more tasks, wake up the other worker threads.
348 if (work_queue_.HasReadyToRunTasks())
349 has_ready_to_run_tasks_cv_.Broadcast();
350
ericrke3e5b6f2015-12-02 00:00:37351 // If namespace has finished running all tasks, wake up origin threads.
ericrk4e3aa5a2015-12-01 03:53:56352 if (work_queue_.HasFinishedRunningTasksInNamespace(
353 prioritized_task.task_namespace))
skyostila1c7eb72016-02-12 17:14:08354 has_namespaces_with_finished_running_tasks_cv_.Broadcast();
ericrk4e3aa5a2015-12-01 03:53:56355}
356
dcastagna4517a182015-08-05 19:51:03357RasterWorkerPool::ClosureTask::ClosureTask(const base::Closure& closure)
358 : closure_(closure) {}
359
360// Overridden from cc::Task:
361void RasterWorkerPool::ClosureTask::RunOnWorkerThread() {
362 closure_.Run();
363 closure_.Reset();
ericrk4e3aa5a2015-12-01 03:53:56364}
dcastagna4517a182015-08-05 19:51:03365
366RasterWorkerPool::ClosureTask::~ClosureTask() {}
367
368} // namespace content