Skip to content

Commit

Permalink
TaskGraphRunner Group support
Browse files Browse the repository at this point in the history
Adds a group to TaskGraphRunner, this can be used by an
implementation along with priority in order to decide how to execute
tasks.

This is a prerequisite patch for thread affinity changes which are
coming in a follow-up.

This patch causes a moderate (~15%) regression in cc_perftests for TaskGraphRunner.

The main regressions I'm seeing are:

In ScheduleTasks, we're seeing an additional 3% time spent in operator[] for the two new maps vs ToT.

We're also seeing an additional 5.5% of time spent in test code which builds the task graph.

Other regressions are less clear, but probably have to do with the additional cost of ScheduleTasks in the function body itself (inlined looping).

BUG=
CQ_INCLUDE_TRYBOTS=tryserver.blink:linux_blink_rel

Committed: https://crrev.com/05ca4bc9df381e6345f9cf7ee29cdfa075be30c4
Cr-Commit-Position: refs/heads/master@{#365140}

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

Cr-Commit-Position: refs/heads/master@{#365646}
  • Loading branch information
ericrk authored and Commit bot committed Dec 16, 2015
1 parent b8207ad commit 3b4338f
Show file tree
Hide file tree
Showing 16 changed files with 342 additions and 127 deletions.
1 change: 1 addition & 0 deletions cc/cc.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,7 @@
'raster/single_thread_task_graph_runner.h',
'raster/synchronous_task_graph_runner.cc',
'raster/synchronous_task_graph_runner.h',
'raster/task_category.h',
'raster/task_graph_runner.cc',
'raster/task_graph_runner.h',
'raster/task_graph_work_queue.cc',
Expand Down
23 changes: 18 additions & 5 deletions cc/raster/single_thread_task_graph_runner.cc
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ void SingleThreadTaskGraphRunner::Run() {
base::AutoLock lock(lock_);

while (true) {
if (!work_queue_.HasReadyToRunTasks()) {
if (!RunTaskWithLockAcquired()) {
// Exit when shutdown is set and no more tasks are pending.
if (shutdown_)
break;
Expand All @@ -121,18 +121,29 @@ void SingleThreadTaskGraphRunner::Run() {
has_ready_to_run_tasks_cv_.Wait();
continue;
}

RunTaskWithLockAcquired();
}
}

void SingleThreadTaskGraphRunner::RunTaskWithLockAcquired() {
bool SingleThreadTaskGraphRunner::RunTaskWithLockAcquired() {
TRACE_EVENT0("toplevel",
"SingleThreadTaskGraphRunner::RunTaskWithLockAcquired");

lock_.AssertAcquired();

auto prioritized_task = work_queue_.GetNextTaskToRun();
// Find the first category with any tasks to run. This task graph runner
// treats categories as an additional priority.
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, 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);
Task* task = prioritized_task.task;

// Call WillRun() before releasing |lock_| and running task.
Expand All @@ -152,6 +163,8 @@ void SingleThreadTaskGraphRunner::RunTaskWithLockAcquired() {
if (work_queue_.HasFinishedRunningTasksInNamespace(
prioritized_task.task_namespace))
has_namespaces_with_finished_running_tasks_cv_.Signal();

return true;
}

} // namespace cc
3 changes: 2 additions & 1 deletion cc/raster/single_thread_task_graph_runner.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ class CC_EXPORT SingleThreadTaskGraphRunner
void Shutdown();

private:
void RunTaskWithLockAcquired();
// Returns true if there was a task to run.
bool RunTaskWithLockAcquired();

scoped_ptr<base::SimpleThread> thread_;

Expand Down
32 changes: 25 additions & 7 deletions cc/raster/synchronous_task_graph_runner.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

#include "cc/raster/synchronous_task_graph_runner.h"

#include <algorithm>
#include <utility>

#include "base/threading/simple_thread.h"
#include "base/threading/thread_restrictions.h"
#include "base/trace_event/trace_event.h"
Expand Down Expand Up @@ -41,9 +44,9 @@ void SynchronousTaskGraphRunner::WaitForTasksToFinishRunning(
if (!task_namespace)
return;

while (
!TaskGraphWorkQueue::HasFinishedRunningTasksInNamespace(task_namespace)) {
RunTask();
while (!work_queue_.HasFinishedRunningTasksInNamespace(task_namespace)) {
bool succeeded = RunTask();
DCHECK(succeeded);
}
}

Expand All @@ -57,21 +60,36 @@ void SynchronousTaskGraphRunner::CollectCompletedTasks(
}

void SynchronousTaskGraphRunner::RunUntilIdle() {
while (work_queue_.HasReadyToRunTasks())
RunTask();
while (RunTask()) {
}
}

void SynchronousTaskGraphRunner::RunTask() {
bool SynchronousTaskGraphRunner::RunTask() {
TRACE_EVENT0("toplevel", "SynchronousTaskGraphRunner::RunTask");

auto prioritized_task = work_queue_.GetNextTaskToRun();
// Find the first category with any tasks to run. This task graph runner
// treats categories as an additional priority.
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, 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);

Task* task = prioritized_task.task;
task->WillRun();
task->RunOnWorkerThread();
task->DidRun();

work_queue_.CompleteTask(prioritized_task);

return true;
}

} // namespace cc
3 changes: 2 additions & 1 deletion cc/raster/synchronous_task_graph_runner.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ class CC_EXPORT SynchronousTaskGraphRunner : public TaskGraphRunner {
void RunUntilIdle();

private:
void RunTask();
// Returns true if there was a task to run.
bool RunTask();

// Stores the actual tasks to be run, sorted by priority.
TaskGraphWorkQueue work_queue_;
Expand Down
24 changes: 17 additions & 7 deletions cc/raster/task_graph_runner.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,19 +46,29 @@ class CC_EXPORT Task : public base::RefCountedThreadSafe<Task> {

// A task dependency graph describes the order in which to execute a set
// of tasks. Dependencies are represented as edges. Each node is assigned
// a priority and a run count that matches the number of dependencies.
// Priority range from 0 (most favorable scheduling) to UINT_MAX
// (least favorable).
// a category, a priority and a run count that matches the number of
// dependencies. Priority range from 0 (most favorable scheduling) to UINT16_MAX
// (least favorable). Categories range from 0 to UINT16_MAX. It is up to the
// implementation and its consumer to determine the meaning (if any) of a
// category. A TaskGraphRunner implementation may chose to prioritize certain
// categories over others, regardless of the individual priorities of tasks.
struct CC_EXPORT TaskGraph {
struct Node {
typedef std::vector<Node> Vector;

Node(Task* task, size_t priority, size_t dependencies)
: task(task), priority(priority), dependencies(dependencies) {}
Node(Task* task,
uint16_t category,
uint16_t priority,
uint32_t dependencies)
: task(task),
category(category),
priority(priority),
dependencies(dependencies) {}

Task* task;
size_t priority;
size_t dependencies;
uint16_t category;
uint16_t priority;
uint32_t dependencies;
};

struct Edge {
Expand Down
10 changes: 5 additions & 5 deletions cc/raster/task_graph_runner_perftest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -230,13 +230,13 @@ class TaskGraphRunnerPerfTest : public testing::Test {
for (PerfTaskImpl::Vector::const_iterator it = leaf_tasks.begin();
it != leaf_tasks.end();
++it) {
graph->nodes.push_back(TaskGraph::Node(it->get(), 0u, 0u));
graph->nodes.push_back(TaskGraph::Node(it->get(), 0u, 0u, 0u));
}

for (PerfTaskImpl::Vector::const_iterator it = tasks.begin();
it != tasks.end();
++it) {
graph->nodes.push_back(TaskGraph::Node(it->get(), 0u, leaf_tasks.size()));
it != tasks.end(); ++it) {
graph->nodes.push_back(
TaskGraph::Node(it->get(), 0u, 0u, leaf_tasks.size()));

for (PerfTaskImpl::Vector::const_iterator leaf_it = leaf_tasks.begin();
leaf_it != leaf_tasks.end();
Expand All @@ -255,7 +255,7 @@ class TaskGraphRunnerPerfTest : public testing::Test {
for (PerfTaskImpl::Vector::const_iterator it = top_level_tasks.begin();
it != top_level_tasks.end();
++it) {
graph->nodes.push_back(TaskGraph::Node(it->get(), 0u, tasks.size()));
graph->nodes.push_back(TaskGraph::Node(it->get(), 0u, 0u, tasks.size()));
}
}

Expand Down
Loading

0 comments on commit 3b4338f

Please sign in to comment.