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.
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"
25 class ScheduleWorkTest
: public testing::Test
{
27 ScheduleWorkTest() : counter_(0) {}
29 void Increment(uint64_t amount
) { counter_
+= amount
; }
31 void Schedule(int index
) {
32 base::TimeTicks start
= base::TimeTicks::Now();
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;
41 for (size_t i
= 0; i
< kBatchSize
; ++i
) {
42 target_message_loop()->ScheduleWork();
45 now
= base::TimeTicks::Now();
46 base::TimeDelta laptime
= now
- lastnow
;
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),
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();
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(
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
) {
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
121 : (target_type
== MessageLoop::TYPE_UI
? "ui" : "default"));
122 perf_test::PrintResult(
126 total_time
.InMicroseconds() / static_cast<double>(counter_
),
129 perf_test::PrintResult(
133 min_batch_time
.InMicroseconds() / static_cast<double>(kBatchSize
),
136 perf_test::PrintResult(
140 max_batch_time
.InMicroseconds() / static_cast<double>(kBatchSize
),
143 if (TimeTicks::IsThreadNowSupported()) {
144 perf_test::PrintResult(
148 total_thread_time
.InMicroseconds() / static_cast<double>(counter_
),
154 MessageLoop
* target_message_loop() {
155 #if defined(OS_ANDROID)
157 return java_thread_
->message_loop();
159 return target_
->message_loop();
163 scoped_ptr
<Thread
> target_
;
164 #if defined(OS_ANDROID)
165 scoped_ptr
<android::JavaHandlerThread
> java_thread_
;
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_
;
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);
227 static void DoNothing() {
230 class FakeMessagePump
: public MessagePump
{
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
{
244 void Run(int batch_size
, int tasks_per_reload
) {
245 base::TimeTicks start
= 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;
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);
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();
267 now
= base::TimeTicks::Now();
268 } while (now
- start
< base::TimeDelta::FromSeconds(5));
269 std::string trace
= StringPrintf("%d_tasks_per_reload", tasks_per_reload
);
270 perf_test::PrintResult(
274 (now
- start
).InMicroseconds() / static_cast<double>(num_posted
),
280 TEST_F(PostTaskTest
, OneTaskPerReload
) {
284 TEST_F(PostTaskTest
, TenTasksPerReload
) {
288 TEST_F(PostTaskTest
, OneHundredTasksPerReload
) {