// 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/resources/raster_worker_pool.h" #include "base/time/time.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 PerfWorkerPoolTaskImpl : public internal::WorkerPoolTask { public: // Overridden from internal::WorkerPoolTask: virtual void RunOnWorkerThread(unsigned thread_index) OVERRIDE {} virtual void CompleteOnOriginThread() OVERRIDE {} private: virtual ~PerfWorkerPoolTaskImpl() {} }; class PerfRasterWorkerPool : public RasterWorkerPool { public: PerfRasterWorkerPool() : RasterWorkerPool(NULL, 1) {} virtual ~PerfRasterWorkerPool() {} static scoped_ptr Create() { return make_scoped_ptr(new PerfRasterWorkerPool); } // Overridden from RasterWorkerPool: virtual void ScheduleTasks(RasterTask::Queue* queue) OVERRIDE { NOTREACHED(); } virtual void OnRasterTasksFinished() OVERRIDE { NOTREACHED(); } virtual void OnRasterTasksRequiredForActivationFinished() OVERRIDE { NOTREACHED(); } void SetRasterTasks(RasterTask::Queue* queue) { RasterWorkerPool::SetRasterTasks(queue); TaskMap perf_tasks; for (RasterTaskVector::const_iterator it = raster_tasks().begin(); it != raster_tasks().end(); ++it) { internal::RasterWorkerPoolTask* task = it->get(); scoped_refptr new_perf_task( new PerfWorkerPoolTaskImpl); perf_tasks[task] = new_perf_task; } perf_tasks_.swap(perf_tasks); } void BuildTaskGraph() { unsigned priority = 0; TaskGraph graph; scoped_refptr raster_required_for_activation_finished_task( CreateRasterRequiredForActivationFinishedTask()); internal::GraphNode* raster_required_for_activation_finished_node = CreateGraphNodeForTask( raster_required_for_activation_finished_task.get(), priority++, &graph); scoped_refptr raster_finished_task( CreateRasterFinishedTask()); internal::GraphNode* raster_finished_node = CreateGraphNodeForTask(raster_finished_task.get(), priority++, &graph); for (RasterTaskVector::const_iterator it = raster_tasks().begin(); it != raster_tasks().end(); ++it) { internal::RasterWorkerPoolTask* task = it->get(); TaskMap::iterator perf_it = perf_tasks_.find(task); DCHECK(perf_it != perf_tasks_.end()); if (perf_it != perf_tasks_.end()) { internal::WorkerPoolTask* perf_task = perf_it->second.get(); internal::GraphNode* perf_node = CreateGraphNodeForRasterTask(perf_task, task->dependencies(), priority++, &graph); if (IsRasterTaskRequiredForActivation(task)) { raster_required_for_activation_finished_node->add_dependency(); perf_node->add_dependent( raster_required_for_activation_finished_node); } raster_finished_node->add_dependency(); perf_node->add_dependent(raster_finished_node); } } } private: TaskMap perf_tasks_; DISALLOW_COPY_AND_ASSIGN(PerfRasterWorkerPool); }; class RasterWorkerPoolPerfTest : public testing::Test { public: RasterWorkerPoolPerfTest() : num_runs_(0) {} // Overridden from testing::Test: virtual void SetUp() OVERRIDE { raster_worker_pool_ = PerfRasterWorkerPool::Create(); } virtual void TearDown() OVERRIDE { raster_worker_pool_->Shutdown(); } 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()); } 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 CreateTasks(RasterWorkerPool::RasterTask::Queue* tasks, unsigned num_raster_tasks, unsigned num_image_decode_tasks) { typedef std::vector TaskVector; TaskVector image_decode_tasks; for (unsigned i = 0; i < num_image_decode_tasks; ++i) { image_decode_tasks.push_back( RasterWorkerPool::CreateImageDecodeTask( NULL, 0, NULL, base::Bind( &RasterWorkerPoolPerfTest::OnImageDecodeTaskCompleted))); } for (unsigned i = 0; i < num_raster_tasks; ++i) { RasterWorkerPool::Task::Set decode_tasks; for (TaskVector::iterator it = image_decode_tasks.begin(); it != image_decode_tasks.end(); ++it) decode_tasks.Insert(*it); tasks->Append( RasterWorkerPool::CreateRasterTask( NULL, NULL, gfx::Rect(), 1.0, HIGH_QUALITY_RASTER_MODE, false, TileResolution(), 1, NULL, 1, NULL, base::Bind(&RasterWorkerPoolPerfTest::OnRasterTaskCompleted), &decode_tasks), false); } } void RunBuildTaskGraphTest(const std::string test_name, unsigned num_raster_tasks, unsigned num_image_decode_tasks) { start_time_ = base::TimeTicks(); num_runs_ = 0; RasterWorkerPool::RasterTask::Queue tasks; CreateTasks(&tasks, num_raster_tasks, num_image_decode_tasks); raster_worker_pool_->SetRasterTasks(&tasks); do { raster_worker_pool_->BuildTaskGraph(); } while (DidRun()); AfterTest(test_name); } protected: static void OnRasterTaskCompleted(const PicturePileImpl::Analysis& analysis, bool was_canceled) {} static void OnImageDecodeTaskCompleted(bool was_canceled) {} scoped_ptr raster_worker_pool_; base::TimeTicks start_time_; base::TimeDelta elapsed_; int num_runs_; }; TEST_F(RasterWorkerPoolPerfTest, BuildTaskGraph) { RunBuildTaskGraphTest("build_task_graph_10_0", 10, 0); RunBuildTaskGraphTest("build_task_graph_100_0", 100, 0); RunBuildTaskGraphTest("build_task_graph_1000_0", 1000, 0); RunBuildTaskGraphTest("build_task_graph_10_1", 10, 1); RunBuildTaskGraphTest("build_task_graph_100_1", 100, 1); RunBuildTaskGraphTest("build_task_graph_1000_1", 1000, 1); RunBuildTaskGraphTest("build_task_graph_10_4", 10, 4); RunBuildTaskGraphTest("build_task_graph_100_4", 100, 4); RunBuildTaskGraphTest("build_task_graph_1000_4", 1000, 4); RunBuildTaskGraphTest("build_task_graph_10_16", 10, 16); RunBuildTaskGraphTest("build_task_graph_100_16", 100, 16); RunBuildTaskGraphTest("build_task_graph_1000_16", 1000, 16); } } // namespace } // namespace cc