blob: 7a8fb31cae909a55348430cd9b667291dd9de021 [file] [log] [blame]
jamesr2e146d72014-09-29 21:12:441// 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.
4
avi9b6f42932015-12-26 22:15:145#include <stddef.h>
6#include <stdint.h>
7
jamesr2e146d72014-09-29 21:12:448#include "base/bind.h"
Peter Kasting383640f52018-02-13 06:22:409#include "base/bind_helpers.h"
jamesr2e146d72014-09-29 21:12:4410#include "base/format_macros.h"
dcheng093de9b2016-04-04 21:25:5111#include "base/memory/ptr_util.h"
Alexander Timin4f9c35c2018-11-01 20:15:2012#include "base/message_loop/message_loop.h"
Carlos Caballero14712af92019-04-17 16:13:0113#include "base/message_loop/message_loop_current.h"
Carlos Caballerodd8bf7b042019-07-30 14:14:1514#include "base/message_loop/message_pump_type.h"
fdoray10224582016-06-30 18:17:3915#include "base/single_thread_task_runner.h"
jamesr2e146d72014-09-29 21:12:4416#include "base/strings/stringprintf.h"
17#include "base/synchronization/condition_variable.h"
18#include "base/synchronization/lock.h"
19#include "base/synchronization/waitable_event.h"
Carlos Caballero14712af92019-04-17 16:13:0120#include "base/task/sequence_manager/sequence_manager_impl.h"
jamesr2e146d72014-09-29 21:12:4421#include "base/threading/thread.h"
22#include "base/time/time.h"
23#include "build/build_config.h"
24#include "testing/gtest/include/gtest/gtest.h"
25#include "testing/perf/perf_test.h"
26
27#if defined(OS_ANDROID)
28#include "base/android/java_handler_thread.h"
29#endif
30
31namespace base {
Alex Clarkee1cc1bb2019-06-06 17:24:2532namespace {
33
34#if defined(OS_ANDROID)
35class JavaHandlerThreadForTest : public android::JavaHandlerThread {
36 public:
37 explicit JavaHandlerThreadForTest(const char* name)
38 : android::JavaHandlerThread(name, base::ThreadPriority::NORMAL) {}
39
Gabriel Charette35f26252019-08-12 12:01:2040 using android::JavaHandlerThread::state;
41 using android::JavaHandlerThread::State;
Alex Clarkee1cc1bb2019-06-06 17:24:2542};
43#endif
44
45} // namespace
jamesr2e146d72014-09-29 21:12:4446
47class ScheduleWorkTest : public testing::Test {
48 public:
49 ScheduleWorkTest() : counter_(0) {}
50
fdoraydc2a6592015-10-15 03:46:4051 void SetUp() override {
52 if (base::ThreadTicks::IsSupported())
53 base::ThreadTicks::WaitUntilInitialized();
54 }
55
jamesr2e146d72014-09-29 21:12:4456 void Increment(uint64_t amount) { counter_ += amount; }
57
58 void Schedule(int index) {
charliea3be839702015-01-26 17:35:4159 base::TimeTicks start = base::TimeTicks::Now();
miu1ab506a2015-05-29 23:57:1260 base::ThreadTicks thread_start;
61 if (ThreadTicks::IsSupported())
62 thread_start = base::ThreadTicks::Now();
jamesr2e146d72014-09-29 21:12:4463 base::TimeDelta minimum = base::TimeDelta::Max();
64 base::TimeDelta maximum = base::TimeDelta();
65 base::TimeTicks now, lastnow = start;
66 uint64_t schedule_calls = 0u;
67 do {
68 for (size_t i = 0; i < kBatchSize; ++i) {
Alex Clarke00c56392019-02-15 20:22:5669 target_message_loop_base()->GetMessagePump()->ScheduleWork();
jamesr2e146d72014-09-29 21:12:4470 schedule_calls++;
71 }
charliea3be839702015-01-26 17:35:4172 now = base::TimeTicks::Now();
jamesr2e146d72014-09-29 21:12:4473 base::TimeDelta laptime = now - lastnow;
74 lastnow = now;
75 minimum = std::min(minimum, laptime);
76 maximum = std::max(maximum, laptime);
77 } while (now - start < base::TimeDelta::FromSeconds(kTargetTimeSec));
78
79 scheduling_times_[index] = now - start;
miu1ab506a2015-05-29 23:57:1280 if (ThreadTicks::IsSupported())
jamesr2e146d72014-09-29 21:12:4481 scheduling_thread_times_[index] =
miu1ab506a2015-05-29 23:57:1282 base::ThreadTicks::Now() - thread_start;
jamesr2e146d72014-09-29 21:12:4483 min_batch_times_[index] = minimum;
84 max_batch_times_[index] = maximum;
Alex Clarke00c56392019-02-15 20:22:5685 target_message_loop_base()->GetTaskRunner()->PostTask(
tzik92b7a422017-04-11 15:00:4486 FROM_HERE, base::BindOnce(&ScheduleWorkTest::Increment,
87 base::Unretained(this), schedule_calls));
jamesr2e146d72014-09-29 21:12:4488 }
89
Carlos Caballerodd8bf7b042019-07-30 14:14:1590 void ScheduleWork(MessagePumpType target_type, int num_scheduling_threads) {
jamesr2e146d72014-09-29 21:12:4491#if defined(OS_ANDROID)
Carlos Caballerodd8bf7b042019-07-30 14:14:1592 if (target_type == MessagePumpType::JAVA) {
Alex Clarkee1cc1bb2019-06-06 17:24:2593 java_thread_.reset(new JavaHandlerThreadForTest("target"));
jamesr2e146d72014-09-29 21:12:4494 java_thread_->Start();
95 } else
96#endif
97 {
Alex Clarke636d6b62019-02-22 01:39:0498 target_.reset(new Thread("test"));
99
100 Thread::Options options(target_type, 0u);
101
102 std::unique_ptr<MessageLoop> message_loop =
103 MessageLoop::CreateUnbound(target_type);
104 message_loop_ = message_loop.get();
105 options.task_environment =
106 new internal::MessageLoopTaskEnvironment(std::move(message_loop));
107 target_->StartWithOptions(options);
amistry7fc519fa2015-08-10 23:50:44108
109 // Without this, it's possible for the scheduling threads to start and run
110 // before the target thread. In this case, the scheduling threads will
111 // call target_message_loop()->ScheduleWork(), which dereferences the
112 // loop's message pump, which is only created after the target thread has
113 // finished starting.
114 target_->WaitUntilThreadStarted();
jamesr2e146d72014-09-29 21:12:44115 }
116
dcheng093de9b2016-04-04 21:25:51117 std::vector<std::unique_ptr<Thread>> scheduling_threads;
jamesr2e146d72014-09-29 21:12:44118 scheduling_times_.reset(new base::TimeDelta[num_scheduling_threads]);
119 scheduling_thread_times_.reset(new base::TimeDelta[num_scheduling_threads]);
120 min_batch_times_.reset(new base::TimeDelta[num_scheduling_threads]);
121 max_batch_times_.reset(new base::TimeDelta[num_scheduling_threads]);
122
123 for (int i = 0; i < num_scheduling_threads; ++i) {
Jeremy Roman9532f252017-08-16 23:27:24124 scheduling_threads.push_back(std::make_unique<Thread>("posting thread"));
jamesr2e146d72014-09-29 21:12:44125 scheduling_threads[i]->Start();
126 }
127
128 for (int i = 0; i < num_scheduling_threads; ++i) {
fdoray6ef45cf2016-08-25 15:36:37129 scheduling_threads[i]->task_runner()->PostTask(
tzik92b7a422017-04-11 15:00:44130 FROM_HERE, base::BindOnce(&ScheduleWorkTest::Schedule,
131 base::Unretained(this), i));
jamesr2e146d72014-09-29 21:12:44132 }
133
134 for (int i = 0; i < num_scheduling_threads; ++i) {
135 scheduling_threads[i]->Stop();
136 }
137#if defined(OS_ANDROID)
Carlos Caballerodd8bf7b042019-07-30 14:14:15138 if (target_type == MessagePumpType::JAVA) {
jamesr2e146d72014-09-29 21:12:44139 java_thread_->Stop();
140 java_thread_.reset();
141 } else
142#endif
143 {
144 target_->Stop();
145 target_.reset();
146 }
147 base::TimeDelta total_time;
148 base::TimeDelta total_thread_time;
149 base::TimeDelta min_batch_time = base::TimeDelta::Max();
150 base::TimeDelta max_batch_time = base::TimeDelta();
151 for (int i = 0; i < num_scheduling_threads; ++i) {
152 total_time += scheduling_times_[i];
153 total_thread_time += scheduling_thread_times_[i];
154 min_batch_time = std::min(min_batch_time, min_batch_times_[i]);
155 max_batch_time = std::max(max_batch_time, max_batch_times_[i]);
156 }
157 std::string trace = StringPrintf(
Carlos Caballerodd8bf7b042019-07-30 14:14:15158 "%d_threads_scheduling_to_%s_pump", num_scheduling_threads,
159 target_type == MessagePumpType::IO
jamesr2e146d72014-09-29 21:12:44160 ? "io"
Carlos Caballerodd8bf7b042019-07-30 14:14:15161 : (target_type == MessagePumpType::UI ? "ui" : "default"));
jamesr2e146d72014-09-29 21:12:44162 perf_test::PrintResult(
163 "task",
164 "",
165 trace,
166 total_time.InMicroseconds() / static_cast<double>(counter_),
167 "us/task",
168 true);
169 perf_test::PrintResult(
170 "task",
171 "_min_batch_time",
172 trace,
173 min_batch_time.InMicroseconds() / static_cast<double>(kBatchSize),
174 "us/task",
175 false);
176 perf_test::PrintResult(
177 "task",
178 "_max_batch_time",
179 trace,
180 max_batch_time.InMicroseconds() / static_cast<double>(kBatchSize),
181 "us/task",
182 false);
miu1ab506a2015-05-29 23:57:12183 if (ThreadTicks::IsSupported()) {
jamesr2e146d72014-09-29 21:12:44184 perf_test::PrintResult(
185 "task",
186 "_thread_time",
187 trace,
188 total_thread_time.InMicroseconds() / static_cast<double>(counter_),
189 "us/task",
190 true);
191 }
192 }
193
Carlos Caballero14712af92019-04-17 16:13:01194 sequence_manager::internal::SequenceManagerImpl* target_message_loop_base() {
jamesr2e146d72014-09-29 21:12:44195#if defined(OS_ANDROID)
Alex Clarkee1cc1bb2019-06-06 17:24:25196 if (java_thread_) {
197 return static_cast<sequence_manager::internal::SequenceManagerImpl*>(
Gabriel Charette35f26252019-08-12 12:01:20198 java_thread_->state()->sequence_manager.get());
Alex Clarkee1cc1bb2019-06-06 17:24:25199 }
jamesr2e146d72014-09-29 21:12:44200#endif
Carlos Caballero14712af92019-04-17 16:13:01201 return MessageLoopCurrent::Get()->GetCurrentSequenceManagerImpl();
jamesr2e146d72014-09-29 21:12:44202 }
203
204 private:
Alex Clarke636d6b62019-02-22 01:39:04205 std::unique_ptr<Thread> target_;
206 MessageLoop* message_loop_;
jamesr2e146d72014-09-29 21:12:44207#if defined(OS_ANDROID)
Alex Clarkee1cc1bb2019-06-06 17:24:25208 std::unique_ptr<JavaHandlerThreadForTest> java_thread_;
jamesr2e146d72014-09-29 21:12:44209#endif
dcheng093de9b2016-04-04 21:25:51210 std::unique_ptr<base::TimeDelta[]> scheduling_times_;
211 std::unique_ptr<base::TimeDelta[]> scheduling_thread_times_;
212 std::unique_ptr<base::TimeDelta[]> min_batch_times_;
213 std::unique_ptr<base::TimeDelta[]> max_batch_times_;
jamesr2e146d72014-09-29 21:12:44214 uint64_t counter_;
215
216 static const size_t kTargetTimeSec = 5;
217 static const size_t kBatchSize = 1000;
218};
219
220TEST_F(ScheduleWorkTest, ThreadTimeToIOFromOneThread) {
Carlos Caballerodd8bf7b042019-07-30 14:14:15221 ScheduleWork(MessagePumpType::IO, 1);
jamesr2e146d72014-09-29 21:12:44222}
223
224TEST_F(ScheduleWorkTest, ThreadTimeToIOFromTwoThreads) {
Carlos Caballerodd8bf7b042019-07-30 14:14:15225 ScheduleWork(MessagePumpType::IO, 2);
jamesr2e146d72014-09-29 21:12:44226}
227
228TEST_F(ScheduleWorkTest, ThreadTimeToIOFromFourThreads) {
Carlos Caballerodd8bf7b042019-07-30 14:14:15229 ScheduleWork(MessagePumpType::IO, 4);
jamesr2e146d72014-09-29 21:12:44230}
231
232TEST_F(ScheduleWorkTest, ThreadTimeToUIFromOneThread) {
Carlos Caballerodd8bf7b042019-07-30 14:14:15233 ScheduleWork(MessagePumpType::UI, 1);
jamesr2e146d72014-09-29 21:12:44234}
235
236TEST_F(ScheduleWorkTest, ThreadTimeToUIFromTwoThreads) {
Carlos Caballerodd8bf7b042019-07-30 14:14:15237 ScheduleWork(MessagePumpType::UI, 2);
jamesr2e146d72014-09-29 21:12:44238}
239
240TEST_F(ScheduleWorkTest, ThreadTimeToUIFromFourThreads) {
Carlos Caballerodd8bf7b042019-07-30 14:14:15241 ScheduleWork(MessagePumpType::UI, 4);
jamesr2e146d72014-09-29 21:12:44242}
243
244TEST_F(ScheduleWorkTest, ThreadTimeToDefaultFromOneThread) {
Carlos Caballerodd8bf7b042019-07-30 14:14:15245 ScheduleWork(MessagePumpType::DEFAULT, 1);
jamesr2e146d72014-09-29 21:12:44246}
247
248TEST_F(ScheduleWorkTest, ThreadTimeToDefaultFromTwoThreads) {
Carlos Caballerodd8bf7b042019-07-30 14:14:15249 ScheduleWork(MessagePumpType::DEFAULT, 2);
jamesr2e146d72014-09-29 21:12:44250}
251
252TEST_F(ScheduleWorkTest, ThreadTimeToDefaultFromFourThreads) {
Carlos Caballerodd8bf7b042019-07-30 14:14:15253 ScheduleWork(MessagePumpType::DEFAULT, 4);
jamesr2e146d72014-09-29 21:12:44254}
255
256#if defined(OS_ANDROID)
257TEST_F(ScheduleWorkTest, ThreadTimeToJavaFromOneThread) {
Carlos Caballerodd8bf7b042019-07-30 14:14:15258 ScheduleWork(MessagePumpType::JAVA, 1);
jamesr2e146d72014-09-29 21:12:44259}
260
261TEST_F(ScheduleWorkTest, ThreadTimeToJavaFromTwoThreads) {
Carlos Caballerodd8bf7b042019-07-30 14:14:15262 ScheduleWork(MessagePumpType::JAVA, 2);
jamesr2e146d72014-09-29 21:12:44263}
264
265TEST_F(ScheduleWorkTest, ThreadTimeToJavaFromFourThreads) {
Carlos Caballerodd8bf7b042019-07-30 14:14:15266 ScheduleWork(MessagePumpType::JAVA, 4);
jamesr2e146d72014-09-29 21:12:44267}
268#endif
269
jamesr2e146d72014-09-29 21:12:44270} // namespace base