Commit 362c9d06 authored by reveman@chromium.org's avatar reveman@chromium.org

Re-land: cc: Cancel and re-prioritize worker pool tasks.

This adds a task graph interface to the worker pool and
implements a simple queue instance of this interface for
use by the tile manager.

The task graph interface can be used describe more
complicated task dependencies in the future and
provides the immediate benefit of seamlessly being
able to cancel and re-prioritize tasks.

BUG=178974,244642
TEST=cc_unittests --gtest_filter=WorkerPoolTest.Dependencies

Review URL: https://chromiumcodereview.appspot.com/14689004

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@203041 0039d316-1c4b-4281-b951-d872f2087c98
parent 3d82df66
...@@ -31,7 +31,7 @@ class ScopedPtrHashMap { ...@@ -31,7 +31,7 @@ class ScopedPtrHashMap {
~ScopedPtrHashMap() { clear(); } ~ScopedPtrHashMap() { clear(); }
void swap(ScopedPtrHashMap<Key, Value*>& other) { void swap(ScopedPtrHashMap<Key, Value>& other) {
data_.swap(other.data_); data_.swap(other.data_);
} }
......
This diff is collapsed.
...@@ -5,31 +5,52 @@ ...@@ -5,31 +5,52 @@
#ifndef CC_BASE_WORKER_POOL_H_ #ifndef CC_BASE_WORKER_POOL_H_
#define CC_BASE_WORKER_POOL_H_ #define CC_BASE_WORKER_POOL_H_
#include <deque>
#include <string> #include <string>
#include <vector>
#include "base/cancelable_callback.h" #include "base/cancelable_callback.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/message_loop.h" #include "base/message_loop.h"
#include "cc/base/cc_export.h" #include "cc/base/cc_export.h"
#include "cc/base/scoped_ptr_deque.h"
namespace cc { namespace cc {
namespace internal { namespace internal {
class WorkerPoolTask { class CC_EXPORT WorkerPoolTask
: public base::RefCountedThreadSafe<WorkerPoolTask> {
public: public:
virtual ~WorkerPoolTask(); typedef std::vector<scoped_refptr<WorkerPoolTask> > TaskVector;
virtual void RunOnThread(unsigned thread_index) = 0; virtual void RunOnThread(unsigned thread_index) = 0;
virtual void DispatchCompletionCallback() = 0;
void DidSchedule();
void WillRun();
void DidRun();
void DidComplete(); void DidComplete();
bool IsReadyToRun() const;
bool HasFinishedRunning() const;
bool HasCompleted() const;
TaskVector& dependencies() { return dependencies_; }
protected: protected:
explicit WorkerPoolTask(const base::Closure& reply); friend class base::RefCountedThreadSafe<WorkerPoolTask>;
WorkerPoolTask();
explicit WorkerPoolTask(TaskVector* dependencies);
virtual ~WorkerPoolTask();
const base::Closure reply_; private:
bool did_schedule_;
bool did_run_;
bool did_complete_;
TaskVector dependencies_;
}; };
} // namespace internal } // namespace internal
...@@ -42,67 +63,50 @@ class CC_EXPORT WorkerPoolClient { ...@@ -42,67 +63,50 @@ class CC_EXPORT WorkerPoolClient {
virtual ~WorkerPoolClient() {} virtual ~WorkerPoolClient() {}
}; };
// A worker thread pool that runs rendering tasks and guarantees completion // A worker thread pool that runs tasks provided by task graph and
// of all pending tasks at shutdown. // guarantees completion of all pending tasks at shutdown.
class CC_EXPORT WorkerPool { class CC_EXPORT WorkerPool {
public: public:
typedef base::Callback<void()> Callback;
virtual ~WorkerPool(); virtual ~WorkerPool();
static scoped_ptr<WorkerPool> Create(
size_t num_threads,
base::TimeDelta check_for_completed_tasks_delay,
const std::string& thread_name_prefix) {
return make_scoped_ptr(new WorkerPool(num_threads,
check_for_completed_tasks_delay,
thread_name_prefix));
}
// Tells the worker pool to shutdown and returns once all pending tasks have // Tells the worker pool to shutdown and returns once all pending tasks have
// completed. // completed.
void Shutdown(); virtual void Shutdown();
// Posts |task| to worker pool. On completion, |reply|
// is posted to the thread that called PostTaskAndReply().
void PostTaskAndReply(const Callback& task, const base::Closure& reply);
// Set a new client. // Set a new client.
void SetClient(WorkerPoolClient* client) { void SetClient(WorkerPoolClient* client) {
client_ = client; client_ = client;
} }
// Force a check for completed tasks.
void CheckForCompletedTasks();
protected: protected:
WorkerPool(size_t num_threads, WorkerPool(size_t num_threads,
base::TimeDelta check_for_completed_tasks_delay, base::TimeDelta check_for_completed_tasks_delay,
const std::string& thread_name_prefix); const std::string& thread_name_prefix);
void PostTask(scoped_ptr<internal::WorkerPoolTask> task); void ScheduleTasks(internal::WorkerPoolTask* root);
private: private:
class Inner; class Inner;
friend class Inner; friend class Inner;
void OnTaskCompleted(); typedef std::deque<scoped_refptr<internal::WorkerPoolTask> > TaskDeque;
void OnIdle();
void OnIdle(TaskDeque* completed_tasks);
void ScheduleCheckForCompletedTasks(); void ScheduleCheckForCompletedTasks();
void CheckForCompletedTasks(); void DispatchCompletionCallbacks(TaskDeque* completed_tasks);
void DispatchCompletionCallbacks();
WorkerPoolClient* client_; WorkerPoolClient* client_;
scoped_refptr<base::MessageLoopProxy> origin_loop_; scoped_refptr<base::MessageLoopProxy> origin_loop_;
base::WeakPtrFactory<WorkerPool> weak_ptr_factory_; base::CancelableClosure check_for_completed_tasks_callback_;
base::TimeDelta check_for_completed_tasks_delay_; base::TimeDelta check_for_completed_tasks_delay_;
bool check_for_completed_tasks_pending_; bool check_for_completed_tasks_pending_;
bool in_dispatch_completion_callbacks_;
// Holds all completed tasks for which we have not yet dispatched
// reply callbacks.
ScopedPtrDeque<internal::WorkerPoolTask> completed_tasks_;
// Hide the gory details of the worker pool in |inner_|. // Hide the gory details of the worker pool in |inner_|.
const scoped_ptr<Inner> inner_; const scoped_ptr<Inner> inner_;
DISALLOW_COPY_AND_ASSIGN(WorkerPool);
}; };
} // namespace cc } // namespace cc
......
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "cc/base/worker_pool.h"
#include "base/time.h"
#include "cc/base/completion_event.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace cc {
namespace {
static const int kTimeLimitMillis = 2000;
static const int kWarmupRuns = 5;
static const int kTimeCheckInterval = 10;
class PerfTaskImpl : public internal::WorkerPoolTask {
public:
explicit PerfTaskImpl(internal::WorkerPoolTask::TaskVector* dependencies)
: internal::WorkerPoolTask(dependencies) {}
// Overridden from internal::WorkerPoolTask:
virtual void RunOnThread(unsigned thread_index) OVERRIDE {}
virtual void DispatchCompletionCallback() OVERRIDE {}
private:
virtual ~PerfTaskImpl() {}
};
class PerfControlTaskImpl : public internal::WorkerPoolTask {
public:
explicit PerfControlTaskImpl(
internal::WorkerPoolTask::TaskVector* dependencies)
: internal::WorkerPoolTask(dependencies),
did_start_(new CompletionEvent),
can_finish_(new CompletionEvent) {}
// Overridden from internal::WorkerPoolTask:
virtual void RunOnThread(unsigned thread_index) OVERRIDE {
did_start_->Signal();
can_finish_->Wait();
}
virtual void DispatchCompletionCallback() OVERRIDE {}
void WaitForTaskToStartRunning() {
did_start_->Wait();
}
void AllowTaskToFinish() {
can_finish_->Signal();
}
private:
virtual ~PerfControlTaskImpl() {}
scoped_ptr<CompletionEvent> did_start_;
scoped_ptr<CompletionEvent> can_finish_;
};
class PerfWorkerPool : public WorkerPool {
public:
PerfWorkerPool() : WorkerPool(1, base::TimeDelta::FromDays(1024), "test") {}
virtual ~PerfWorkerPool() {}
static scoped_ptr<PerfWorkerPool> Create() {
return make_scoped_ptr(new PerfWorkerPool);
}
void ScheduleTasks(internal::WorkerPoolTask* root) {
WorkerPool::ScheduleTasks(root);
}
};
class WorkerPoolPerfTest : public testing::Test,
public WorkerPoolClient {
public:
WorkerPoolPerfTest() : num_runs_(0) {}
// Overridden from testing::Test:
virtual void SetUp() OVERRIDE {
worker_pool_ = PerfWorkerPool::Create();
worker_pool_->SetClient(this);
}
virtual void TearDown() OVERRIDE {
worker_pool_->Shutdown();
}
// Overridden from WorkerPoolClient:
virtual void DidFinishDispatchingWorkerPoolCompletionCallbacks() OVERRIDE {}
void EndTest() {
elapsed_ = base::TimeTicks::HighResNow() - start_time_;
}
void AfterTest(const std::string test_name) {
// Format matches chrome/test/perf/perf_test.h:PrintResult
printf("*RESULT %s: %.2f runs/s\n",
test_name.c_str(),
num_runs_ / elapsed_.InSecondsF());
}
void BuildTaskGraph(internal::WorkerPoolTask::TaskVector* dependencies,
unsigned current_depth,
unsigned max_depth,
unsigned num_children_per_node) {
internal::WorkerPoolTask::TaskVector children;
if (current_depth < max_depth) {
for (unsigned i = 0; i < num_children_per_node; ++i) {
BuildTaskGraph(&children,
current_depth + 1,
max_depth,
num_children_per_node);
}
} else if (leaf_task_) {
children.push_back(leaf_task_);
}
dependencies->push_back(make_scoped_refptr(new PerfTaskImpl(&children)));
}
bool DidRun() {
++num_runs_;
if (num_runs_ == kWarmupRuns)
start_time_ = base::TimeTicks::HighResNow();
if (!start_time_.is_null() && (num_runs_ % kTimeCheckInterval) == 0) {
base::TimeDelta elapsed = base::TimeTicks::HighResNow() - start_time_;
if (elapsed >= base::TimeDelta::FromMilliseconds(kTimeLimitMillis)) {
elapsed_ = elapsed;
return false;
}
}
return true;
}
void RunBuildTaskGraphTest(const std::string test_name,
unsigned max_depth,
unsigned num_children_per_node) {
start_time_ = base::TimeTicks();
num_runs_ = 0;
do {
internal::WorkerPoolTask::TaskVector children;
BuildTaskGraph(&children, 0, max_depth, num_children_per_node);
} while (DidRun());
AfterTest(test_name);
}
void RunScheduleTasksTest(const std::string test_name,
unsigned max_depth,
unsigned num_children_per_node) {
start_time_ = base::TimeTicks();
num_runs_ = 0;
do {
internal::WorkerPoolTask::TaskVector empty;
leaf_task_ = make_scoped_refptr(new PerfControlTaskImpl(&empty));
internal::WorkerPoolTask::TaskVector children;
BuildTaskGraph(&children, 0, max_depth, num_children_per_node);
scoped_refptr<PerfTaskImpl> root_task(
make_scoped_refptr(new PerfTaskImpl(&children)));
worker_pool_->ScheduleTasks(root_task);
leaf_task_->WaitForTaskToStartRunning();
worker_pool_->ScheduleTasks(NULL);
worker_pool_->CheckForCompletedTasks();
leaf_task_->AllowTaskToFinish();
} while (DidRun());
AfterTest(test_name);
}
void RunExecuteTasksTest(const std::string test_name,
unsigned max_depth,
unsigned num_children_per_node) {
start_time_ = base::TimeTicks();
num_runs_ = 0;
do {
internal::WorkerPoolTask::TaskVector children;
BuildTaskGraph(&children, 0, max_depth, num_children_per_node);
scoped_refptr<PerfControlTaskImpl> root_task(
make_scoped_refptr(new PerfControlTaskImpl(&children)));
worker_pool_->ScheduleTasks(root_task);
root_task->WaitForTaskToStartRunning();
root_task->AllowTaskToFinish();
worker_pool_->CheckForCompletedTasks();
} while (DidRun());
AfterTest(test_name);
}
protected:
scoped_ptr<PerfWorkerPool> worker_pool_;
scoped_refptr<PerfControlTaskImpl> leaf_task_;
base::TimeTicks start_time_;
base::TimeDelta elapsed_;
int num_runs_;
};
TEST_F(WorkerPoolPerfTest, BuildTaskGraph) {
RunBuildTaskGraphTest("build_task_graph_1_10", 1, 10);
RunBuildTaskGraphTest("build_task_graph_1_1000", 1, 1000);
RunBuildTaskGraphTest("build_task_graph_2_10", 2, 10);
RunBuildTaskGraphTest("build_task_graph_5_5", 5, 5);
RunBuildTaskGraphTest("build_task_graph_10_2", 10, 2);
RunBuildTaskGraphTest("build_task_graph_1000_1", 1000, 1);
RunBuildTaskGraphTest("build_task_graph_10_1", 10, 1);
}
TEST_F(WorkerPoolPerfTest, ScheduleTasks) {
RunScheduleTasksTest("schedule_tasks_1_10", 1, 10);
RunScheduleTasksTest("schedule_tasks_1_1000", 1, 1000);
RunScheduleTasksTest("schedule_tasks_2_10", 2, 10);
RunScheduleTasksTest("schedule_tasks_5_5", 5, 5);
RunScheduleTasksTest("schedule_tasks_10_2", 10, 2);
RunScheduleTasksTest("schedule_tasks_1000_1", 1000, 1);
RunScheduleTasksTest("schedule_tasks_10_1", 10, 1);
}
TEST_F(WorkerPoolPerfTest, ExecuteTasks) {
RunExecuteTasksTest("execute_tasks_1_10", 1, 10);
RunExecuteTasksTest("execute_tasks_1_1000", 1, 1000);
RunExecuteTasksTest("execute_tasks_2_10", 2, 10);
RunExecuteTasksTest("execute_tasks_5_5", 5, 5);
RunExecuteTasksTest("execute_tasks_10_2", 10, 2);
RunExecuteTasksTest("execute_tasks_1000_1", 1000, 1);
RunExecuteTasksTest("execute_tasks_10_1", 10, 1);
}
} // namespace
} // namespace cc
...@@ -4,27 +4,101 @@ ...@@ -4,27 +4,101 @@
#include "cc/base/worker_pool.h" #include "cc/base/worker_pool.h"
#include <vector>
#include "cc/base/completion_event.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
namespace cc { namespace cc {
namespace { namespace {
class WorkerPoolTest : public testing::Test, class FakeTaskImpl : public internal::WorkerPoolTask {
public WorkerPoolClient { public:
FakeTaskImpl(const base::Closure& callback,
const base::Closure& reply,
internal::WorkerPoolTask::TaskVector* dependencies)
: internal::WorkerPoolTask(dependencies),
callback_(callback),
reply_(reply) {
}
FakeTaskImpl(const base::Closure& callback, const base::Closure& reply)
: callback_(callback),
reply_(reply) {
}
// Overridden from internal::WorkerPoolTask:
virtual void RunOnThread(unsigned thread_index) OVERRIDE {
if (!callback_.is_null())
callback_.Run();
}
virtual void DispatchCompletionCallback() OVERRIDE {
if (!reply_.is_null())
reply_.Run();
}
private:
virtual ~FakeTaskImpl() {}
const base::Closure callback_;
const base::Closure reply_;
};
class FakeWorkerPool : public WorkerPool {
public: public:
WorkerPoolTest() FakeWorkerPool() : WorkerPool(1, base::TimeDelta::FromDays(1024), "test") {}
: run_task_count_(0), virtual ~FakeWorkerPool() {}
on_task_completed_count_(0),
finish_dispatching_completion_callbacks_count_(0) { static scoped_ptr<FakeWorkerPool> Create() {
return make_scoped_ptr(new FakeWorkerPool);
}
void ScheduleTasks(const base::Closure& callback,
const base::Closure& reply,
const base::Closure& dependency,
int count) {
scoped_refptr<FakeTaskImpl> dependency_task(
new FakeTaskImpl(dependency, base::Closure()));
internal::WorkerPoolTask::TaskVector tasks;
for (int i = 0; i < count; ++i) {
internal::WorkerPoolTask::TaskVector dependencies(1, dependency_task);
tasks.push_back(new FakeTaskImpl(callback, reply, &dependencies));
} }
virtual ~WorkerPoolTest() { scoped_refptr<FakeTaskImpl> completion_task(
new FakeTaskImpl(base::Bind(&FakeWorkerPool::OnTasksCompleted,
base::Unretained(this)),
base::Closure(),
&tasks));
scheduled_tasks_completion_.reset(new CompletionEvent);
WorkerPool::ScheduleTasks(completion_task);
} }
void WaitForTasksToComplete() {
DCHECK(scheduled_tasks_completion_);
scheduled_tasks_completion_->Wait();
}
private:
void OnTasksCompleted() {
DCHECK(scheduled_tasks_completion_);
scheduled_tasks_completion_->Signal();
}
scoped_ptr<CompletionEvent> scheduled_tasks_completion_;
};
class WorkerPoolTest : public testing::Test,
public WorkerPoolClient {
public:
WorkerPoolTest() : finish_dispatching_completion_callbacks_count_(0) {}
virtual ~WorkerPoolTest() {}
// Overridden from testing::Test:
virtual void SetUp() OVERRIDE { virtual void SetUp() OVERRIDE {
Reset(); Reset();
} }
virtual void TearDown() OVERRIDE { virtual void TearDown() OVERRIDE {
worker_pool_->Shutdown(); worker_pool_->Shutdown();
} }
...@@ -35,35 +109,34 @@ class WorkerPoolTest : public testing::Test, ...@@ -35,35 +109,34 @@ class WorkerPoolTest : public testing::Test,
} }
void Reset() { void Reset() {
worker_pool_ = WorkerPool::Create(1, worker_pool_ = FakeWorkerPool::Create();
base::TimeDelta::FromDays(1024),
"test");
worker_pool_->SetClient(this); worker_pool_->SetClient(this);
} }
void RunAllTasksAndReset() { void RunAllTasksAndReset() {
worker_pool_->WaitForTasksToComplete();
worker_pool_->Shutdown(); worker_pool_->Shutdown();
Reset(); Reset();
} }
WorkerPool* worker_pool() { FakeWorkerPool* worker_pool() {
return worker_pool_.get(); return worker_pool_.get();
} }
void RunTask() { void RunTask(unsigned id) {
++run_task_count_; run_task_ids_.push_back(id);
} }
void OnTaskCompleted() { void OnTaskCompleted(unsigned id) {
++on_task_completed_count_; on_task_completed_ids_.push_back(id);
} }
unsigned run_task_count() { const std::vector<unsigned>& run_task_ids() {
return run_task_count_; return run_task_ids_;
} }
unsigned on_task_completed_count() { const std::vector<unsigned>& on_task_completed_ids() {
return on_task_completed_count_; return on_task_completed_ids_;
} }
unsigned finish_dispatching_completion_callbacks_count() { unsigned finish_dispatching_completion_callbacks_count() {
...@@ -71,39 +144,72 @@ class WorkerPoolTest : public testing::Test, ...@@ -71,39 +144,72 @@ class WorkerPoolTest : public testing::Test,
} }
private: private:
scoped_ptr<WorkerPool> worker_pool_; scoped_ptr<FakeWorkerPool> worker_pool_;
unsigned run_task_count_; std::vector<unsigned> run_task_ids_;
unsigned on_task_completed_count_; std::vector<unsigned> on_task_completed_ids_;
unsigned finish_dispatching_completion_callbacks_count_; unsigned finish_dispatching_completion_callbacks_count_;
}; };
TEST_F(WorkerPoolTest, Basic) { TEST_F(WorkerPoolTest, Basic) {
EXPECT_EQ(0u, run_task_count()); EXPECT_EQ(0u, run_task_ids().size());
EXPECT_EQ(0u, on_task_completed_count()); EXPECT_EQ(0u, on_task_completed_ids().size());
EXPECT_EQ(0u, finish_dispatching_completion_callbacks_count()); EXPECT_EQ(0u, finish_dispatching_completion_callbacks_count());
worker_pool()->PostTaskAndReply( worker_pool()->ScheduleTasks(
base::Bind(&WorkerPoolTest::RunTask, base::Unretained(this)), base::Bind(&WorkerPoolTest::RunTask, base::Unretained(this), 0u),
base::Bind(&WorkerPoolTest::OnTaskCompleted, base::Unretained(this))); base::Bind(&WorkerPoolTest::OnTaskCompleted, base::Unretained(this), 0u),
base::Closure(),
1);
RunAllTasksAndReset(); RunAllTasksAndReset();
EXPECT_EQ(1u, run_task_count()); EXPECT_EQ(1u, run_task_ids().size());
EXPECT_EQ(1u, on_task_completed_count()); EXPECT_EQ(1u, on_task_completed_ids().size());
EXPECT_EQ(1u, finish_dispatching_completion_callbacks_count()); EXPECT_EQ(1u, finish_dispatching_completion_callbacks_count());
worker_pool()->PostTaskAndReply( worker_pool()->ScheduleTasks(
base::Bind(&WorkerPoolTest::RunTask, base::Unretained(this)), base::Bind(&WorkerPoolTest::RunTask, base::Unretained(this), 0u),
base::Bind(&WorkerPoolTest::OnTaskCompleted, base::Unretained(this))); base::Bind(&WorkerPoolTest::OnTaskCompleted, base::Unretained(this), 0u),
worker_pool()->PostTaskAndReply( base::Closure(),
base::Bind(&WorkerPoolTest::RunTask, base::Unretained(this)), 2);
base::Bind(&WorkerPoolTest::OnTaskCompleted, base::Unretained(this)));
RunAllTasksAndReset(); RunAllTasksAndReset();
EXPECT_EQ(3u, run_task_count()); EXPECT_EQ(3u, run_task_ids().size());
EXPECT_EQ(3u, on_task_completed_count()); EXPECT_EQ(3u, on_task_completed_ids().size());
EXPECT_EQ(2u, finish_dispatching_completion_callbacks_count()); EXPECT_EQ(2u, finish_dispatching_completion_callbacks_count());
} }
TEST_F(WorkerPoolTest, Dependencies) {
worker_pool()->ScheduleTasks(
base::Bind(&WorkerPoolTest::RunTask, base::Unretained(this), 1u),
base::Bind(&WorkerPoolTest::OnTaskCompleted, base::Unretained(this), 1u),
base::Bind(&WorkerPoolTest::RunTask, base::Unretained(this), 0u),
1);
RunAllTasksAndReset();
// Check if dependency ran before task.
ASSERT_EQ(2u, run_task_ids().size());
EXPECT_EQ(0u, run_task_ids()[0]);
EXPECT_EQ(1u, run_task_ids()[1]);
ASSERT_EQ(1u, on_task_completed_ids().size());
EXPECT_EQ(1u, on_task_completed_ids()[0]);
worker_pool()->ScheduleTasks(
base::Bind(&WorkerPoolTest::RunTask, base::Unretained(this), 1u),
base::Bind(&WorkerPoolTest::OnTaskCompleted, base::Unretained(this), 1u),
base::Bind(&WorkerPoolTest::RunTask, base::Unretained(this), 0u),
2);
RunAllTasksAndReset();
// Dependency should only run once.
ASSERT_EQ(5u, run_task_ids().size());
EXPECT_EQ(0u, run_task_ids()[2]);
EXPECT_EQ(1u, run_task_ids()[3]);
EXPECT_EQ(1u, run_task_ids()[4]);
ASSERT_EQ(3u, on_task_completed_ids().size());
EXPECT_EQ(1u, on_task_completed_ids()[1]);
EXPECT_EQ(1u, on_task_completed_ids()[2]);
}
} // namespace } // namespace
} // namespace cc } // namespace cc
...@@ -225,9 +225,10 @@ ...@@ -225,9 +225,10 @@
'cc_test_support', 'cc_test_support',
], ],
'sources': [ 'sources': [
'trees/layer_tree_host_perftest.cc', 'base/worker_pool_perftest.cc',
'test/run_all_unittests.cc',
'test/cc_test_suite.cc', 'test/cc_test_suite.cc',
'test/run_all_unittests.cc',
'trees/layer_tree_host_perftest.cc',
], ],
'include_dirs': [ 'include_dirs': [
'test', 'test',
......
...@@ -5,9 +5,9 @@ ...@@ -5,9 +5,9 @@
#ifndef CC_RESOURCES_MANAGED_TILE_STATE_H_ #ifndef CC_RESOURCES_MANAGED_TILE_STATE_H_
#define CC_RESOURCES_MANAGED_TILE_STATE_H_ #define CC_RESOURCES_MANAGED_TILE_STATE_H_
#include "base/hash_tables.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "cc/resources/platform_color.h" #include "cc/resources/platform_color.h"
#include "cc/resources/raster_worker_pool.h"
#include "cc/resources/resource_pool.h" #include "cc/resources/resource_pool.h"
#include "cc/resources/resource_provider.h" #include "cc/resources/resource_provider.h"
#include "cc/resources/tile_manager.h" #include "cc/resources/tile_manager.h"
...@@ -113,11 +113,10 @@ class CC_EXPORT ManagedTileState { ...@@ -113,11 +113,10 @@ class CC_EXPORT ManagedTileState {
scoped_ptr<base::Value> AsValue() const; scoped_ptr<base::Value> AsValue() const;
// Persisted state: valid all the time. // Persisted state: valid all the time.
typedef base::hash_set<uint32_t> PixelRefSet;
PixelRefSet decoded_pixel_refs;
TileVersion tile_version; TileVersion tile_version;
PicturePileImpl::Analysis picture_pile_analysis;
bool picture_pile_analyzed; bool picture_pile_analyzed;
PicturePileImpl::Analysis picture_pile_analysis;
RasterWorkerPool::Task raster_task;
// Ephemeral state, valid only during TileManager::ManageTiles. // Ephemeral state, valid only during TileManager::ManageTiles.
bool is_in_never_bin_on_both_trees() const { bool is_in_never_bin_on_both_trees() const {
......
...@@ -10,24 +10,72 @@ namespace cc { ...@@ -10,24 +10,72 @@ namespace cc {
namespace { namespace {
class RasterWorkerPoolContainerTaskImpl : public internal::WorkerPoolTask {
public:
RasterWorkerPoolContainerTaskImpl(
internal::WorkerPoolTask::TaskVector* dependencies)
: internal::WorkerPoolTask(dependencies) {
}
// Overridden from internal::WorkerPoolTask:
virtual void RunOnThread(unsigned thread_index) OVERRIDE {}
virtual void DispatchCompletionCallback() OVERRIDE {}
private:
virtual ~RasterWorkerPoolContainerTaskImpl() {}
};
class RasterWorkerPoolTaskImpl : public internal::WorkerPoolTask { class RasterWorkerPoolTaskImpl : public internal::WorkerPoolTask {
public: public:
RasterWorkerPoolTaskImpl(PicturePileImpl* picture_pile, RasterWorkerPoolTaskImpl(const base::Closure& callback,
const RasterWorkerPool::RasterCallback& task, const RasterWorkerPool::Task::Reply& reply)
const base::Closure& reply) : callback_(callback),
: internal::WorkerPoolTask(reply), reply_(reply) {
}
// Overridden from internal::WorkerPoolTask:
virtual void RunOnThread(unsigned thread_index) OVERRIDE {
callback_.Run();
}
virtual void DispatchCompletionCallback() OVERRIDE {
reply_.Run(!HasFinishedRunning());
}
private:
virtual ~RasterWorkerPoolTaskImpl() {}
const base::Closure callback_;
const RasterWorkerPool::Task::Reply reply_;
};
class RasterWorkerPoolPictureTaskImpl : public internal::WorkerPoolTask {
public:
RasterWorkerPoolPictureTaskImpl(
PicturePileImpl* picture_pile,
const RasterWorkerPool::PictureTask::Callback& callback,
const RasterWorkerPool::Task::Reply& reply,
internal::WorkerPoolTask::TaskVector* dependencies)
: internal::WorkerPoolTask(dependencies),
picture_pile_(picture_pile), picture_pile_(picture_pile),
task_(task) { callback_(callback),
reply_(reply) {
DCHECK(picture_pile_); DCHECK(picture_pile_);
} }
// Overridden from internal::WorkerPoolTask:
virtual void RunOnThread(unsigned thread_index) OVERRIDE { virtual void RunOnThread(unsigned thread_index) OVERRIDE {
task_.Run(picture_pile_->GetCloneForDrawingOnThread(thread_index)); callback_.Run(picture_pile_->GetCloneForDrawingOnThread(thread_index));
}
virtual void DispatchCompletionCallback() OVERRIDE {
reply_.Run(!HasFinishedRunning());
} }
private: private:
virtual ~RasterWorkerPoolPictureTaskImpl() {}
scoped_refptr<PicturePileImpl> picture_pile_; scoped_refptr<PicturePileImpl> picture_pile_;
RasterWorkerPool::RasterCallback task_; const RasterWorkerPool::PictureTask::Callback callback_;
const RasterWorkerPool::Task::Reply reply_;
}; };
const char* kWorkerThreadNamePrefix = "CompositorRaster"; const char* kWorkerThreadNamePrefix = "CompositorRaster";
...@@ -36,8 +84,52 @@ const int kCheckForCompletedTasksDelayMs = 6; ...@@ -36,8 +84,52 @@ const int kCheckForCompletedTasksDelayMs = 6;
} // namespace } // namespace
RasterWorkerPool::RasterWorkerPool(size_t num_threads) RasterWorkerPool::Task::Queue::Queue() {
: WorkerPool( }
RasterWorkerPool::Task::Queue::~Queue() {
}
void RasterWorkerPool::Task::Queue::Append(const Task& task) {
DCHECK(!task.is_null());
tasks_.push_back(task.internal_);
}
RasterWorkerPool::Task::Task() {
}
RasterWorkerPool::Task::Task(const base::Closure& callback,
const Reply& reply)
: internal_(new RasterWorkerPoolTaskImpl(callback, reply)) {
}
RasterWorkerPool::Task::Task(Queue* dependencies)
: internal_(new RasterWorkerPoolContainerTaskImpl(&dependencies->tasks_)) {
}
RasterWorkerPool::Task::Task(scoped_refptr<internal::WorkerPoolTask> internal)
: internal_(internal) {
}
RasterWorkerPool::Task::~Task() {
}
void RasterWorkerPool::Task::Reset() {
internal_ = NULL;
}
RasterWorkerPool::PictureTask::PictureTask(PicturePileImpl* picture_pile,
const Callback& callback,
const Reply& reply,
Task::Queue* dependencies)
: RasterWorkerPool::Task(
new RasterWorkerPoolPictureTaskImpl(picture_pile,
callback,
reply,
&dependencies->tasks_)) {
}
RasterWorkerPool::RasterWorkerPool(size_t num_threads) : WorkerPool(
num_threads, num_threads,
base::TimeDelta::FromMilliseconds(kCheckForCompletedTasksDelayMs), base::TimeDelta::FromMilliseconds(kCheckForCompletedTasksDelayMs),
kWorkerThreadNamePrefix) { kWorkerThreadNamePrefix) {
...@@ -46,13 +138,15 @@ RasterWorkerPool::RasterWorkerPool(size_t num_threads) ...@@ -46,13 +138,15 @@ RasterWorkerPool::RasterWorkerPool(size_t num_threads)
RasterWorkerPool::~RasterWorkerPool() { RasterWorkerPool::~RasterWorkerPool() {
} }
void RasterWorkerPool::PostRasterTaskAndReply(PicturePileImpl* picture_pile, void RasterWorkerPool::Shutdown() {
const RasterCallback& task, // Cancel all previously scheduled tasks.
const base::Closure& reply) { WorkerPool::ScheduleTasks(NULL);
PostTask(make_scoped_ptr(new RasterWorkerPoolTaskImpl(
picture_pile, WorkerPool::Shutdown();
task, }
reply)).PassAs<internal::WorkerPoolTask>());
void RasterWorkerPool::ScheduleTasks(Task* task) {
WorkerPool::ScheduleTasks(task ? task->internal_ : NULL);
} }
} // namespace cc } // namespace cc
...@@ -5,8 +5,6 @@ ...@@ -5,8 +5,6 @@
#ifndef CC_RESOURCES_RASTER_WORKER_POOL_H_ #ifndef CC_RESOURCES_RASTER_WORKER_POOL_H_
#define CC_RESOURCES_RASTER_WORKER_POOL_H_ #define CC_RESOURCES_RASTER_WORKER_POOL_H_
#include <string>
#include "cc/base/worker_pool.h" #include "cc/base/worker_pool.h"
namespace cc { namespace cc {
...@@ -15,7 +13,55 @@ class PicturePileImpl; ...@@ -15,7 +13,55 @@ class PicturePileImpl;
// A worker thread pool that runs raster tasks. // A worker thread pool that runs raster tasks.
class CC_EXPORT RasterWorkerPool : public WorkerPool { class CC_EXPORT RasterWorkerPool : public WorkerPool {
public: public:
typedef base::Callback<void(PicturePileImpl* picture_pile)> RasterCallback; class Task {
public:
typedef base::Callback<void(bool)> Reply;
// Highest priority task first. Order of execution is not guaranteed.
class Queue {
public:
Queue();
~Queue();
bool empty() const { return tasks_.empty(); }
// Add task to the back of the queue.
void Append(const Task& task);
private:
friend class RasterWorkerPool;
internal::WorkerPoolTask::TaskVector tasks_;
};
Task();
Task(const base::Closure& callback, const Reply& reply);
explicit Task(Queue* dependencies);
~Task();
// Returns true if Task is null (doesn't refer to anything).
bool is_null() const { return !internal_; }
// Returns the Task into an uninitialized state.
void Reset();
protected:
friend class RasterWorkerPool;
explicit Task(scoped_refptr<internal::WorkerPoolTask> internal);
scoped_refptr<internal::WorkerPoolTask> internal_;
};
class PictureTask : public Task {
public:
typedef base::Callback<void(PicturePileImpl*)> Callback;
PictureTask(PicturePileImpl* picture_pile,
const Callback& callback,
const Reply& reply,
Queue* dependencies);
};
virtual ~RasterWorkerPool(); virtual ~RasterWorkerPool();
...@@ -23,9 +69,16 @@ class CC_EXPORT RasterWorkerPool : public WorkerPool { ...@@ -23,9 +69,16 @@ class CC_EXPORT RasterWorkerPool : public WorkerPool {
return make_scoped_ptr(new RasterWorkerPool(num_threads)); return make_scoped_ptr(new RasterWorkerPool(num_threads));
} }
void PostRasterTaskAndReply(PicturePileImpl* picture_pile, // Tells the worker pool to shutdown after canceling all previously
const RasterCallback& task, // scheduled tasks. Reply callbacks are still guaranteed to run.
const base::Closure& reply); virtual void Shutdown() OVERRIDE;
// Schedule running of |root| task and all its dependencies. Tasks
// previously scheduled but no longer needed to run |root| will be
// canceled unless already running. Once scheduled, reply callbacks
// are guaranteed to run for all tasks even if they later get
// canceled by another call to ScheduleTasks().
void ScheduleTasks(Task* root);
private: private:
explicit RasterWorkerPool(size_t num_threads); explicit RasterWorkerPool(size_t num_threads);
......
...@@ -981,6 +981,8 @@ uint8_t* ResourceProvider::MapPixelBuffer(ResourceId id) { ...@@ -981,6 +981,8 @@ uint8_t* ResourceProvider::MapPixelBuffer(ResourceId id) {
context3d->mapBufferCHROMIUM( context3d->mapBufferCHROMIUM(
GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, GL_WRITE_ONLY)); GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, GL_WRITE_ONLY));
context3d->bindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); context3d->bindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
// Buffer is required to be 4-byte aligned.
CHECK(!(reinterpret_cast<intptr_t>(image) & 3));
return image; return image;
} }
......
This diff is collapsed.
...@@ -62,6 +62,8 @@ scoped_ptr<base::Value> TileManagerBinPriorityAsValue( ...@@ -62,6 +62,8 @@ scoped_ptr<base::Value> TileManagerBinPriorityAsValue(
// created, and unregister from the manager when they are deleted. // created, and unregister from the manager when they are deleted.
class CC_EXPORT TileManager : public WorkerPoolClient { class CC_EXPORT TileManager : public WorkerPoolClient {
public: public:
typedef base::hash_set<uint32_t> PixelRefSet;
static scoped_ptr<TileManager> Create( static scoped_ptr<TileManager> Create(
TileManagerClient* client, TileManagerClient* client,
ResourceProvider* resource_provider, ResourceProvider* resource_provider,
...@@ -116,7 +118,7 @@ class CC_EXPORT TileManager : public WorkerPoolClient { ...@@ -116,7 +118,7 @@ class CC_EXPORT TileManager : public WorkerPoolClient {
void UnregisterTile(Tile* tile); void UnregisterTile(Tile* tile);
// Virtual for test // Virtual for test
virtual void DispatchMoreTasks(); virtual void ScheduleTasks();
private: private:
// Data that is passed to raster tasks. // Data that is passed to raster tasks.
...@@ -129,8 +131,6 @@ class CC_EXPORT TileManager : public WorkerPoolClient { ...@@ -129,8 +131,6 @@ class CC_EXPORT TileManager : public WorkerPoolClient {
int source_frame_number; int source_frame_number;
}; };
RasterTaskMetadata GetRasterTaskMetadata(const Tile& tile) const;
void AssignBinsToTiles(); void AssignBinsToTiles();
void SortTiles(); void SortTiles();
void AssignGpuMemoryToTiles(); void AssignGpuMemoryToTiles();
...@@ -142,20 +142,19 @@ class CC_EXPORT TileManager : public WorkerPoolClient { ...@@ -142,20 +142,19 @@ class CC_EXPORT TileManager : public WorkerPoolClient {
client_->ScheduleManageTiles(); client_->ScheduleManageTiles();
manage_tiles_pending_ = true; manage_tiles_pending_ = true;
} }
bool DispatchImageDecodeTasksForTile(Tile* tile); RasterWorkerPool::Task CreateImageDecodeTask(
void DispatchOneImageDecodeTask( Tile* tile, skia::LazyPixelRef* pixel_ref);
scoped_refptr<Tile> tile, skia::LazyPixelRef* pixel_ref);
void OnImageDecodeTaskCompleted( void OnImageDecodeTaskCompleted(
scoped_refptr<Tile> tile, scoped_refptr<Tile> tile,
uint32_t pixel_ref_id); uint32_t pixel_ref_id,
bool CanDispatchRasterTask(Tile* tile) const; bool was_canceled);
scoped_ptr<ResourcePool::Resource> PrepareTileForRaster(Tile* tile); RasterTaskMetadata GetRasterTaskMetadata(const Tile& tile) const;
void DispatchOneRasterTask(scoped_refptr<Tile> tile); RasterWorkerPool::Task CreateRasterTask(Tile* tile);
void OnRasterTaskCompleted( void OnRasterTaskCompleted(
scoped_refptr<Tile> tile, scoped_refptr<Tile> tile,
scoped_ptr<ResourcePool::Resource> resource, scoped_ptr<ResourcePool::Resource> resource,
PicturePileImpl::Analysis* analysis, PicturePileImpl::Analysis* analysis,
int manage_tiles_call_count_when_dispatched); bool was_canceled);
void DidFinishTileInitialization(Tile* tile); void DidFinishTileInitialization(Tile* tile);
void DidTileTreeBinChange(Tile* tile, void DidTileTreeBinChange(Tile* tile,
TileManagerBin new_tree_bin, TileManagerBin new_tree_bin,
...@@ -163,9 +162,13 @@ class CC_EXPORT TileManager : public WorkerPoolClient { ...@@ -163,9 +162,13 @@ class CC_EXPORT TileManager : public WorkerPoolClient {
scoped_ptr<Value> GetMemoryRequirementsAsValue() const; scoped_ptr<Value> GetMemoryRequirementsAsValue() const;
void AddRequiredTileForActivation(Tile* tile); void AddRequiredTileForActivation(Tile* tile);
static void RunImageDecodeTask(
skia::LazyPixelRef* pixel_ref,
int layer_id,
RenderingStatsInstrumentation* stats_instrumentation);
static void RunAnalyzeAndRasterTask( static void RunAnalyzeAndRasterTask(
const RasterWorkerPool::RasterCallback& analyze_task, const RasterWorkerPool::PictureTask::Callback& analyze_task,
const RasterWorkerPool::RasterCallback& raster_task, const RasterWorkerPool::PictureTask::Callback& raster_task,
PicturePileImpl* picture_pile); PicturePileImpl* picture_pile);
static void RunAnalyzeTask( static void RunAnalyzeTask(
PicturePileImpl::Analysis* analysis, PicturePileImpl::Analysis* analysis,
...@@ -183,16 +186,11 @@ class CC_EXPORT TileManager : public WorkerPoolClient { ...@@ -183,16 +186,11 @@ class CC_EXPORT TileManager : public WorkerPoolClient {
const RasterTaskMetadata& metadata, const RasterTaskMetadata& metadata,
RenderingStatsInstrumentation* stats_instrumentation, RenderingStatsInstrumentation* stats_instrumentation,
PicturePileImpl* picture_pile); PicturePileImpl* picture_pile);
static void RunImageDecodeTask(
skia::LazyPixelRef* pixel_ref,
int layer_id,
RenderingStatsInstrumentation* stats_instrumentation);
TileManagerClient* client_; TileManagerClient* client_;
scoped_ptr<ResourcePool> resource_pool_; scoped_ptr<ResourcePool> resource_pool_;
scoped_ptr<RasterWorkerPool> raster_worker_pool_; scoped_ptr<RasterWorkerPool> raster_worker_pool_;
bool manage_tiles_pending_; bool manage_tiles_pending_;
int manage_tiles_call_count_;
GlobalStateThatImpactsTilePriority global_state_; GlobalStateThatImpactsTilePriority global_state_;
...@@ -202,8 +200,8 @@ class CC_EXPORT TileManager : public WorkerPoolClient { ...@@ -202,8 +200,8 @@ class CC_EXPORT TileManager : public WorkerPoolClient {
typedef std::set<Tile*> TileSet; typedef std::set<Tile*> TileSet;
TileSet tiles_that_need_to_be_initialized_for_activation_; TileSet tiles_that_need_to_be_initialized_for_activation_;
typedef base::hash_set<uint32_t> PixelRefSet; typedef base::hash_map<uint32_t, RasterWorkerPool::Task> PixelRefMap;
PixelRefSet pending_decode_tasks_; PixelRefMap pending_decode_tasks_;
typedef std::queue<scoped_refptr<Tile> > TileQueue; typedef std::queue<scoped_refptr<Tile> > TileQueue;
TileQueue tiles_with_pending_upload_; TileQueue tiles_with_pending_upload_;
...@@ -217,7 +215,6 @@ class CC_EXPORT TileManager : public WorkerPoolClient { ...@@ -217,7 +215,6 @@ class CC_EXPORT TileManager : public WorkerPoolClient {
bool use_color_estimator_; bool use_color_estimator_;
bool did_initialize_visible_tile_; bool did_initialize_visible_tile_;
size_t pending_tasks_;
size_t max_pending_tasks_; size_t max_pending_tasks_;
DISALLOW_COPY_AND_ASSIGN(TileManager); DISALLOW_COPY_AND_ASSIGN(TileManager);
......
...@@ -17,7 +17,7 @@ class FakeTileManager : public TileManager { ...@@ -17,7 +17,7 @@ class FakeTileManager : public TileManager {
protected: protected:
// Do nothing // Do nothing
virtual void DispatchMoreTasks() OVERRIDE { } virtual void ScheduleTasks() OVERRIDE { }
}; };
} // namespace cc } // namespace cc
......
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