blob: 83221181847079802f42625a401f0270480eed54 [file] [log] [blame]
alexclarkef02cff06d2015-03-06 12:11:501// Copyright 2015 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
Greg Kraynov8ae7ac3232018-07-04 14:56:275#include "base/task/sequence_manager/sequence_manager.h"
alexclarkef02cff06d2015-03-06 12:11:506
avif57136c12015-12-25 23:27:457#include <stddef.h>
Gyuyoung Kim8a77f8c2017-09-27 12:24:168#include <memory>
avif57136c12015-12-25 23:27:459
alexclarkef02cff06d2015-03-06 12:11:5010#include "base/bind.h"
Alexander Timin4f9c35c2018-11-01 20:15:2011#include "base/message_loop/message_loop.h"
Greg Kraynov99693982018-08-09 09:05:1912#include "base/message_loop/message_pump_default.h"
fdoray2df4a9e2016-07-18 23:47:1613#include "base/run_loop.h"
Francois Doraye2bfbf322018-11-19 14:04:4514#include "base/sequence_checker.h"
Gabriel Charette5ff87ce2017-05-16 18:03:4515#include "base/single_thread_task_runner.h"
alexclarke5768f7d2016-10-06 13:23:3916#include "base/strings/stringprintf.h"
Alex Clarked4b78b82018-10-19 15:48:5317#include "base/synchronization/condition_variable.h"
18#include "base/task/post_task.h"
Greg Kraynov8ae7ac3232018-07-04 14:56:2719#include "base/task/sequence_manager/task_queue_impl.h"
Greg Kraynov1d6ba6262018-07-11 18:29:4820#include "base/task/sequence_manager/test/mock_time_domain.h"
21#include "base/task/sequence_manager/test/sequence_manager_for_test.h"
22#include "base/task/sequence_manager/test/test_task_queue.h"
23#include "base/task/sequence_manager/test/test_task_time_observer.h"
Greg Kraynov3634ea32018-08-07 08:43:3824#include "base/task/sequence_manager/thread_controller_with_message_pump_impl.h"
Alex Clarked4b78b82018-10-19 15:48:5325#include "base/task/task_traits.h"
Gabriel Charette52fa3ae2019-04-15 21:44:3726#include "base/task/thread_pool/thread_pool.h"
27#include "base/task/thread_pool/thread_pool_impl.h"
alexclarkef02cff06d2015-03-06 12:11:5028#include "base/threading/thread.h"
fdoray19e49e92016-09-30 20:42:1629#include "base/threading/thread_task_runner_handle.h"
alexclarkef65eb2d2015-11-03 18:24:1630#include "base/time/default_tick_clock.h"
Alex Clarkefd959592018-10-30 15:32:4631#include "build/build_config.h"
alexclarkef02cff06d2015-03-06 12:11:5032#include "testing/gtest/include/gtest/gtest.h"
33#include "testing/perf/perf_test.h"
34
Greg Kraynov8f4784462018-05-14 10:08:2135namespace base {
36namespace sequence_manager {
Sami Kyostila2bde91432018-11-07 01:43:4637namespace {
38const int kNumTasks = 1000000;
39}
alexclarkef02cff06d2015-03-06 12:11:5040
Greg Kraynovfd592fd2018-06-29 18:37:3741// To reduce noise related to the OS timer, we use a mock time domain to
alexclarke5768f7d2016-10-06 13:23:3942// fast forward the timers.
Greg Kraynovfd592fd2018-06-29 18:37:3743class PerfTestTimeDomain : public MockTimeDomain {
alexclarke5768f7d2016-10-06 13:23:3944 public:
Greg Kraynovfd592fd2018-06-29 18:37:3745 PerfTestTimeDomain() : MockTimeDomain(TimeTicks::Now()) {}
Chris Watkins6c3881792018-01-09 04:05:1846 ~PerfTestTimeDomain() override = default;
alexclarke5768f7d2016-10-06 13:23:3947
Greg Kraynov8f4784462018-05-14 10:08:2148 Optional<TimeDelta> DelayTillNextTask(LazyNow* lazy_now) override {
Greg Kraynovf8240bda2018-06-28 17:42:3649 Optional<TimeTicks> run_time = NextScheduledRunTime();
50 if (!run_time)
51 return nullopt;
Greg Kraynovfd592fd2018-06-29 18:37:3752 SetNowTicks(*run_time);
53 // Makes SequenceManager to continue immediately.
54 return TimeDelta();
alexclarke5768f7d2016-10-06 13:23:3955 }
56
Greg Kraynove28bfbc2018-06-29 14:53:3757 void SetNextDelayedDoWork(LazyNow* lazy_now, TimeTicks run_time) override {
alexclarkeefc263f2016-10-20 13:51:4958 // De-dupe DoWorks.
altimin8053f442017-04-11 15:05:0859 if (NumberOfScheduledWakeUps() == 1u)
alexclarke5768f7d2016-10-06 13:23:3960 RequestDoWork();
61 }
62
Greg Kraynovfd592fd2018-06-29 18:37:3763 private:
alexclarke5768f7d2016-10-06 13:23:3964 DISALLOW_COPY_AND_ASSIGN(PerfTestTimeDomain);
65};
66
Gabriel Charette75110a52019-01-29 22:39:3367// TODO(crbug.com/891670): This can be simplified after the transition away from
68// the old base::MessageLoop.
69enum class PerfTestType {
70 // A SequenceManager on top of a MessageLoop (which is SequenceManager based).
71 // This configuration is now strictly overkill.
72 kUseSequenceManagerWithMessageLoop,
73 kUseSequenceManagerWithUIMessageLoop,
74 kUseSequenceManagerWithIOMessageLoop,
75
76 // A SequenceManager with a ThreadControllerWithMessagePumpImpl driving the
77 // thread.
78 kUseSequenceManagerWithMessagePump,
79 kUseSequenceManagerWithUIMessagePump,
80 kUseSequenceManagerWithIOMessagePump,
81 kUseSequenceManagerWithMessagePumpAndRandomSampling,
82
83 // A SequenceManager backed base::MessageLoop (now the default and only
84 // base::MessageLoop configuration).
85 kUseMessageLoop,
86 kUseUIMessageLoop,
87 kUseIOMessageLoop,
88
Gabriel Charette3e2898f2019-05-01 14:55:0189 // A SingleThreadTaskRunner in the thread pool.
90 kUseSingleThreadInThreadPool,
Greg Kraynov3634ea32018-08-07 08:43:3891};
92
Alex Clarke3cf99942018-10-31 11:57:0393// Customization point for SequenceManagerPerfTest which allows us to test
94// various implementations.
95class PerfTestDelegate {
alexclarkef02cff06d2015-03-06 12:11:5096 public:
Alex Clarke3cf99942018-10-31 11:57:0397 virtual ~PerfTestDelegate() = default;
alexclarkef02cff06d2015-03-06 12:11:5098
Alex Clarke3cf99942018-10-31 11:57:0399 virtual const char* GetName() const = 0;
Greg Kraynov3634ea32018-08-07 08:43:38100
Alex Clarke3cf99942018-10-31 11:57:03101 virtual bool VirtualTimeIsSupported() const = 0;
Greg Kraynov3634ea32018-08-07 08:43:38102
Alex Clarke3cf99942018-10-31 11:57:03103 virtual bool MultipleQueuesSupported() const = 0;
Greg Kraynov3634ea32018-08-07 08:43:38104
Alex Clarke3cf99942018-10-31 11:57:03105 virtual scoped_refptr<TaskRunner> CreateTaskRunner() = 0;
Greg Kraynov3634ea32018-08-07 08:43:38106
Alex Clarke3cf99942018-10-31 11:57:03107 virtual void WaitUntilDone() = 0;
108
109 virtual void SignalDone() = 0;
110};
111
112class BaseSequenceManagerPerfTestDelegate : public PerfTestDelegate {
113 public:
114 BaseSequenceManagerPerfTestDelegate() {}
115
116 ~BaseSequenceManagerPerfTestDelegate() override = default;
117
118 bool VirtualTimeIsSupported() const override { return true; }
119
120 bool MultipleQueuesSupported() const override { return true; }
121
122 scoped_refptr<TaskRunner> CreateTaskRunner() override {
123 scoped_refptr<TestTaskQueue> task_queue =
Alex Clarkea94872272018-11-20 09:42:10124 manager_->CreateTaskQueueWithType<TestTaskQueue>(
Alex Clarke3cf99942018-10-31 11:57:03125 TaskQueue::Spec("test").SetTimeDomain(time_domain_.get()));
126 owned_task_queues_.push_back(task_queue);
127 return task_queue->task_runner();
Greg Kraynov3634ea32018-08-07 08:43:38128 }
129
Alex Clarke3cf99942018-10-31 11:57:03130 void WaitUntilDone() override {
131 run_loop_.reset(new RunLoop());
132 run_loop_->Run();
Greg Kraynov3634ea32018-08-07 08:43:38133 }
134
Alex Clarke3cf99942018-10-31 11:57:03135 void SignalDone() override { run_loop_->Quit(); }
136
137 SequenceManager* GetManager() const { return manager_.get(); }
138
139 void SetSequenceManager(std::unique_ptr<SequenceManager> manager) {
140 manager_ = std::move(manager);
141 time_domain_ = std::make_unique<PerfTestTimeDomain>();
142 manager_->RegisterTimeDomain(time_domain_.get());
143 }
144
145 void ShutDown() {
146 owned_task_queues_.clear();
147 manager_->UnregisterTimeDomain(time_domain_.get());
148 manager_.reset();
149 }
150
151 private:
152 std::unique_ptr<SequenceManager> manager_;
153 std::unique_ptr<TimeDomain> time_domain_;
154 std::unique_ptr<RunLoop> run_loop_;
155 std::vector<scoped_refptr<TestTaskQueue>> owned_task_queues_;
156};
157
158template <class MessageLoopType>
159class SequenceManagerWithMessageLoopPerfTestDelegate
160 : public BaseSequenceManagerPerfTestDelegate {
161 public:
162 explicit SequenceManagerWithMessageLoopPerfTestDelegate(const char* name)
163 : name_(name), message_loop_(new MessageLoopType()) {
Carlos Caballerob9fb1b1e2019-04-01 11:49:17164 SetSequenceManager(CreateSequenceManagerOnCurrentThread(
Alex Clarke5f3d461b2019-04-29 14:23:11165 SequenceManager::Settings::Builder()
166 .SetRandomisedSamplingEnabled(false)
167 .Build()));
Alex Clarke3cf99942018-10-31 11:57:03168 }
169
170 ~SequenceManagerWithMessageLoopPerfTestDelegate() override { ShutDown(); }
171
172 const char* GetName() const override { return name_; }
173
174 private:
175 const char* const name_;
176 std::unique_ptr<MessageLoop> message_loop_;
177};
178
179class SequenceManagerWithMessagePumpPerfTestDelegate
180 : public BaseSequenceManagerPerfTestDelegate {
181 public:
Karolina Soltys1dccaeb2018-12-05 15:20:01182 SequenceManagerWithMessagePumpPerfTestDelegate(
183 const char* name,
184 MessageLoop::Type type,
185 bool randomised_sampling_enabled = false)
Alex Clarke3cf99942018-10-31 11:57:03186 : name_(name) {
Alex Clarke5f3d461b2019-04-29 14:23:11187 auto settings =
188 SequenceManager::Settings::Builder()
189 .SetRandomisedSamplingEnabled(randomised_sampling_enabled)
190 .Build();
Alex Clarke3cf99942018-10-31 11:57:03191 SetSequenceManager(SequenceManagerForTest::Create(
Greg Kraynov3634ea32018-08-07 08:43:38192 std::make_unique<internal::ThreadControllerWithMessagePumpImpl>(
Alex Clarke5f3d461b2019-04-29 14:23:11193 MessageLoop ::CreateMessagePumpForType(type), settings),
194 std::move(settings)));
Alex Clarke3cf99942018-10-31 11:57:03195
Alex Clarked4b78b82018-10-19 15:48:53196 // ThreadControllerWithMessagePumpImpl doesn't provide a default task
197 // runner.
Greg Kraynov3634ea32018-08-07 08:43:38198 scoped_refptr<TaskQueue> default_task_queue =
Alex Clarkea94872272018-11-20 09:42:10199 GetManager()->template CreateTaskQueueWithType<TestTaskQueue>(
Alex Clarke3cf99942018-10-31 11:57:03200 TaskQueue::Spec("default"));
201 GetManager()->SetDefaultTaskRunner(default_task_queue->task_runner());
fdoraydc2a6592015-10-15 03:46:40202 }
203
Alex Clarke3cf99942018-10-31 11:57:03204 ~SequenceManagerWithMessagePumpPerfTestDelegate() override { ShutDown(); }
205
206 const char* GetName() const override { return name_; }
207
208 private:
209 const char* const name_;
210};
211
212class MessageLoopPerfTestDelegate : public PerfTestDelegate {
213 public:
214 MessageLoopPerfTestDelegate(const char* name,
215 std::unique_ptr<MessageLoop> message_loop)
216 : name_(name), message_loop_(std::move(message_loop)) {}
217
218 ~MessageLoopPerfTestDelegate() override = default;
219
220 const char* GetName() const override { return name_; }
221
222 bool VirtualTimeIsSupported() const override { return false; }
223
224 bool MultipleQueuesSupported() const override { return false; }
225
226 scoped_refptr<TaskRunner> CreateTaskRunner() override {
227 return message_loop_->task_runner();
Alex Clarkefd959592018-10-30 15:32:46228 }
Alex Clarked4b78b82018-10-19 15:48:53229
Alex Clarke3cf99942018-10-31 11:57:03230 void WaitUntilDone() override {
231 run_loop_.reset(new RunLoop());
232 run_loop_->Run();
233 }
234
235 void SignalDone() override { run_loop_->Quit(); }
236
237 private:
238 const char* const name_;
239 std::unique_ptr<MessageLoop> message_loop_;
240 std::unique_ptr<RunLoop> run_loop_;
241};
242
Gabriel Charette3e2898f2019-05-01 14:55:01243class SingleThreadInThreadPoolPerfTestDelegate : public PerfTestDelegate {
Alex Clarke3cf99942018-10-31 11:57:03244 public:
Gabriel Charette3e2898f2019-05-01 14:55:01245 SingleThreadInThreadPoolPerfTestDelegate() : done_cond_(&done_lock_) {
Gabriel Charette43fd3702019-05-29 16:36:51246 ThreadPoolInstance::Set(
Gabriel Charette52fa3ae2019-04-15 21:44:37247 std::make_unique<::base::internal::ThreadPoolImpl>("Test"));
Gabriel Charette43fd3702019-05-29 16:36:51248 ThreadPoolInstance::Get()->StartWithDefaultParams();
Alex Clarked4b78b82018-10-19 15:48:53249 }
250
Gabriel Charette3e2898f2019-05-01 14:55:01251 ~SingleThreadInThreadPoolPerfTestDelegate() override {
Gabriel Charette43fd3702019-05-29 16:36:51252 ThreadPoolInstance::Get()->JoinForTesting();
253 ThreadPoolInstance::Set(nullptr);
Alex Clarked4b78b82018-10-19 15:48:53254 }
255
Alex Clarke3cf99942018-10-31 11:57:03256 const char* GetName() const override {
Gabriel Charette3e2898f2019-05-01 14:55:01257 return " single thread in ThreadPool ";
alexclarke5768f7d2016-10-06 13:23:39258 }
259
Alex Clarke3cf99942018-10-31 11:57:03260 bool VirtualTimeIsSupported() const override { return false; }
261
262 bool MultipleQueuesSupported() const override { return false; }
263
264 scoped_refptr<TaskRunner> CreateTaskRunner() override {
265 return CreateSingleThreadTaskRunnerWithTraits(
266 {TaskPriority::USER_BLOCKING});
Alex Clarked4b78b82018-10-19 15:48:53267 }
268
Alex Clarke3cf99942018-10-31 11:57:03269 void WaitUntilDone() override {
270 AutoLock auto_lock(done_lock_);
271 done_cond_.Wait();
Alex Clarked4b78b82018-10-19 15:48:53272 }
273
Alex Clarke3cf99942018-10-31 11:57:03274 void SignalDone() override {
275 AutoLock auto_lock(done_lock_);
276 done_cond_.Signal();
alexclarkef02cff06d2015-03-06 12:11:50277 }
278
Alex Clarke3cf99942018-10-31 11:57:03279 private:
280 Lock done_lock_;
281 ConditionVariable done_cond_;
282};
283
284class TestCase {
285 public:
286 // |delegate| is assumed to outlive TestCase.
287 explicit TestCase(PerfTestDelegate* delegate) : delegate_(delegate) {}
288
289 virtual ~TestCase() = default;
290
291 virtual void Start() = 0;
292
293 protected:
294 PerfTestDelegate* const delegate_; // NOT OWNED
295};
296
297class TaskSource {
298 public:
299 virtual ~TaskSource() = default;
300
301 virtual void Start() = 0;
302};
303
304class SameThreadTaskSource : public TaskSource {
305 public:
306 SameThreadTaskSource(std::vector<scoped_refptr<TaskRunner>> task_runners,
307 size_t num_tasks)
308 : num_queues_(task_runners.size()),
309 num_tasks_(num_tasks),
310 task_closure_(
311 BindRepeating(&SameThreadTaskSource::TestTask, Unretained(this))),
Francois Doraye2bfbf322018-11-19 14:04:45312 task_runners_(std::move(task_runners)) {
313 DETACH_FROM_SEQUENCE(sequence_checker_);
314 }
Alex Clarke3cf99942018-10-31 11:57:03315
316 void Start() override {
317 num_tasks_in_flight_ = 1;
318 num_tasks_to_post_ = num_tasks_;
319 num_tasks_to_run_ = num_tasks_;
Francois Doraye2bfbf322018-11-19 14:04:45320 // Post the initial task instead of running it synchronously to ensure that
321 // all invocations happen on the same sequence.
322 PostTask(0);
Alex Clarke3cf99942018-10-31 11:57:03323 }
324
325 protected:
326 virtual void PostTask(unsigned int queue) = 0;
327
328 virtual void SignalDone() = 0;
329
330 void TestTask() {
Francois Doraye2bfbf322018-11-19 14:04:45331 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
332
alexclarkef02cff06d2015-03-06 12:11:50333 if (--num_tasks_to_run_ == 0) {
Alex Clarked4b78b82018-10-19 15:48:53334 SignalDone();
alexclarke5768f7d2016-10-06 13:23:39335 return;
alexclarkef02cff06d2015-03-06 12:11:50336 }
337
338 num_tasks_in_flight_--;
339 // NOTE there are only up to max_tasks_in_flight_ pending delayed tasks at
340 // any one time. Thanks to the lower_num_tasks_to_post going to zero if
341 // there are a lot of tasks in flight, the total number of task in flight at
342 // any one time is very variable.
343 unsigned int lower_num_tasks_to_post =
344 num_tasks_in_flight_ < (max_tasks_in_flight_ / 2) ? 1 : 0;
345 unsigned int max_tasks_to_post =
346 num_tasks_to_post_ % 2 ? lower_num_tasks_to_post : 10;
347 for (unsigned int i = 0;
348 i < max_tasks_to_post && num_tasks_in_flight_ < max_tasks_in_flight_ &&
skyostil0bbc9d22015-09-29 13:07:23349 num_tasks_to_post_ > 0;
alexclarkef02cff06d2015-03-06 12:11:50350 i++) {
351 // Choose a queue weighted towards queue 0.
352 unsigned int queue = num_tasks_to_post_ % (num_queues_ + 1);
353 if (queue == num_queues_) {
354 queue = 0;
355 }
Alex Clarke3cf99942018-10-31 11:57:03356 PostTask(queue);
357 num_tasks_in_flight_++;
358 num_tasks_to_post_--;
359 }
360 }
361
362 const size_t num_queues_;
363 const size_t num_tasks_;
364 const RepeatingClosure task_closure_;
365 const std::vector<scoped_refptr<TaskRunner>> task_runners_;
366 const unsigned int max_tasks_in_flight_ = 200;
367 unsigned int num_tasks_in_flight_;
368 unsigned int num_tasks_to_post_;
369 unsigned int num_tasks_to_run_;
Francois Doraye2bfbf322018-11-19 14:04:45370 SEQUENCE_CHECKER(sequence_checker_);
Alex Clarke3cf99942018-10-31 11:57:03371};
372
373class CrossThreadTaskSource : public TaskSource {
374 public:
375 CrossThreadTaskSource(std::vector<scoped_refptr<TaskRunner>> task_runners,
376 size_t num_tasks)
377 : num_queues_(task_runners.size()),
378 num_tasks_(num_tasks),
379 task_closure_(
380 BindRepeating(&CrossThreadTaskSource::TestTask, Unretained(this))),
381 task_runners_(std::move(task_runners)) {}
382
383 void Start() override {
384 num_tasks_in_flight_ = 0;
385 num_tasks_to_run_ = num_tasks_;
386
387 for (size_t i = 0; i < num_tasks_; i++) {
388 while (num_tasks_in_flight_.load(std::memory_order_acquire) >
389 max_tasks_in_flight_) {
Sami Kyostila2bde91432018-11-07 01:43:46390 PlatformThread::YieldCurrentThread();
Alex Clarke3cf99942018-10-31 11:57:03391 }
392 // Choose a queue weighted towards queue 0.
393 unsigned int queue = i % (num_queues_ + 1);
394 if (queue == num_queues_) {
395 queue = 0;
396 }
397 PostTask(queue);
398 num_tasks_in_flight_++;
399 }
400 }
401
402 protected:
403 virtual void PostTask(unsigned int queue) = 0;
404
405 // Will be called on the main thread.
406 virtual void SignalDone() = 0;
407
408 void TestTask() {
409 if (num_tasks_to_run_.fetch_sub(1) == 1) {
410 SignalDone();
411 return;
412 }
413 num_tasks_in_flight_--;
414 }
415
416 const size_t num_queues_;
417 const size_t num_tasks_;
418 const RepeatingClosure task_closure_;
419 const std::vector<scoped_refptr<TaskRunner>> task_runners_;
420 const unsigned int max_tasks_in_flight_ = 200;
421 std::atomic<unsigned int> num_tasks_in_flight_;
422 std::atomic<unsigned int> num_tasks_to_run_;
423};
424
425class SingleThreadImmediateTestCase : public TestCase {
426 public:
427 SingleThreadImmediateTestCase(
428 PerfTestDelegate* delegate,
Sami Kyostila2bde91432018-11-07 01:43:46429 std::vector<scoped_refptr<TaskRunner>> task_runners)
Alex Clarke3cf99942018-10-31 11:57:03430 : TestCase(delegate),
431 task_source_(std::make_unique<SingleThreadImmediateTaskSource>(
432 delegate,
433 std::move(task_runners),
Sami Kyostila2bde91432018-11-07 01:43:46434 kNumTasks)) {}
Alex Clarke3cf99942018-10-31 11:57:03435
436 void Start() override { task_source_->Start(); }
437
438 private:
439 class SingleThreadImmediateTaskSource : public SameThreadTaskSource {
440 public:
441 SingleThreadImmediateTaskSource(
442 PerfTestDelegate* delegate,
443 std::vector<scoped_refptr<TaskRunner>> task_runners,
444 size_t num_tasks)
445 : SameThreadTaskSource(std::move(task_runners), num_tasks),
446 delegate_(delegate) {}
447
448 ~SingleThreadImmediateTaskSource() override = default;
449
450 void PostTask(unsigned int queue) override {
451 task_runners_[queue]->PostTask(FROM_HERE, task_closure_);
452 }
453
454 void SignalDone() override { delegate_->SignalDone(); }
455
456 PerfTestDelegate* delegate_; // NOT OWNED.
457 };
458
459 const std::unique_ptr<TaskSource> task_source_;
460};
461
462class SingleThreadDelayedTestCase : public TestCase {
463 public:
464 SingleThreadDelayedTestCase(
465 PerfTestDelegate* delegate,
Sami Kyostila2bde91432018-11-07 01:43:46466 std::vector<scoped_refptr<TaskRunner>> task_runners)
Alex Clarke3cf99942018-10-31 11:57:03467 : TestCase(delegate),
468 task_source_(std::make_unique<SingleThreadDelayedTaskSource>(
469 delegate,
470 std::move(task_runners),
Sami Kyostila2bde91432018-11-07 01:43:46471 kNumTasks)) {}
Alex Clarke3cf99942018-10-31 11:57:03472
473 void Start() override { task_source_->Start(); }
474
475 private:
476 class SingleThreadDelayedTaskSource : public SameThreadTaskSource {
477 public:
478 explicit SingleThreadDelayedTaskSource(
479 PerfTestDelegate* delegate,
480 std::vector<scoped_refptr<TaskRunner>> task_runners,
481 size_t num_tasks)
482 : SameThreadTaskSource(std::move(task_runners), num_tasks),
483 delegate_(delegate) {}
484
485 ~SingleThreadDelayedTaskSource() override = default;
486
487 void PostTask(unsigned int queue) override {
alexclarkef02cff06d2015-03-06 12:11:50488 unsigned int delay =
489 num_tasks_to_post_ % 2 ? 1 : (10 + num_tasks_to_post_ % 10);
Alex Clarke3cf99942018-10-31 11:57:03490 task_runners_[queue]->PostDelayedTask(FROM_HERE, task_closure_,
Alex Clarked4b78b82018-10-19 15:48:53491 TimeDelta::FromMilliseconds(delay));
Alex Clarke3cf99942018-10-31 11:57:03492 }
493
494 void SignalDone() override { delegate_->SignalDone(); }
495
496 PerfTestDelegate* delegate_; // NOT OWNED.
497 };
498
499 const std::unique_ptr<TaskSource> task_source_;
500};
501
502class TwoThreadTestCase : public TestCase {
503 public:
504 TwoThreadTestCase(PerfTestDelegate* delegate,
Sami Kyostila2bde91432018-11-07 01:43:46505 std::vector<scoped_refptr<TaskRunner>> task_runners)
Alex Clarke3cf99942018-10-31 11:57:03506 : TestCase(delegate),
507 task_runners_(std::move(task_runners)),
Sami Kyostila2bde91432018-11-07 01:43:46508 num_tasks_(kNumTasks),
Alex Clarke3cf99942018-10-31 11:57:03509 auxiliary_thread_("auxillary thread") {
510 auxiliary_thread_.Start();
511 }
512
513 ~TwoThreadTestCase() override { auxiliary_thread_.Stop(); }
514
515 protected:
516 void Start() override {
517 done_count_ = 0;
518 same_thread_task_source_ =
519 std::make_unique<SingleThreadImmediateTaskSource>(this, task_runners_,
520 num_tasks_ / 2);
521 cross_thread_task_scorce_ =
522 std::make_unique<CrossThreadImmediateTaskSource>(this, task_runners_,
523 num_tasks_ / 2);
524
525 auxiliary_thread_.task_runner()->PostTask(
526 FROM_HERE, base::BindOnce(&CrossThreadImmediateTaskSource::Start,
527 Unretained(cross_thread_task_scorce_.get())));
528 same_thread_task_source_->Start();
529 }
530
531 class SingleThreadImmediateTaskSource : public SameThreadTaskSource {
532 public:
533 SingleThreadImmediateTaskSource(
534 TwoThreadTestCase* two_thread_test_case,
535 std::vector<scoped_refptr<TaskRunner>> task_runners,
536 size_t num_tasks)
537 : SameThreadTaskSource(std::move(task_runners), num_tasks),
538 two_thread_test_case_(two_thread_test_case) {}
539
540 ~SingleThreadImmediateTaskSource() override = default;
541
542 void PostTask(unsigned int queue) override {
543 task_runners_[queue]->PostTask(FROM_HERE, task_closure_);
544 }
545
546 // Will be called on the main thread.
547 void SignalDone() override { two_thread_test_case_->SignalDone(); }
548
549 TwoThreadTestCase* two_thread_test_case_; // NOT OWNED.
550 };
551
552 class CrossThreadImmediateTaskSource : public CrossThreadTaskSource {
553 public:
554 CrossThreadImmediateTaskSource(
555 TwoThreadTestCase* two_thread_test_case,
556 std::vector<scoped_refptr<TaskRunner>> task_runners,
557 size_t num_tasks)
558 : CrossThreadTaskSource(std::move(task_runners), num_tasks),
559 two_thread_test_case_(two_thread_test_case) {}
560
561 ~CrossThreadImmediateTaskSource() override = default;
562
563 void PostTask(unsigned int queue) override {
564 task_runners_[queue]->PostTask(FROM_HERE, task_closure_);
565 }
566
567 // Will be called on the main thread.
568 void SignalDone() override { two_thread_test_case_->SignalDone(); }
569
570 TwoThreadTestCase* two_thread_test_case_; // NOT OWNED.
571 };
572
573 void SignalDone() {
574 if (++done_count_ == 2)
575 delegate_->SignalDone();
576 }
577
578 private:
579 const std::vector<scoped_refptr<TaskRunner>> task_runners_;
580 const size_t num_tasks_;
581 Thread auxiliary_thread_;
582 std::unique_ptr<SingleThreadImmediateTaskSource> same_thread_task_source_;
583 std::unique_ptr<CrossThreadImmediateTaskSource> cross_thread_task_scorce_;
584 int done_count_ = 0;
585};
586
587class SequenceManagerPerfTest : public testing::TestWithParam<PerfTestType> {
588 public:
Gabriel Charette75110a52019-01-29 22:39:33589 SequenceManagerPerfTest() = default;
Alex Clarke3cf99942018-10-31 11:57:03590
Sami Kyostilacf339fd2019-01-28 13:55:07591 void SetUp() override { delegate_ = CreateDelegate(); }
592
Alex Clarke3cf99942018-10-31 11:57:03593 void TearDown() override { delegate_.reset(); }
594
595 std::unique_ptr<PerfTestDelegate> CreateDelegate() {
596 switch (GetParam()) {
597 case PerfTestType::kUseSequenceManagerWithMessageLoop:
598 return std::make_unique<
599 SequenceManagerWithMessageLoopPerfTestDelegate<MessageLoop>>(
600 " SequenceManager with MessageLoop ");
601
Alex Clarke3cf99942018-10-31 11:57:03602 case PerfTestType::kUseSequenceManagerWithUIMessageLoop:
603 return std::make_unique<
604 SequenceManagerWithMessageLoopPerfTestDelegate<MessageLoopForUI>>(
605 " SequenceManager with MessageLoopForUI ");
606
Alex Clarke3cf99942018-10-31 11:57:03607 case PerfTestType::kUseSequenceManagerWithIOMessageLoop:
608 return std::make_unique<
609 SequenceManagerWithMessageLoopPerfTestDelegate<MessageLoopForIO>>(
610 " SequenceManager with MessageLoopForIO ");
611
Gabriel Charette75110a52019-01-29 22:39:33612 case PerfTestType::kUseSequenceManagerWithMessagePump:
613 return std::make_unique<SequenceManagerWithMessagePumpPerfTestDelegate>(
614 " SequenceManager with MessagePumpDefault ",
615 MessageLoop::TYPE_DEFAULT);
616
617 case PerfTestType::kUseSequenceManagerWithUIMessagePump:
618 return std::make_unique<SequenceManagerWithMessagePumpPerfTestDelegate>(
619 " SequenceManager with MessagePumpForUI ", MessageLoop::TYPE_UI);
620
Alex Clarke3cf99942018-10-31 11:57:03621 case PerfTestType::kUseSequenceManagerWithIOMessagePump:
622 return std::make_unique<SequenceManagerWithMessagePumpPerfTestDelegate>(
623 " SequenceManager with MessagePumpForIO ", MessageLoop::TYPE_IO);
624
Gabriel Charette75110a52019-01-29 22:39:33625 case PerfTestType::kUseSequenceManagerWithMessagePumpAndRandomSampling:
626 return std::make_unique<SequenceManagerWithMessagePumpPerfTestDelegate>(
627 " SequenceManager with MessagePumpDefault and random sampling ",
628 MessageLoop::TYPE_DEFAULT, true);
629
Alex Clarke3cf99942018-10-31 11:57:03630 case PerfTestType::kUseMessageLoop:
631 return std::make_unique<MessageLoopPerfTestDelegate>(
632 " MessageLoop ", std::make_unique<MessageLoop>());
633
634 case PerfTestType::kUseUIMessageLoop:
635 return std::make_unique<MessageLoopPerfTestDelegate>(
636 " MessageLoopForUI ", std::make_unique<MessageLoopForUI>());
637
638 case PerfTestType::kUseIOMessageLoop:
639 return std::make_unique<MessageLoopPerfTestDelegate>(
640 " MessageLoopForIO ", std::make_unique<MessageLoopForIO>());
641
Gabriel Charette3e2898f2019-05-01 14:55:01642 case PerfTestType::kUseSingleThreadInThreadPool:
643 return std::make_unique<SingleThreadInThreadPoolPerfTestDelegate>();
Alex Clarke3cf99942018-10-31 11:57:03644
645 default:
646 NOTREACHED();
647 return nullptr;
Alex Clarkea77f1e02018-05-21 09:20:18648 }
649 }
650
Sami Kyostila2bde91432018-11-07 01:43:46651 bool ShouldMeasureQueueScaling() const {
652 // To limit test run time, we only measure multiple queues specific sequence
653 // manager configurations.
654 return delegate_->MultipleQueuesSupported() &&
655 GetParam() == PerfTestType::kUseSequenceManagerWithUIMessagePump;
656 }
657
Alex Clarke3cf99942018-10-31 11:57:03658 std::vector<scoped_refptr<TaskRunner>> CreateTaskRunners(int num) {
659 std::vector<scoped_refptr<TaskRunner>> task_runners;
660 for (int i = 0; i < num; i++) {
661 task_runners.push_back(delegate_->CreateTaskRunner());
Alex Clarkea77f1e02018-05-21 09:20:18662 }
Alex Clarke3cf99942018-10-31 11:57:03663 return task_runners;
alexclarkef02cff06d2015-03-06 12:11:50664 }
665
Alex Clarke3cf99942018-10-31 11:57:03666 void Benchmark(const std::string& trace, TestCase* TestCase) {
Alex Clarked4b78b82018-10-19 15:48:53667 TimeTicks start = TimeTicks::Now();
668 TimeTicks now;
Sami Kyostila2bde91432018-11-07 01:43:46669 TestCase->Start();
670 delegate_->WaitUntilDone();
671 now = TimeTicks::Now();
Greg Kraynov3634ea32018-08-07 08:43:38672
alexclarkef02cff06d2015-03-06 12:11:50673 perf_test::PrintResult(
Alex Clarke3cf99942018-10-31 11:57:03674 "task", "", trace + delegate_->GetName(),
Sami Kyostila2bde91432018-11-07 01:43:46675 (now - start).InMicroseconds() / static_cast<double>(kNumTasks),
676 "us/task", true);
Alex Clarke3cf99942018-10-31 11:57:03677 LOG(ERROR) << "task " << trace << delegate_->GetName()
678 << ((now - start).InMicroseconds() /
Sami Kyostila2bde91432018-11-07 01:43:46679 static_cast<double>(kNumTasks))
680 << " us/task";
alexclarkef02cff06d2015-03-06 12:11:50681 }
682
Alex Clarke3cf99942018-10-31 11:57:03683 std::unique_ptr<PerfTestDelegate> delegate_;
alexclarkef02cff06d2015-03-06 12:11:50684};
685
Victor Costan7266ee8a2019-02-13 05:08:23686INSTANTIATE_TEST_SUITE_P(
Alex Clarked4b78b82018-10-19 15:48:53687 ,
688 SequenceManagerPerfTest,
Karolina Soltys1dccaeb2018-12-05 15:20:01689 testing::Values(
690 PerfTestType::kUseSequenceManagerWithMessageLoop,
691 PerfTestType::kUseSequenceManagerWithMessagePump,
692 PerfTestType::kUseSequenceManagerWithUIMessageLoop,
693 PerfTestType::kUseSequenceManagerWithUIMessagePump,
694 PerfTestType::kUseSequenceManagerWithIOMessageLoop,
695 PerfTestType::kUseSequenceManagerWithIOMessagePump,
696 PerfTestType::kUseMessageLoop,
697 PerfTestType::kUseUIMessageLoop,
698 PerfTestType::kUseIOMessageLoop,
Gabriel Charette3e2898f2019-05-01 14:55:01699 PerfTestType::kUseSingleThreadInThreadPool,
Karolina Soltys1dccaeb2018-12-05 15:20:01700 PerfTestType::kUseSequenceManagerWithMessagePumpAndRandomSampling));
Sami Kyostila2bde91432018-11-07 01:43:46701TEST_P(SequenceManagerPerfTest, PostDelayedTasks_OneQueue) {
Alex Clarke3cf99942018-10-31 11:57:03702 if (!delegate_->VirtualTimeIsSupported()) {
703 LOG(INFO) << "Unsupported";
704 return;
Alex Clarked4b78b82018-10-19 15:48:53705 }
706
Sami Kyostila2bde91432018-11-07 01:43:46707 SingleThreadDelayedTestCase task_source(delegate_.get(),
708 CreateTaskRunners(1));
709 Benchmark("post delayed tasks with one queue", &task_source);
alexclarkef02cff06d2015-03-06 12:11:50710}
711
Sami Kyostila2bde91432018-11-07 01:43:46712TEST_P(SequenceManagerPerfTest, PostDelayedTasks_FourQueues) {
713 if (!delegate_->VirtualTimeIsSupported() || !ShouldMeasureQueueScaling()) {
Alex Clarke3cf99942018-10-31 11:57:03714 LOG(INFO) << "Unsupported";
715 return;
Alex Clarked4b78b82018-10-19 15:48:53716 }
717
Alex Clarke3cf99942018-10-31 11:57:03718 SingleThreadDelayedTestCase task_source(delegate_.get(),
Sami Kyostila2bde91432018-11-07 01:43:46719 CreateTaskRunners(4));
720 Benchmark("post delayed tasks with four queues", &task_source);
alexclarke976cb662016-01-20 14:17:43721}
722
Sami Kyostila2bde91432018-11-07 01:43:46723TEST_P(SequenceManagerPerfTest, PostDelayedTasks_EightQueues) {
724 if (!delegate_->VirtualTimeIsSupported() || !ShouldMeasureQueueScaling()) {
725 LOG(INFO) << "Unsupported";
Alex Clarkea77f1e02018-05-21 09:20:18726 return;
Sami Kyostila2bde91432018-11-07 01:43:46727 }
Alex Clarkea77f1e02018-05-21 09:20:18728
Sami Kyostila2bde91432018-11-07 01:43:46729 SingleThreadDelayedTestCase task_source(delegate_.get(),
730 CreateTaskRunners(8));
731 Benchmark("post delayed tasks with eight queues", &task_source);
732}
733
734TEST_P(SequenceManagerPerfTest, PostDelayedTasks_ThirtyTwoQueues) {
735 if (!delegate_->VirtualTimeIsSupported() || !ShouldMeasureQueueScaling()) {
736 LOG(INFO) << "Unsupported";
737 return;
738 }
739
740 SingleThreadDelayedTestCase task_source(delegate_.get(),
741 CreateTaskRunners(32));
742 Benchmark("post delayed tasks with thirty two queues", &task_source);
743}
744
745TEST_P(SequenceManagerPerfTest, PostImmediateTasks_OneQueue) {
Alex Clarke3cf99942018-10-31 11:57:03746 SingleThreadImmediateTestCase task_source(delegate_.get(),
Sami Kyostila2bde91432018-11-07 01:43:46747 CreateTaskRunners(1));
748 Benchmark("post immediate tasks with one queue", &task_source);
Alex Clarkea77f1e02018-05-21 09:20:18749}
750
Sami Kyostila2bde91432018-11-07 01:43:46751TEST_P(SequenceManagerPerfTest, PostImmediateTasks_FourQueues) {
752 if (!ShouldMeasureQueueScaling()) {
Alex Clarke3cf99942018-10-31 11:57:03753 LOG(INFO) << "Unsupported";
754 return;
Alex Clarked4b78b82018-10-19 15:48:53755 }
756
Alex Clarke3cf99942018-10-31 11:57:03757 SingleThreadImmediateTestCase task_source(delegate_.get(),
Sami Kyostila2bde91432018-11-07 01:43:46758 CreateTaskRunners(4));
759 Benchmark("post immediate tasks with four queues", &task_source);
Alex Clarkea77f1e02018-05-21 09:20:18760}
761
Sami Kyostila2bde91432018-11-07 01:43:46762TEST_P(SequenceManagerPerfTest, PostImmediateTasks_EightQueues) {
763 if (!ShouldMeasureQueueScaling()) {
Alex Clarke3cf99942018-10-31 11:57:03764 LOG(INFO) << "Unsupported";
765 return;
Alex Clarked4b78b82018-10-19 15:48:53766 }
Alex Clarkea77f1e02018-05-21 09:20:18767
Alex Clarke3cf99942018-10-31 11:57:03768 SingleThreadImmediateTestCase task_source(delegate_.get(),
Sami Kyostila2bde91432018-11-07 01:43:46769 CreateTaskRunners(8));
770 Benchmark("post immediate tasks with eight queues", &task_source);
Alex Clarkea77f1e02018-05-21 09:20:18771}
772
Sami Kyostila2bde91432018-11-07 01:43:46773TEST_P(SequenceManagerPerfTest, PostImmediateTasks_ThirtyTwoQueues) {
774 if (!ShouldMeasureQueueScaling()) {
Alex Clarke3cf99942018-10-31 11:57:03775 LOG(INFO) << "Unsupported";
776 return;
Alex Clarked4b78b82018-10-19 15:48:53777 }
Alex Clarkea77f1e02018-05-21 09:20:18778
Alex Clarke3cf99942018-10-31 11:57:03779 SingleThreadImmediateTestCase task_source(delegate_.get(),
Sami Kyostila2bde91432018-11-07 01:43:46780 CreateTaskRunners(32));
781 Benchmark("post immediate tasks with thirty two queues", &task_source);
Alex Clarke3cf99942018-10-31 11:57:03782}
783
Sami Kyostila2bde91432018-11-07 01:43:46784TEST_P(SequenceManagerPerfTest, PostImmediateTasksFromTwoThreads_OneQueue) {
785 TwoThreadTestCase task_source(delegate_.get(), CreateTaskRunners(1));
Sami Kyostilaafb3ed20c2018-11-28 10:26:12786 Benchmark("post immediate tasks with one queue from two threads",
787 &task_source);
Alex Clarke3cf99942018-10-31 11:57:03788}
789
Sami Kyostila2bde91432018-11-07 01:43:46790TEST_P(SequenceManagerPerfTest, PostImmediateTasksFromTwoThreads_FourQueues) {
791 if (!ShouldMeasureQueueScaling()) {
Alex Clarke3cf99942018-10-31 11:57:03792 LOG(INFO) << "Unsupported";
793 return;
794 }
795
Sami Kyostila2bde91432018-11-07 01:43:46796 TwoThreadTestCase task_source(delegate_.get(), CreateTaskRunners(4));
Sami Kyostilaafb3ed20c2018-11-28 10:26:12797 Benchmark("post immediate tasks with four queues from two threads",
798 &task_source);
Alex Clarke3cf99942018-10-31 11:57:03799}
800
Sami Kyostila2bde91432018-11-07 01:43:46801TEST_P(SequenceManagerPerfTest, PostImmediateTasksFromTwoThreads_EightQueues) {
802 if (!ShouldMeasureQueueScaling()) {
Alex Clarke3cf99942018-10-31 11:57:03803 LOG(INFO) << "Unsupported";
804 return;
805 }
806
Sami Kyostila2bde91432018-11-07 01:43:46807 TwoThreadTestCase task_source(delegate_.get(), CreateTaskRunners(8));
Sami Kyostilaafb3ed20c2018-11-28 10:26:12808 Benchmark("post immediate tasks with eight queues from two threads",
809 &task_source);
Alex Clarke3cf99942018-10-31 11:57:03810}
811
812TEST_P(SequenceManagerPerfTest,
Sami Kyostila2bde91432018-11-07 01:43:46813 PostImmediateTasksFromTwoThreads_ThirtyTwoQueues) {
814 if (!ShouldMeasureQueueScaling()) {
Alex Clarke3cf99942018-10-31 11:57:03815 LOG(INFO) << "Unsupported";
816 return;
817 }
818
Sami Kyostila2bde91432018-11-07 01:43:46819 TwoThreadTestCase task_source(delegate_.get(), CreateTaskRunners(32));
Sami Kyostilaafb3ed20c2018-11-28 10:26:12820 Benchmark("post immediate tasks with thirty two queues from two threads",
821 &task_source);
Alex Clarkea77f1e02018-05-21 09:20:18822}
823
alexclarkef02cff06d2015-03-06 12:11:50824// TODO(alexclarke): Add additional tests with different mixes of non-delayed vs
825// delayed tasks.
826
Greg Kraynov8f4784462018-05-14 10:08:21827} // namespace sequence_manager
828} // namespace base