Commit 7795c700 authored by ericrk's avatar ericrk Committed by Commit bot

Add category handling to RasterWorkerPool

This change causes RasterWorkerPool to handle task
categories. To do this RasterWorkerPool assigns
specific task categories to each of its threads.

As I've been having trouble showing a clear win/loss
for using a single thread for background tasks, this
is behind a flag
"--use-single-thread-for-background-raster-tasks",
allowing us to test this more.

BUG=564260
CQ_INCLUDE_TRYBOTS=tryserver.blink:linux_blink_rel
CQ_EXTRA_TRYBOTS=tryserver.chromium.perf:linux_perf_bisect;tryserver.chromium.perf:mac_10_10_perf_bisect;tryserver.chromium.perf:win_perf_bisect

Review URL: https://codereview.chromium.org/1576133002

Cr-Commit-Position: refs/heads/master@{#370812}
parent e77ab9d1
...@@ -4,16 +4,39 @@ ...@@ -4,16 +4,39 @@
#include "content/renderer/raster_worker_pool.h" #include "content/renderer/raster_worker_pool.h"
#include <stddef.h> #include <string>
#include <stdint.h>
#include <utility> #include <utility>
#include <vector>
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/threading/thread_restrictions.h" #include "base/threading/thread_restrictions.h"
#include "base/trace_event/trace_event.h" #include "base/trace_event/trace_event.h"
#include "cc/base/math_util.h"
#include "cc/raster/task_category.h"
namespace content { namespace content {
namespace {
// A thread which forwards to RasterWorkerPool::Run with the runnable
// categories.
class RasterWorkerPoolThread : public base::SimpleThread {
public:
explicit RasterWorkerPoolThread(const std::string& name_prefix,
const Options& options,
RasterWorkerPool* pool,
std::vector<cc::TaskCategory> categories)
: SimpleThread(name_prefix, options),
pool_(pool),
categories_(categories) {}
void Run() override { pool_->Run(categories_); }
private:
RasterWorkerPool* const pool_;
const std::vector<cc::TaskCategory> categories_;
};
} // namespace
// A sequenced task runner which posts tasks to a RasterWorkerPool. // A sequenced task runner which posts tasks to a RasterWorkerPool.
class RasterWorkerPool::RasterWorkerPoolSequencedTaskRunner class RasterWorkerPool::RasterWorkerPoolSequencedTaskRunner
...@@ -52,7 +75,10 @@ class RasterWorkerPool::RasterWorkerPoolSequencedTaskRunner ...@@ -52,7 +75,10 @@ class RasterWorkerPool::RasterWorkerPoolSequencedTaskRunner
if (!graph_.nodes.empty()) if (!graph_.nodes.empty())
dependencies = 1; dependencies = 1;
cc::TaskGraph::Node node(graph_task.get(), 0u /* category */, // Treat any tasks that are enqueued through the SequencedTaskRunner as
// FOREGROUND priority. We don't have enough information to know the
// actual priority of such tasks, so we run them as soon as possible.
cc::TaskGraph::Node node(graph_task.get(), cc::TASK_CATEGORY_FOREGROUND,
0u /* priority */, dependencies); 0u /* priority */, dependencies);
if (dependencies) { if (dependencies) {
graph_.edges.push_back( graph_.edges.push_back(
...@@ -99,12 +125,27 @@ void RasterWorkerPool::Start( ...@@ -99,12 +125,27 @@ void RasterWorkerPool::Start(
const base::SimpleThread::Options& thread_options) { const base::SimpleThread::Options& thread_options) {
DCHECK(threads_.empty()); DCHECK(threads_.empty());
while (threads_.size() < static_cast<size_t>(num_threads)) { while (threads_.size() < static_cast<size_t>(num_threads)) {
scoped_ptr<base::DelegateSimpleThread> thread( // Determine the categories that each thread can run.
new base::DelegateSimpleThread( std::vector<cc::TaskCategory> task_categories;
this, base::StringPrintf("CompositorTileWorker%u",
static_cast<unsigned>(threads_.size() + 1)) // The first thread can run nonconcurrent tasks.
.c_str(), if (threads_.size() == 0) {
thread_options)); task_categories.push_back(cc::TASK_CATEGORY_NONCONCURRENT_FOREGROUND);
}
// All threads can run foreground tasks.
task_categories.push_back(cc::TASK_CATEGORY_FOREGROUND);
// The last thread can run background tasks.
if (threads_.size() == (static_cast<size_t>(num_threads) - 1)) {
task_categories.push_back(cc::TASK_CATEGORY_BACKGROUND);
}
scoped_ptr<base::SimpleThread> thread(new RasterWorkerPoolThread(
base::StringPrintf("CompositorTileWorker%u",
static_cast<unsigned>(threads_.size() + 1))
.c_str(),
thread_options, this, task_categories));
thread->Start(); thread->Start();
threads_.push_back(std::move(thread)); threads_.push_back(std::move(thread));
} }
...@@ -153,10 +194,13 @@ bool RasterWorkerPool::PostDelayedTask( ...@@ -153,10 +194,13 @@ bool RasterWorkerPool::PostDelayedTask(
tasks_.push_back(make_scoped_refptr(new ClosureTask(task))); tasks_.push_back(make_scoped_refptr(new ClosureTask(task)));
graph_.Reset(); graph_.Reset();
for (const auto& graph_task : tasks_) for (const auto& graph_task : tasks_) {
// Delayed tasks are assigned FOREGROUND category, ensuring that they run as
// soon as possible once their delay has expired.
graph_.nodes.push_back( graph_.nodes.push_back(
cc::TaskGraph::Node(graph_task.get(), 0u /* category */, cc::TaskGraph::Node(graph_task.get(), cc::TASK_CATEGORY_FOREGROUND,
0u /* priority */, 0u /* dependencies */)); 0u /* priority */, 0u /* dependencies */));
}
ScheduleTasksWithLockAcquired(namespace_token_, &graph_); ScheduleTasksWithLockAcquired(namespace_token_, &graph_);
completed_tasks_.clear(); completed_tasks_.clear();
...@@ -167,12 +211,11 @@ bool RasterWorkerPool::RunsTasksOnCurrentThread() const { ...@@ -167,12 +211,11 @@ bool RasterWorkerPool::RunsTasksOnCurrentThread() const {
return true; return true;
} }
// Overridden from base::DelegateSimpleThread::Delegate: void RasterWorkerPool::Run(const std::vector<cc::TaskCategory>& categories) {
void RasterWorkerPool::Run() {
base::AutoLock lock(lock_); base::AutoLock lock(lock_);
while (true) { while (true) {
if (!RunTaskWithLockAcquired()) { if (!RunTaskWithLockAcquired(categories)) {
// Exit when shutdown is set and no more tasks are pending. // Exit when shutdown is set and no more tasks are pending.
if (shutdown_) if (shutdown_)
break; break;
...@@ -222,9 +265,9 @@ void RasterWorkerPool::ScheduleTasksWithLockAcquired(cc::NamespaceToken token, ...@@ -222,9 +265,9 @@ void RasterWorkerPool::ScheduleTasksWithLockAcquired(cc::NamespaceToken token,
work_queue_.ScheduleTasks(token, graph); work_queue_.ScheduleTasks(token, graph);
// If there is more work available, wake up worker thread. // If there is more work available, wake up the other worker threads.
if (work_queue_.HasReadyToRunTasks()) if (work_queue_.HasReadyToRunTasks())
has_ready_to_run_tasks_cv_.Signal(); has_ready_to_run_tasks_cv_.Broadcast();
} }
void RasterWorkerPool::WaitForTasksToFinishRunning(cc::NamespaceToken token) { void RasterWorkerPool::WaitForTasksToFinishRunning(cc::NamespaceToken token) {
...@@ -264,34 +307,26 @@ void RasterWorkerPool::CollectCompletedTasksWithLockAcquired( ...@@ -264,34 +307,26 @@ void RasterWorkerPool::CollectCompletedTasksWithLockAcquired(
work_queue_.CollectCompletedTasks(token, completed_tasks); work_queue_.CollectCompletedTasks(token, completed_tasks);
} }
bool RasterWorkerPool::RunTaskWithLockAcquired() { bool RasterWorkerPool::RunTaskWithLockAcquired(
const std::vector<cc::TaskCategory>& categories) {
for (const auto& category : categories) {
if (work_queue_.HasReadyToRunTasksForCategory(category)) {
RunTaskInCategoryWithLockAcquired(category);
return true;
}
}
return false;
}
void RasterWorkerPool::RunTaskInCategoryWithLockAcquired(
cc::TaskCategory category) {
TRACE_EVENT0("toplevel", "TaskGraphRunner::RunTask"); TRACE_EVENT0("toplevel", "TaskGraphRunner::RunTask");
lock_.AssertAcquired(); lock_.AssertAcquired();
// Find the first category with any tasks to run. This task graph runner
// treats categories as an additional priority.
// TODO(ericrk): Add more category/thread logic.
const auto& ready_to_run_namespaces = work_queue_.ready_to_run_namespaces();
auto found = std::find_if(
ready_to_run_namespaces.cbegin(), ready_to_run_namespaces.cend(),
[](const std::pair<uint16_t,
cc::TaskGraphWorkQueue::TaskNamespace::Vector>& pair) {
return !pair.second.empty();
});
if (found == ready_to_run_namespaces.cend()) {
return false;
}
const uint16_t category = found->first;
auto prioritized_task = work_queue_.GetNextTaskToRun(category); auto prioritized_task = work_queue_.GetNextTaskToRun(category);
cc::Task* task = prioritized_task.task; cc::Task* task = prioritized_task.task;
// There may be more work available, so wake up another worker thread.
if (work_queue_.HasReadyToRunTasks())
has_ready_to_run_tasks_cv_.Signal();
// Call WillRun() before releasing |lock_| and running task. // Call WillRun() before releasing |lock_| and running task.
task->WillRun(); task->WillRun();
...@@ -306,12 +341,14 @@ bool RasterWorkerPool::RunTaskWithLockAcquired() { ...@@ -306,12 +341,14 @@ bool RasterWorkerPool::RunTaskWithLockAcquired() {
work_queue_.CompleteTask(prioritized_task); work_queue_.CompleteTask(prioritized_task);
// We may have just dequeued more tasks, wake up the other worker threads.
if (work_queue_.HasReadyToRunTasks())
has_ready_to_run_tasks_cv_.Broadcast();
// If namespace has finished running all tasks, wake up origin threads. // If namespace has finished running all tasks, wake up origin threads.
if (work_queue_.HasFinishedRunningTasksInNamespace( if (work_queue_.HasFinishedRunningTasksInNamespace(
prioritized_task.task_namespace)) prioritized_task.task_namespace))
has_namespaces_with_finished_running_tasks_cv_.Broadcast(); has_namespaces_with_finished_running_tasks_cv_.Broadcast();
return true;
} }
RasterWorkerPool::ClosureTask::ClosureTask(const base::Closure& closure) RasterWorkerPool::ClosureTask::ClosureTask(const base::Closure& closure)
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/synchronization/condition_variable.h" #include "base/synchronization/condition_variable.h"
#include "base/task_runner.h" #include "base/task_runner.h"
#include "base/threading/simple_thread.h" #include "base/threading/simple_thread.h"
#include "cc/raster/task_category.h"
#include "cc/raster/task_graph_runner.h" #include "cc/raster/task_graph_runner.h"
#include "cc/raster/task_graph_work_queue.h" #include "cc/raster/task_graph_work_queue.h"
#include "content/common/content_export.h" #include "content/common/content_export.h"
...@@ -27,10 +28,8 @@ namespace content { ...@@ -27,10 +28,8 @@ namespace content {
// parallel with other instances of sequenced task runners. // parallel with other instances of sequenced task runners.
// It's also possible to get the underlying TaskGraphRunner to schedule a graph // It's also possible to get the underlying TaskGraphRunner to schedule a graph
// of tasks with their dependencies. // of tasks with their dependencies.
class CONTENT_EXPORT RasterWorkerPool class CONTENT_EXPORT RasterWorkerPool : public base::TaskRunner,
: public base::TaskRunner, public cc::TaskGraphRunner {
public cc::TaskGraphRunner,
public base::DelegateSimpleThread::Delegate {
public: public:
RasterWorkerPool(); RasterWorkerPool();
...@@ -47,8 +46,9 @@ class CONTENT_EXPORT RasterWorkerPool ...@@ -47,8 +46,9 @@ class CONTENT_EXPORT RasterWorkerPool
void CollectCompletedTasks(cc::NamespaceToken token, void CollectCompletedTasks(cc::NamespaceToken token,
cc::Task::Vector* completed_tasks) override; cc::Task::Vector* completed_tasks) override;
// Overridden from base::DelegateSimpleThread::Delegate: // Runs a task from one of the provided categories. Categories listed first
void Run() override; // have higher priority.
void Run(const std::vector<cc::TaskCategory>& categories);
void FlushForTesting(); void FlushForTesting();
...@@ -75,9 +75,13 @@ class CONTENT_EXPORT RasterWorkerPool ...@@ -75,9 +75,13 @@ class CONTENT_EXPORT RasterWorkerPool
class RasterWorkerPoolSequencedTaskRunner; class RasterWorkerPoolSequencedTaskRunner;
friend class RasterWorkerPoolSequencedTaskRunner; friend class RasterWorkerPoolSequencedTaskRunner;
// Run next task. Caller must acquire |lock_| prior to calling this function. // Runs a task from one of the provided categories. Categories listed first
// Returns true if there was a task available to run. // have higher priority. Returns false if there were no tasks to run.
bool RunTaskWithLockAcquired(); bool RunTaskWithLockAcquired(const std::vector<cc::TaskCategory>& categories);
// Run next task for the given category. Caller must acquire |lock_| prior to
// calling this function and make sure at least one task is ready to run.
void RunTaskInCategoryWithLockAcquired(cc::TaskCategory category);
// Simple Task for the TaskGraphRunner that wraps a closure. // Simple Task for the TaskGraphRunner that wraps a closure.
// This class is used to schedule TaskRunner tasks on the // This class is used to schedule TaskRunner tasks on the
...@@ -104,7 +108,7 @@ class CONTENT_EXPORT RasterWorkerPool ...@@ -104,7 +108,7 @@ class CONTENT_EXPORT RasterWorkerPool
cc::Task::Vector* completed_tasks); cc::Task::Vector* completed_tasks);
// The actual threads where work is done. // The actual threads where work is done.
ScopedVector<base::DelegateSimpleThread> threads_; std::vector<scoped_ptr<base::SimpleThread>> threads_;
// Lock to exclusively access all the following members that are used to // Lock to exclusively access all the following members that are used to
// implement the TaskRunner and TaskGraphRunner interfaces. // implement the TaskRunner and TaskGraphRunner interfaces.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment