1// Copyright 2013 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
5#include "cc/resources/raster_worker_pool.h"
6
7#include "base/time/time.h"
8#include "testing/gtest/include/gtest/gtest.h"
9
10namespace cc {
11
12namespace {
13
14static const int kTimeLimitMillis = 2000;
15static const int kWarmupRuns = 5;
16static const int kTimeCheckInterval = 10;
17
18class PerfWorkerPoolTaskImpl : public internal::WorkerPoolTask {
19 public:
20  // Overridden from internal::WorkerPoolTask:
21  virtual void RunOnWorkerThread(unsigned thread_index) OVERRIDE {}
22  virtual void CompleteOnOriginThread() OVERRIDE {}
23
24 private:
25  virtual ~PerfWorkerPoolTaskImpl() {}
26};
27
28class PerfRasterWorkerPool : public RasterWorkerPool {
29 public:
30  PerfRasterWorkerPool() : RasterWorkerPool(NULL, 1) {}
31  virtual ~PerfRasterWorkerPool() {}
32
33  static scoped_ptr<PerfRasterWorkerPool> Create() {
34    return make_scoped_ptr(new PerfRasterWorkerPool);
35  }
36
37  // Overridden from RasterWorkerPool:
38  virtual void ScheduleTasks(RasterTask::Queue* queue) OVERRIDE {
39    NOTREACHED();
40  }
41  virtual void OnRasterTasksFinished() OVERRIDE {
42    NOTREACHED();
43  }
44  virtual void OnRasterTasksRequiredForActivationFinished() OVERRIDE {
45    NOTREACHED();
46  }
47
48  void SetRasterTasks(RasterTask::Queue* queue) {
49    RasterWorkerPool::SetRasterTasks(queue);
50
51    TaskMap perf_tasks;
52    for (RasterTaskVector::const_iterator it = raster_tasks().begin();
53         it != raster_tasks().end(); ++it) {
54      internal::RasterWorkerPoolTask* task = it->get();
55
56      scoped_refptr<internal::WorkerPoolTask> new_perf_task(
57          new PerfWorkerPoolTaskImpl);
58      perf_tasks[task] = new_perf_task;
59    }
60
61    perf_tasks_.swap(perf_tasks);
62  }
63
64  void BuildTaskGraph() {
65    unsigned priority = 0;
66    TaskGraph graph;
67
68    scoped_refptr<internal::WorkerPoolTask>
69        raster_required_for_activation_finished_task(
70            CreateRasterRequiredForActivationFinishedTask());
71    internal::GraphNode* raster_required_for_activation_finished_node =
72        CreateGraphNodeForTask(
73            raster_required_for_activation_finished_task.get(),
74            priority++,
75            &graph);
76
77    scoped_refptr<internal::WorkerPoolTask> raster_finished_task(
78        CreateRasterFinishedTask());
79    internal::GraphNode* raster_finished_node =
80        CreateGraphNodeForTask(raster_finished_task.get(),
81                               priority++,
82                               &graph);
83
84    for (RasterTaskVector::const_iterator it = raster_tasks().begin();
85         it != raster_tasks().end(); ++it) {
86      internal::RasterWorkerPoolTask* task = it->get();
87
88      TaskMap::iterator perf_it = perf_tasks_.find(task);
89      DCHECK(perf_it != perf_tasks_.end());
90      if (perf_it != perf_tasks_.end()) {
91        internal::WorkerPoolTask* perf_task = perf_it->second.get();
92
93        internal::GraphNode* perf_node =
94            CreateGraphNodeForRasterTask(perf_task,
95                                         task->dependencies(),
96                                         priority++,
97                                         &graph);
98
99        if (IsRasterTaskRequiredForActivation(task)) {
100          raster_required_for_activation_finished_node->add_dependency();
101          perf_node->add_dependent(
102              raster_required_for_activation_finished_node);
103        }
104
105        raster_finished_node->add_dependency();
106        perf_node->add_dependent(raster_finished_node);
107      }
108    }
109  }
110
111 private:
112  TaskMap perf_tasks_;
113
114  DISALLOW_COPY_AND_ASSIGN(PerfRasterWorkerPool);
115};
116
117class RasterWorkerPoolPerfTest : public testing::Test {
118 public:
119  RasterWorkerPoolPerfTest() : num_runs_(0) {}
120
121  // Overridden from testing::Test:
122  virtual void SetUp() OVERRIDE {
123    raster_worker_pool_ = PerfRasterWorkerPool::Create();
124  }
125  virtual void TearDown() OVERRIDE {
126    raster_worker_pool_->Shutdown();
127  }
128
129  void EndTest() {
130    elapsed_ = base::TimeTicks::HighResNow() - start_time_;
131  }
132
133  void AfterTest(const std::string test_name) {
134    // Format matches chrome/test/perf/perf_test.h:PrintResult
135    printf("*RESULT %s: %.2f runs/s\n",
136           test_name.c_str(),
137           num_runs_ / elapsed_.InSecondsF());
138  }
139
140  bool DidRun() {
141    ++num_runs_;
142    if (num_runs_ == kWarmupRuns)
143      start_time_ = base::TimeTicks::HighResNow();
144
145    if (!start_time_.is_null() && (num_runs_ % kTimeCheckInterval) == 0) {
146      base::TimeDelta elapsed = base::TimeTicks::HighResNow() - start_time_;
147      if (elapsed >= base::TimeDelta::FromMilliseconds(kTimeLimitMillis)) {
148        elapsed_ = elapsed;
149        return false;
150      }
151    }
152
153    return true;
154  }
155
156  void CreateTasks(RasterWorkerPool::RasterTask::Queue* tasks,
157                   unsigned num_raster_tasks,
158                   unsigned num_image_decode_tasks) {
159    typedef std::vector<RasterWorkerPool::Task> TaskVector;
160    TaskVector image_decode_tasks;
161
162    for (unsigned i = 0; i < num_image_decode_tasks; ++i) {
163      image_decode_tasks.push_back(
164          RasterWorkerPool::CreateImageDecodeTask(
165              NULL,
166              0,
167              NULL,
168              base::Bind(
169                  &RasterWorkerPoolPerfTest::OnImageDecodeTaskCompleted)));
170    }
171
172    for (unsigned i = 0; i < num_raster_tasks; ++i) {
173      RasterWorkerPool::Task::Set decode_tasks;
174      for (TaskVector::iterator it = image_decode_tasks.begin();
175           it != image_decode_tasks.end(); ++it)
176        decode_tasks.Insert(*it);
177
178      tasks->Append(
179          RasterWorkerPool::CreateRasterTask(
180              NULL,
181              NULL,
182              gfx::Rect(),
183              1.0,
184              HIGH_QUALITY_RASTER_MODE,
185              false,
186              TileResolution(),
187              1,
188              NULL,
189              1,
190              NULL,
191              base::Bind(&RasterWorkerPoolPerfTest::OnRasterTaskCompleted),
192              &decode_tasks),
193          false);
194    }
195  }
196
197  void RunBuildTaskGraphTest(const std::string test_name,
198                             unsigned num_raster_tasks,
199                             unsigned num_image_decode_tasks) {
200    start_time_ = base::TimeTicks();
201    num_runs_ = 0;
202    RasterWorkerPool::RasterTask::Queue tasks;
203    CreateTasks(&tasks, num_raster_tasks, num_image_decode_tasks);
204    raster_worker_pool_->SetRasterTasks(&tasks);
205    do {
206      raster_worker_pool_->BuildTaskGraph();
207    } while (DidRun());
208
209    AfterTest(test_name);
210  }
211
212 protected:
213  static void OnRasterTaskCompleted(const PicturePileImpl::Analysis& analysis,
214                                    bool was_canceled) {}
215  static void OnImageDecodeTaskCompleted(bool was_canceled) {}
216
217  scoped_ptr<PerfRasterWorkerPool> raster_worker_pool_;
218  base::TimeTicks start_time_;
219  base::TimeDelta elapsed_;
220  int num_runs_;
221};
222
223TEST_F(RasterWorkerPoolPerfTest, BuildTaskGraph) {
224  RunBuildTaskGraphTest("build_task_graph_10_0", 10, 0);
225  RunBuildTaskGraphTest("build_task_graph_100_0", 100, 0);
226  RunBuildTaskGraphTest("build_task_graph_1000_0", 1000, 0);
227  RunBuildTaskGraphTest("build_task_graph_10_1", 10, 1);
228  RunBuildTaskGraphTest("build_task_graph_100_1", 100, 1);
229  RunBuildTaskGraphTest("build_task_graph_1000_1", 1000, 1);
230  RunBuildTaskGraphTest("build_task_graph_10_4", 10, 4);
231  RunBuildTaskGraphTest("build_task_graph_100_4", 100, 4);
232  RunBuildTaskGraphTest("build_task_graph_1000_4", 1000, 4);
233  RunBuildTaskGraphTest("build_task_graph_10_16", 10, 16);
234  RunBuildTaskGraphTest("build_task_graph_100_16", 100, 16);
235  RunBuildTaskGraphTest("build_task_graph_1000_16", 1000, 16);
236}
237
238}  // namespace
239
240}  // namespace cc
241