Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / base / message_loop / message_pump_perftest.cc
blob7d833befa6158a33b5e64810a928c85abf547798
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 {
24 class ScheduleWorkTest : public testing::Test {
25 public:
26 ScheduleWorkTest() : counter_(0) {}
28 void Increment(uint64_t amount) { counter_ += amount; }
30 void Schedule(int index) {
31 base::TimeTicks start = base::TimeTicks::Now();
32 base::ThreadTicks thread_start;
33 if (ThreadTicks::IsSupported())
34 thread_start = base::ThreadTicks::Now();
35 base::TimeDelta minimum = base::TimeDelta::Max();
36 base::TimeDelta maximum = base::TimeDelta();
37 base::TimeTicks now, lastnow = start;
38 uint64_t schedule_calls = 0u;
39 do {
40 for (size_t i = 0; i < kBatchSize; ++i) {
41 target_message_loop()->ScheduleWork();
42 schedule_calls++;
44 now = base::TimeTicks::Now();
45 base::TimeDelta laptime = now - lastnow;
46 lastnow = now;
47 minimum = std::min(minimum, laptime);
48 maximum = std::max(maximum, laptime);
49 } while (now - start < base::TimeDelta::FromSeconds(kTargetTimeSec));
51 scheduling_times_[index] = now - start;
52 if (ThreadTicks::IsSupported())
53 scheduling_thread_times_[index] =
54 base::ThreadTicks::Now() - thread_start;
55 min_batch_times_[index] = minimum;
56 max_batch_times_[index] = maximum;
57 target_message_loop()->PostTask(FROM_HERE,
58 base::Bind(&ScheduleWorkTest::Increment,
59 base::Unretained(this),
60 schedule_calls));
63 void ScheduleWork(MessageLoop::Type target_type, int num_scheduling_threads) {
64 #if defined(OS_ANDROID)
65 if (target_type == MessageLoop::TYPE_JAVA) {
66 java_thread_.reset(new android::JavaHandlerThread("target"));
67 java_thread_->Start();
68 } else
69 #endif
71 target_.reset(new Thread("target"));
72 target_->StartWithOptions(Thread::Options(target_type, 0u));
75 ScopedVector<Thread> scheduling_threads;
76 scheduling_times_.reset(new base::TimeDelta[num_scheduling_threads]);
77 scheduling_thread_times_.reset(new base::TimeDelta[num_scheduling_threads]);
78 min_batch_times_.reset(new base::TimeDelta[num_scheduling_threads]);
79 max_batch_times_.reset(new base::TimeDelta[num_scheduling_threads]);
81 for (int i = 0; i < num_scheduling_threads; ++i) {
82 scheduling_threads.push_back(new Thread("posting thread"));
83 scheduling_threads[i]->Start();
86 for (int i = 0; i < num_scheduling_threads; ++i) {
87 scheduling_threads[i]->message_loop()->PostTask(
88 FROM_HERE,
89 base::Bind(&ScheduleWorkTest::Schedule, base::Unretained(this), i));
92 for (int i = 0; i < num_scheduling_threads; ++i) {
93 scheduling_threads[i]->Stop();
95 #if defined(OS_ANDROID)
96 if (target_type == MessageLoop::TYPE_JAVA) {
97 java_thread_->Stop();
98 java_thread_.reset();
99 } else
100 #endif
102 target_->Stop();
103 target_.reset();
105 base::TimeDelta total_time;
106 base::TimeDelta total_thread_time;
107 base::TimeDelta min_batch_time = base::TimeDelta::Max();
108 base::TimeDelta max_batch_time = base::TimeDelta();
109 for (int i = 0; i < num_scheduling_threads; ++i) {
110 total_time += scheduling_times_[i];
111 total_thread_time += scheduling_thread_times_[i];
112 min_batch_time = std::min(min_batch_time, min_batch_times_[i]);
113 max_batch_time = std::max(max_batch_time, max_batch_times_[i]);
115 std::string trace = StringPrintf(
116 "%d_threads_scheduling_to_%s_pump",
117 num_scheduling_threads,
118 target_type == MessageLoop::TYPE_IO
119 ? "io"
120 : (target_type == MessageLoop::TYPE_UI ? "ui" : "default"));
121 perf_test::PrintResult(
122 "task",
124 trace,
125 total_time.InMicroseconds() / static_cast<double>(counter_),
126 "us/task",
127 true);
128 perf_test::PrintResult(
129 "task",
130 "_min_batch_time",
131 trace,
132 min_batch_time.InMicroseconds() / static_cast<double>(kBatchSize),
133 "us/task",
134 false);
135 perf_test::PrintResult(
136 "task",
137 "_max_batch_time",
138 trace,
139 max_batch_time.InMicroseconds() / static_cast<double>(kBatchSize),
140 "us/task",
141 false);
142 if (ThreadTicks::IsSupported()) {
143 perf_test::PrintResult(
144 "task",
145 "_thread_time",
146 trace,
147 total_thread_time.InMicroseconds() / static_cast<double>(counter_),
148 "us/task",
149 true);
153 MessageLoop* target_message_loop() {
154 #if defined(OS_ANDROID)
155 if (java_thread_)
156 return java_thread_->message_loop();
157 #endif
158 return target_->message_loop();
161 private:
162 scoped_ptr<Thread> target_;
163 #if defined(OS_ANDROID)
164 scoped_ptr<android::JavaHandlerThread> java_thread_;
165 #endif
166 scoped_ptr<base::TimeDelta[]> scheduling_times_;
167 scoped_ptr<base::TimeDelta[]> scheduling_thread_times_;
168 scoped_ptr<base::TimeDelta[]> min_batch_times_;
169 scoped_ptr<base::TimeDelta[]> max_batch_times_;
170 uint64_t counter_;
172 static const size_t kTargetTimeSec = 5;
173 static const size_t kBatchSize = 1000;
176 TEST_F(ScheduleWorkTest, ThreadTimeToIOFromOneThread) {
177 ScheduleWork(MessageLoop::TYPE_IO, 1);
180 TEST_F(ScheduleWorkTest, ThreadTimeToIOFromTwoThreads) {
181 ScheduleWork(MessageLoop::TYPE_IO, 2);
184 TEST_F(ScheduleWorkTest, ThreadTimeToIOFromFourThreads) {
185 ScheduleWork(MessageLoop::TYPE_IO, 4);
188 TEST_F(ScheduleWorkTest, ThreadTimeToUIFromOneThread) {
189 ScheduleWork(MessageLoop::TYPE_UI, 1);
192 TEST_F(ScheduleWorkTest, ThreadTimeToUIFromTwoThreads) {
193 ScheduleWork(MessageLoop::TYPE_UI, 2);
196 TEST_F(ScheduleWorkTest, ThreadTimeToUIFromFourThreads) {
197 ScheduleWork(MessageLoop::TYPE_UI, 4);
200 TEST_F(ScheduleWorkTest, ThreadTimeToDefaultFromOneThread) {
201 ScheduleWork(MessageLoop::TYPE_DEFAULT, 1);
204 TEST_F(ScheduleWorkTest, ThreadTimeToDefaultFromTwoThreads) {
205 ScheduleWork(MessageLoop::TYPE_DEFAULT, 2);
208 TEST_F(ScheduleWorkTest, ThreadTimeToDefaultFromFourThreads) {
209 ScheduleWork(MessageLoop::TYPE_DEFAULT, 4);
212 #if defined(OS_ANDROID)
213 TEST_F(ScheduleWorkTest, ThreadTimeToJavaFromOneThread) {
214 ScheduleWork(MessageLoop::TYPE_JAVA, 1);
217 TEST_F(ScheduleWorkTest, ThreadTimeToJavaFromTwoThreads) {
218 ScheduleWork(MessageLoop::TYPE_JAVA, 2);
221 TEST_F(ScheduleWorkTest, ThreadTimeToJavaFromFourThreads) {
222 ScheduleWork(MessageLoop::TYPE_JAVA, 4);
224 #endif
226 class FakeMessagePump : public MessagePump {
227 public:
228 FakeMessagePump() {}
229 ~FakeMessagePump() override {}
231 void Run(Delegate* delegate) override {}
233 void Quit() override {}
234 void ScheduleWork() override {}
235 void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override {}
238 class PostTaskTest : public testing::Test {
239 public:
240 void Run(int batch_size, int tasks_per_reload) {
241 base::TimeTicks start = base::TimeTicks::Now();
242 base::TimeTicks now;
243 MessageLoop loop(scoped_ptr<MessagePump>(new FakeMessagePump));
244 scoped_refptr<internal::IncomingTaskQueue> queue(
245 new internal::IncomingTaskQueue(&loop));
246 uint32_t num_posted = 0;
247 do {
248 for (int i = 0; i < batch_size; ++i) {
249 for (int j = 0; j < tasks_per_reload; ++j) {
250 queue->AddToIncomingQueue(
251 FROM_HERE, base::Bind(&DoNothing), base::TimeDelta(), false);
252 num_posted++;
254 TaskQueue loop_local_queue;
255 queue->ReloadWorkQueue(&loop_local_queue);
256 while (!loop_local_queue.empty()) {
257 PendingTask t = loop_local_queue.front();
258 loop_local_queue.pop();
259 loop.RunTask(t);
263 now = base::TimeTicks::Now();
264 } while (now - start < base::TimeDelta::FromSeconds(5));
265 std::string trace = StringPrintf("%d_tasks_per_reload", tasks_per_reload);
266 perf_test::PrintResult(
267 "task",
269 trace,
270 (now - start).InMicroseconds() / static_cast<double>(num_posted),
271 "us/task",
272 true);
276 TEST_F(PostTaskTest, OneTaskPerReload) {
277 Run(10000, 1);
280 TEST_F(PostTaskTest, TenTasksPerReload) {
281 Run(10000, 10);
284 TEST_F(PostTaskTest, OneHundredTasksPerReload) {
285 Run(1000, 100);
288 } // namespace base