Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(142)

Side by Side Diff: base/message_loop/message_pump_perftest.cc

Issue 551183002: Microbenchmark for the cost of posting tasks to different pump types (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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.
4
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"
17
18 #if defined(OS_ANDROID)
19 #include "base/android/java_handler_thread.h"
20 #endif
21
22 namespace base {
23 namespace {
24
25 class ScheduleWorkTest : public testing::Test {
26 public:
27 ScheduleWorkTest() : counter_(0) {}
28
29 void Increment(uint64_t amount) { counter_ += amount; }
30
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++;
44 }
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));
51
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));
62 }
63
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
71 {
72 target_.reset(new Thread("target"));
73 target_->StartWithOptions(Thread::Options(target_type, 0u));
74 }
75
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]);
81
82 for (int i = 0; i < num_scheduling_threads; ++i) {
83 scheduling_threads.push_back(new Thread("posting thread"));
84 scheduling_threads[i]->Start();
85 }
86
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));
91 }
92
93 for (int i = 0; i < num_scheduling_threads; ++i) {
94 scheduling_threads[i]->Stop();
95 }
96 #if defined(OS_ANDROID)
97 if (target_type == MessageLoop::TYPE_JAVA) {
98 java_thread_->Stop();
99 java_thread_.reset();
100 } else
101 #endif
102 {
103 target_->Stop();
104 target_.reset();
105 }
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]);
115 }
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",
124 "",
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);
151 }
152 }
153
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();
160 }
161
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_;
172
173 static const size_t kTargetTimeSec = 5;
174 static const size_t kBatchSize = 1000;
175 };
176
177 TEST_F(ScheduleWorkTest, ThreadTimeToIOFromOneThread) {
178 ScheduleWork(MessageLoop::TYPE_IO, 1);
179 }
180
181 TEST_F(ScheduleWorkTest, ThreadTimeToIOFromTwoThreads) {
182 ScheduleWork(MessageLoop::TYPE_IO, 2);
183 }
184
185 TEST_F(ScheduleWorkTest, ThreadTimeToIOFromFourThreads) {
186 ScheduleWork(MessageLoop::TYPE_IO, 4);
187 }
188
189 TEST_F(ScheduleWorkTest, ThreadTimeToUIFromOneThread) {
190 ScheduleWork(MessageLoop::TYPE_UI, 1);
191 }
192
193 TEST_F(ScheduleWorkTest, ThreadTimeToUIFromTwoThreads) {
194 ScheduleWork(MessageLoop::TYPE_UI, 2);
195 }
196
197 TEST_F(ScheduleWorkTest, ThreadTimeToUIFromFourThreads) {
198 ScheduleWork(MessageLoop::TYPE_UI, 4);
199 }
200
201 TEST_F(ScheduleWorkTest, ThreadTimeToDefaultFromOneThread) {
202 ScheduleWork(MessageLoop::TYPE_DEFAULT, 1);
203 }
204
205 TEST_F(ScheduleWorkTest, ThreadTimeToDefaultFromTwoThreads) {
206 ScheduleWork(MessageLoop::TYPE_DEFAULT, 2);
207 }
208
209 TEST_F(ScheduleWorkTest, ThreadTimeToDefaultFromFourThreads) {
210 ScheduleWork(MessageLoop::TYPE_DEFAULT, 4);
211 }
212
213 #if defined(OS_ANDROID)
214 TEST_F(ScheduleWorkTest, ThreadTimeToJavaFromOneThread) {
215 ScheduleWork(MessageLoop::TYPE_JAVA, 1);
216 }
217
218 TEST_F(ScheduleWorkTest, ThreadTimeToJavaFromTwoThreads) {
219 ScheduleWork(MessageLoop::TYPE_JAVA, 2);
220 }
221
222 TEST_F(ScheduleWorkTest, ThreadTimeToJavaFromFourThreads) {
223 ScheduleWork(MessageLoop::TYPE_JAVA, 4);
224 }
225 #endif
226
227 static void DoNothing() {
228 }
229
230 class FakeMessagePump : public MessagePump {
231 public:
232 FakeMessagePump() {}
233 virtual ~FakeMessagePump() {}
234
235 virtual void Run(Delegate* delegate) OVERRIDE {}
236
237 virtual void Quit() OVERRIDE {}
238 virtual void ScheduleWork() OVERRIDE {}
239 virtual void ScheduleDelayedWork(
240 const TimeTicks& delayed_work_time) OVERRIDE {}
241 };
242
243 class PostTaskTest : public testing::Test {
244 public:
245 void Run(int batch_size, int tasks_per_reload) {
246 base::TimeTicks start = base::TimeTicks::HighResNow();
247 base::TimeTicks now;
248 MessageLoop loop(scoped_ptr<MessagePump>(new FakeMessagePump));
249 scoped_refptr<internal::IncomingTaskQueue> queue(
250 new internal::IncomingTaskQueue(&loop));
251 uint32_t num_posted = 0;
252 do {
253 for (int i = 0; i < batch_size; ++i) {
254 for (int j = 0; j < tasks_per_reload; ++j) {
255 queue->AddToIncomingQueue(
256 FROM_HERE, base::Bind(&DoNothing), base::TimeDelta(), false);
257 num_posted++;
258 }
259 TaskQueue loop_local_queue;
260 queue->ReloadWorkQueue(&loop_local_queue);
261 while (!loop_local_queue.empty()) {
262 PendingTask t = loop_local_queue.front();
263 loop_local_queue.pop();
264 loop.RunTask(t);
265 }
266 }
267
268 now = base::TimeTicks::HighResNow();
269 } while (now - start < base::TimeDelta::FromSeconds(5));
270 std::string trace = StringPrintf("%d_tasks_per_reload", tasks_per_reload);
271 perf_test::PrintResult(
272 "task",
273 "",
274 trace,
275 (now - start).InMicroseconds() / static_cast<double>(num_posted),
276 "us/task",
277 true);
278 }
279 };
280
281 TEST_F(PostTaskTest, OneTaskPerReload) {
282 Run(10000, 1);
283 }
284
285 TEST_F(PostTaskTest, TenTasksPerReload) {
286 Run(10000, 10);
287 }
288
289 TEST_F(PostTaskTest, OneHundredTasksPerReload) {
290 Run(1000, 100);
291 }
292
293 } // namespace
294 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698