Blink roll 25b6bd3a7a131ffe68d809546ad1a20707915cdc:3a503f41ae42e5b79cfcd2ff10e65afde...
[chromium-blink-merge.git] / base / message_loop / message_pump_perftest.cc
blob9fca4653dbe2cb3f5bd622358ff6541910d0c27a
1 // Copyright 2014 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.
5 #include "base/bind.h"
6 #include "base/format_macros.h"
7 #include "base/memory/scoped_vector.h"
8 #include "base/strings/stringprintf.h"
9 #include "base/synchronization/condition_variable.h"
10 #include "base/synchronization/lock.h"
11 #include "base/synchronization/waitable_event.h"
12 #include "base/threading/thread.h"
13 #include "base/time/time.h"
14 #include "build/build_config.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 #include "testing/perf/perf_test.h"
18 #if defined(OS_ANDROID)
19 #include "base/android/java_handler_thread.h"
20 #endif
22 namespace base {
23 namespace {
25 class ScheduleWorkTest : public testing::Test {
26 public:
27 ScheduleWorkTest() : counter_(0) {}
29 void Increment(uint64_t amount) { counter_ += amount; }
31 void Schedule(int index) {
32 base::TimeTicks start = base::TimeTicks::HighResNow();
33 base::TimeTicks thread_start;
34 if (TimeTicks::IsThreadNowSupported())
35 thread_start = base::TimeTicks::ThreadNow();
36 base::TimeDelta minimum = base::TimeDelta::Max();
37 base::TimeDelta maximum = base::TimeDelta();
38 base::TimeTicks now, lastnow = start;
39 uint64_t schedule_calls = 0u;
40 do {
41 for (size_t i = 0; i < kBatchSize; ++i) {
42 target_message_loop()->ScheduleWork(true);
43 schedule_calls++;
45 now = base::TimeTicks::HighResNow();
46 base::TimeDelta laptime = now - lastnow;
47 lastnow = now;
48 minimum = std::min(minimum, laptime);
49 maximum = std::max(maximum, laptime);
50 } while (now - start < base::TimeDelta::FromSeconds(kTargetTimeSec));
52 scheduling_times_[index] = now - start;
53 if (TimeTicks::IsThreadNowSupported())
54 scheduling_thread_times_[index] =
55 base::TimeTicks::ThreadNow() - thread_start;
56 min_batch_times_[index] = minimum;
57 max_batch_times_[index] = maximum;
58 target_message_loop()->PostTask(FROM_HERE,
59 base::Bind(&ScheduleWorkTest::Increment,
60 base::Unretained(this),
61 schedule_calls));
64 void ScheduleWork(MessageLoop::Type target_type, int num_scheduling_threads) {
65 #if defined(OS_ANDROID)
66 if (target_type == MessageLoop::TYPE_JAVA) {
67 java_thread_.reset(new android::JavaHandlerThread("target"));
68 java_thread_->Start();
69 } else
70 #endif
72 target_.reset(new Thread("target"));
73 target_->StartWithOptions(Thread::Options(target_type, 0u));
76 ScopedVector<Thread> scheduling_threads;
77 scheduling_times_.reset(new base::TimeDelta[num_scheduling_threads]);
78 scheduling_thread_times_.reset(new base::TimeDelta[num_scheduling_threads]);
79 min_batch_times_.reset(new base::TimeDelta[num_scheduling_threads]);
80 max_batch_times_.reset(new base::TimeDelta[num_scheduling_threads]);
82 for (int i = 0; i < num_scheduling_threads; ++i) {
83 scheduling_threads.push_back(new Thread("posting thread"));
84 scheduling_threads[i]->Start();
87 for (int i = 0; i < num_scheduling_threads; ++i) {
88 scheduling_threads[i]->message_loop()->PostTask(
89 FROM_HERE,
90 base::Bind(&ScheduleWorkTest::Schedule, base::Unretained(this), i));
93 for (int i = 0; i < num_scheduling_threads; ++i) {
94 scheduling_threads[i]->Stop();
96 #if defined(OS_ANDROID)
97 if (target_type == MessageLoop::TYPE_JAVA) {
98 java_thread_->Stop();
99 java_thread_.reset();
100 } else
101 #endif
103 target_->Stop();
104 target_.reset();
106 base::TimeDelta total_time;
107 base::TimeDelta total_thread_time;
108 base::TimeDelta min_batch_time = base::TimeDelta::Max();
109 base::TimeDelta max_batch_time = base::TimeDelta();
110 for (int i = 0; i < num_scheduling_threads; ++i) {
111 total_time += scheduling_times_[i];
112 total_thread_time += scheduling_thread_times_[i];
113 min_batch_time = std::min(min_batch_time, min_batch_times_[i]);
114 max_batch_time = std::max(max_batch_time, max_batch_times_[i]);
116 std::string trace = StringPrintf(
117 "%d_threads_scheduling_to_%s_pump",
118 num_scheduling_threads,
119 target_type == MessageLoop::TYPE_IO
120 ? "io"
121 : (target_type == MessageLoop::TYPE_UI ? "ui" : "default"));
122 perf_test::PrintResult(
123 "task",
125 trace,
126 total_time.InMicroseconds() / static_cast<double>(counter_),
127 "us/task",
128 true);
129 perf_test::PrintResult(
130 "task",
131 "_min_batch_time",
132 trace,
133 min_batch_time.InMicroseconds() / static_cast<double>(kBatchSize),
134 "us/task",
135 false);
136 perf_test::PrintResult(
137 "task",
138 "_max_batch_time",
139 trace,
140 max_batch_time.InMicroseconds() / static_cast<double>(kBatchSize),
141 "us/task",
142 false);
143 if (TimeTicks::IsThreadNowSupported()) {
144 perf_test::PrintResult(
145 "task",
146 "_thread_time",
147 trace,
148 total_thread_time.InMicroseconds() / static_cast<double>(counter_),
149 "us/task",
150 true);
154 MessageLoop* target_message_loop() {
155 #if defined(OS_ANDROID)
156 if (java_thread_)
157 return java_thread_->message_loop();
158 #endif
159 return target_->message_loop();
162 private:
163 scoped_ptr<Thread> target_;
164 #if defined(OS_ANDROID)
165 scoped_ptr<android::JavaHandlerThread> java_thread_;
166 #endif
167 scoped_ptr<base::TimeDelta[]> scheduling_times_;
168 scoped_ptr<base::TimeDelta[]> scheduling_thread_times_;
169 scoped_ptr<base::TimeDelta[]> min_batch_times_;
170 scoped_ptr<base::TimeDelta[]> max_batch_times_;
171 uint64_t counter_;
173 static const size_t kTargetTimeSec = 5;
174 static const size_t kBatchSize = 1000;
177 TEST_F(ScheduleWorkTest, ThreadTimeToIOFromOneThread) {
178 ScheduleWork(MessageLoop::TYPE_IO, 1);
181 TEST_F(ScheduleWorkTest, ThreadTimeToIOFromTwoThreads) {
182 ScheduleWork(MessageLoop::TYPE_IO, 2);
185 TEST_F(ScheduleWorkTest, ThreadTimeToIOFromFourThreads) {
186 ScheduleWork(MessageLoop::TYPE_IO, 4);
189 TEST_F(ScheduleWorkTest, ThreadTimeToUIFromOneThread) {
190 ScheduleWork(MessageLoop::TYPE_UI, 1);
193 TEST_F(ScheduleWorkTest, ThreadTimeToUIFromTwoThreads) {
194 ScheduleWork(MessageLoop::TYPE_UI, 2);
197 TEST_F(ScheduleWorkTest, ThreadTimeToUIFromFourThreads) {
198 ScheduleWork(MessageLoop::TYPE_UI, 4);
201 TEST_F(ScheduleWorkTest, ThreadTimeToDefaultFromOneThread) {
202 ScheduleWork(MessageLoop::TYPE_DEFAULT, 1);
205 TEST_F(ScheduleWorkTest, ThreadTimeToDefaultFromTwoThreads) {
206 ScheduleWork(MessageLoop::TYPE_DEFAULT, 2);
209 TEST_F(ScheduleWorkTest, ThreadTimeToDefaultFromFourThreads) {
210 ScheduleWork(MessageLoop::TYPE_DEFAULT, 4);
213 #if defined(OS_ANDROID)
214 TEST_F(ScheduleWorkTest, ThreadTimeToJavaFromOneThread) {
215 ScheduleWork(MessageLoop::TYPE_JAVA, 1);
218 TEST_F(ScheduleWorkTest, ThreadTimeToJavaFromTwoThreads) {
219 ScheduleWork(MessageLoop::TYPE_JAVA, 2);
222 TEST_F(ScheduleWorkTest, ThreadTimeToJavaFromFourThreads) {
223 ScheduleWork(MessageLoop::TYPE_JAVA, 4);
225 #endif
227 static void DoNothing() {
230 class FakeMessagePump : public MessagePump {
231 public:
232 FakeMessagePump() {}
233 ~FakeMessagePump() override {}
235 void Run(Delegate* delegate) override {}
237 void Quit() override {}
238 void ScheduleWork() override {}
239 void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override {}
242 class PostTaskTest : public testing::Test {
243 public:
244 void Run(int batch_size, int tasks_per_reload) {
245 base::TimeTicks start = base::TimeTicks::HighResNow();
246 base::TimeTicks now;
247 MessageLoop loop(scoped_ptr<MessagePump>(new FakeMessagePump));
248 scoped_refptr<internal::IncomingTaskQueue> queue(
249 new internal::IncomingTaskQueue(&loop));
250 uint32_t num_posted = 0;
251 do {
252 for (int i = 0; i < batch_size; ++i) {
253 for (int j = 0; j < tasks_per_reload; ++j) {
254 queue->AddToIncomingQueue(
255 FROM_HERE, base::Bind(&DoNothing), base::TimeDelta(), false);
256 num_posted++;
258 TaskQueue loop_local_queue;
259 queue->ReloadWorkQueue(&loop_local_queue);
260 while (!loop_local_queue.empty()) {
261 PendingTask t = loop_local_queue.front();
262 loop_local_queue.pop();
263 loop.RunTask(t);
267 now = base::TimeTicks::HighResNow();
268 } while (now - start < base::TimeDelta::FromSeconds(5));
269 std::string trace = StringPrintf("%d_tasks_per_reload", tasks_per_reload);
270 perf_test::PrintResult(
271 "task",
273 trace,
274 (now - start).InMicroseconds() / static_cast<double>(num_posted),
275 "us/task",
276 true);
280 TEST_F(PostTaskTest, OneTaskPerReload) {
281 Run(10000, 1);
284 TEST_F(PostTaskTest, TenTasksPerReload) {
285 Run(10000, 10);
288 TEST_F(PostTaskTest, OneHundredTasksPerReload) {
289 Run(1000, 100);
292 } // namespace
293 } // namespace base