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"
24 class ScheduleWorkTest
: public testing::Test
{
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;
40 for (size_t i
= 0; i
< kBatchSize
; ++i
) {
41 target_message_loop()->ScheduleWork();
44 now
= base::TimeTicks::Now();
45 base::TimeDelta laptime
= now
- lastnow
;
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),
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();
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(
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
) {
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
120 : (target_type
== MessageLoop::TYPE_UI
? "ui" : "default"));
121 perf_test::PrintResult(
125 total_time
.InMicroseconds() / static_cast<double>(counter_
),
128 perf_test::PrintResult(
132 min_batch_time
.InMicroseconds() / static_cast<double>(kBatchSize
),
135 perf_test::PrintResult(
139 max_batch_time
.InMicroseconds() / static_cast<double>(kBatchSize
),
142 if (ThreadTicks::IsSupported()) {
143 perf_test::PrintResult(
147 total_thread_time
.InMicroseconds() / static_cast<double>(counter_
),
153 MessageLoop
* target_message_loop() {
154 #if defined(OS_ANDROID)
156 return java_thread_
->message_loop();
158 return target_
->message_loop();
162 scoped_ptr
<Thread
> target_
;
163 #if defined(OS_ANDROID)
164 scoped_ptr
<android::JavaHandlerThread
> java_thread_
;
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_
;
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);
226 class FakeMessagePump
: public MessagePump
{
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
{
240 void Run(int batch_size
, int tasks_per_reload
) {
241 base::TimeTicks start
= 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;
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);
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();
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(
270 (now
- start
).InMicroseconds() / static_cast<double>(num_posted
),
276 TEST_F(PostTaskTest
, OneTaskPerReload
) {
280 TEST_F(PostTaskTest
, TenTasksPerReload
) {
284 TEST_F(PostTaskTest
, OneHundredTasksPerReload
) {