1 // Copyright 2015 The Chromium Authors
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/task/sequence_manager/sequence_manager.h"
6
7 #include <stddef.h>
8
9 #include <memory>
10 #include <optional>
11
12 #include "base/functional/bind.h"
13 #include "base/logging.h"
14 #include "base/memory/raw_ptr.h"
15 #include "base/message_loop/message_pump_default.h"
16 #include "base/message_loop/message_pump_type.h"
17 #include "base/run_loop.h"
18 #include "base/sequence_checker.h"
19 #include "base/synchronization/condition_variable.h"
20 #include "base/task/sequence_manager/task_queue.h"
21 #include "base/task/sequence_manager/test/mock_time_domain.h"
22 #include "base/task/sequence_manager/test/sequence_manager_for_test.h"
23 #include "base/task/sequence_manager/test/test_task_time_observer.h"
24 #include "base/task/sequence_manager/thread_controller_with_message_pump_impl.h"
25 #include "base/task/single_thread_task_runner.h"
26 #include "base/task/task_traits.h"
27 #include "base/task/thread_pool.h"
28 #include "base/task/thread_pool/thread_pool_impl.h"
29 #include "base/task/thread_pool/thread_pool_instance.h"
30 #include "base/threading/thread.h"
31 #include "base/time/default_tick_clock.h"
32 #include "build/build_config.h"
33 #include "testing/gtest/include/gtest/gtest.h"
34 #include "testing/perf/perf_result_reporter.h"
35
36 namespace base {
37 namespace sequence_manager {
38 namespace {
39 const int kNumTasks = 1000000;
40
41 constexpr char kMetricPrefixSequenceManager[] = "SequenceManager.";
42 constexpr char kMetricPostTimePerTask[] = "post_time_per_task";
43
SetUpReporter(const std::string & story_name)44 perf_test::PerfResultReporter SetUpReporter(const std::string& story_name) {
45 perf_test::PerfResultReporter reporter(kMetricPrefixSequenceManager,
46 story_name);
47 reporter.RegisterImportantMetric(kMetricPostTimePerTask, "us");
48 return reporter;
49 }
50
51 } // namespace
52
53 // To reduce noise related to the OS timer, we use a mock time domain to
54 // fast forward the timers.
55 class PerfTestTimeDomain : public MockTimeDomain {
56 public:
PerfTestTimeDomain()57 PerfTestTimeDomain() : MockTimeDomain(TimeTicks::Now()) {}
58 PerfTestTimeDomain(const PerfTestTimeDomain&) = delete;
59 PerfTestTimeDomain& operator=(const PerfTestTimeDomain&) = delete;
60 ~PerfTestTimeDomain() override = default;
61
MaybeFastForwardToWakeUp(std::optional<WakeUp> wake_up,bool quit_when_idle_requested)62 bool MaybeFastForwardToWakeUp(std::optional<WakeUp> wake_up,
63 bool quit_when_idle_requested) override {
64 if (wake_up) {
65 SetNowTicks(wake_up->time);
66 return true;
67 }
68 return false;
69 }
70 };
71
72 enum class PerfTestType {
73 // A SequenceManager with a ThreadControllerWithMessagePumpImpl driving the
74 // thread.
75 kUseSequenceManagerWithMessagePump,
76 kUseSequenceManagerWithUIMessagePump,
77 kUseSequenceManagerWithIOMessagePump,
78 kUseSequenceManagerWithMessagePumpAndRandomSampling,
79
80 // A SingleThreadTaskRunner in the thread pool.
81 kUseSingleThreadInThreadPool,
82 };
83
84 // Customization point for SequenceManagerPerfTest which allows us to test
85 // various implementations.
86 class PerfTestDelegate {
87 public:
88 virtual ~PerfTestDelegate() = default;
89
90 virtual const char* GetName() const = 0;
91
92 virtual bool VirtualTimeIsSupported() const = 0;
93
94 virtual bool MultipleQueuesSupported() const = 0;
95
96 virtual scoped_refptr<TaskRunner> CreateTaskRunner() = 0;
97
98 virtual void WaitUntilDone() = 0;
99
100 virtual void SignalDone() = 0;
101 };
102
103 class BaseSequenceManagerPerfTestDelegate : public PerfTestDelegate {
104 public:
105 BaseSequenceManagerPerfTestDelegate() = default;
106
107 ~BaseSequenceManagerPerfTestDelegate() override = default;
108
VirtualTimeIsSupported() const109 bool VirtualTimeIsSupported() const override { return true; }
110
MultipleQueuesSupported() const111 bool MultipleQueuesSupported() const override { return true; }
112
CreateTaskRunner()113 scoped_refptr<TaskRunner> CreateTaskRunner() override {
114 owned_task_queues_.push_back(
115 manager_->CreateTaskQueue(TaskQueue::Spec(QueueName::TEST_TQ)));
116 return owned_task_queues_.back()->task_runner();
117 }
118
WaitUntilDone()119 void WaitUntilDone() override {
120 run_loop_ = std::make_unique<RunLoop>();
121 run_loop_->Run();
122 }
123
SignalDone()124 void SignalDone() override { run_loop_->Quit(); }
125
GetManager() const126 SequenceManager* GetManager() const { return manager_.get(); }
127
SetSequenceManager(std::unique_ptr<SequenceManager> manager)128 void SetSequenceManager(std::unique_ptr<SequenceManager> manager) {
129 manager_ = std::move(manager);
130 time_domain_ = std::make_unique<PerfTestTimeDomain>();
131 manager_->SetTimeDomain(time_domain_.get());
132 }
133
ShutDown()134 void ShutDown() {
135 owned_task_queues_.clear();
136 manager_->ResetTimeDomain();
137 manager_.reset();
138 }
139
140 private:
141 std::unique_ptr<SequenceManager> manager_;
142 std::unique_ptr<TimeDomain> time_domain_;
143 std::unique_ptr<RunLoop> run_loop_;
144 std::vector<TaskQueue::Handle> owned_task_queues_;
145 };
146
147 class SequenceManagerWithMessagePumpPerfTestDelegate
148 : public BaseSequenceManagerPerfTestDelegate {
149 public:
SequenceManagerWithMessagePumpPerfTestDelegate(const char * name,MessagePumpType type,bool randomised_sampling_enabled=false)150 SequenceManagerWithMessagePumpPerfTestDelegate(
151 const char* name,
152 MessagePumpType type,
153 bool randomised_sampling_enabled = false)
154 : name_(name) {
155 auto settings =
156 SequenceManager::Settings::Builder()
157 .SetRandomisedSamplingEnabled(randomised_sampling_enabled)
158 .Build();
159 SetSequenceManager(SequenceManagerForTest::Create(
160 std::make_unique<internal::ThreadControllerWithMessagePumpImpl>(
161 MessagePump::Create(type), settings),
162 std::move(settings)));
163
164 // ThreadControllerWithMessagePumpImpl doesn't provide a default task
165 // runner.
166 default_task_queue_ =
167 GetManager()->CreateTaskQueue(TaskQueue::Spec(QueueName::DEFAULT_TQ));
168 GetManager()->SetDefaultTaskRunner(default_task_queue_->task_runner());
169 }
170
~SequenceManagerWithMessagePumpPerfTestDelegate()171 ~SequenceManagerWithMessagePumpPerfTestDelegate() override { ShutDown(); }
172
GetName() const173 const char* GetName() const override { return name_; }
174
175 private:
176 const char* const name_;
177 TaskQueue::Handle default_task_queue_;
178 };
179
180 class SingleThreadInThreadPoolPerfTestDelegate : public PerfTestDelegate {
181 public:
SingleThreadInThreadPoolPerfTestDelegate()182 SingleThreadInThreadPoolPerfTestDelegate() : done_cond_(&done_lock_) {
183 ThreadPoolInstance::Set(
184 std::make_unique<::base::internal::ThreadPoolImpl>("Test"));
185 ThreadPoolInstance::Get()->StartWithDefaultParams();
186 }
187
~SingleThreadInThreadPoolPerfTestDelegate()188 ~SingleThreadInThreadPoolPerfTestDelegate() override {
189 ThreadPoolInstance::Get()->JoinForTesting();
190 ThreadPoolInstance::Set(nullptr);
191 }
192
GetName() const193 const char* GetName() const override {
194 return " single thread in ThreadPool ";
195 }
196
VirtualTimeIsSupported() const197 bool VirtualTimeIsSupported() const override { return false; }
198
MultipleQueuesSupported() const199 bool MultipleQueuesSupported() const override { return false; }
200
CreateTaskRunner()201 scoped_refptr<TaskRunner> CreateTaskRunner() override {
202 return ThreadPool::CreateSingleThreadTaskRunner(
203 {TaskPriority::USER_BLOCKING});
204 }
205
WaitUntilDone()206 void WaitUntilDone() override {
207 AutoLock auto_lock(done_lock_);
208 done_cond_.Wait();
209 }
210
SignalDone()211 void SignalDone() override {
212 AutoLock auto_lock(done_lock_);
213 done_cond_.Signal();
214 }
215
216 private:
217 Lock done_lock_;
218 ConditionVariable done_cond_;
219 };
220
221 class TestCase {
222 public:
223 // |delegate| is assumed to outlive TestCase.
TestCase(PerfTestDelegate * delegate)224 explicit TestCase(PerfTestDelegate* delegate) : delegate_(delegate) {}
225
226 virtual ~TestCase() = default;
227
228 virtual void Start() = 0;
229
230 protected:
231 const raw_ptr<PerfTestDelegate> delegate_; // NOT OWNED
232 };
233
234 class TaskSource {
235 public:
236 virtual ~TaskSource() = default;
237
238 virtual void Start() = 0;
239 };
240
241 class SameThreadTaskSource : public TaskSource {
242 public:
SameThreadTaskSource(std::vector<scoped_refptr<TaskRunner>> task_runners,size_t num_tasks)243 SameThreadTaskSource(std::vector<scoped_refptr<TaskRunner>> task_runners,
244 size_t num_tasks)
245 : num_queues_(task_runners.size()),
246 num_tasks_(num_tasks),
247 task_closure_(
248 BindRepeating(&SameThreadTaskSource::TestTask, Unretained(this))),
249 task_runners_(std::move(task_runners)) {
250 DETACH_FROM_SEQUENCE(sequence_checker_);
251 }
252
Start()253 void Start() override {
254 num_tasks_in_flight_ = 1;
255 num_tasks_to_post_ = num_tasks_;
256 num_tasks_to_run_ = num_tasks_;
257 // Post the initial task instead of running it synchronously to ensure that
258 // all invocations happen on the same sequence.
259 PostTask(0);
260 }
261
262 protected:
263 virtual void PostTask(unsigned int queue) = 0;
264
265 virtual void SignalDone() = 0;
266
TestTask()267 void TestTask() {
268 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
269
270 if (--num_tasks_to_run_ == 0) {
271 SignalDone();
272 return;
273 }
274
275 num_tasks_in_flight_--;
276 // NOTE there are only up to max_tasks_in_flight_ pending delayed tasks at
277 // any one time. Thanks to the lower_num_tasks_to_post going to zero if
278 // there are a lot of tasks in flight, the total number of task in flight at
279 // any one time is very variable.
280 unsigned int lower_num_tasks_to_post =
281 num_tasks_in_flight_ < (max_tasks_in_flight_ / 2) ? 1 : 0;
282 unsigned int max_tasks_to_post =
283 num_tasks_to_post_ % 2 ? lower_num_tasks_to_post : 10;
284 for (unsigned int i = 0;
285 i < max_tasks_to_post && num_tasks_in_flight_ < max_tasks_in_flight_ &&
286 num_tasks_to_post_ > 0;
287 i++) {
288 // Choose a queue weighted towards queue 0.
289 unsigned int queue = num_tasks_to_post_ % (num_queues_ + 1);
290 if (queue == num_queues_) {
291 queue = 0;
292 }
293 PostTask(queue);
294 num_tasks_in_flight_++;
295 num_tasks_to_post_--;
296 }
297 }
298
299 const size_t num_queues_;
300 const size_t num_tasks_;
301 const RepeatingClosure task_closure_;
302 const std::vector<scoped_refptr<TaskRunner>> task_runners_;
303 const unsigned int max_tasks_in_flight_ = 200;
304 unsigned int num_tasks_in_flight_;
305 unsigned int num_tasks_to_post_;
306 unsigned int num_tasks_to_run_;
307 SEQUENCE_CHECKER(sequence_checker_);
308 };
309
310 class CrossThreadTaskSource : public TaskSource {
311 public:
CrossThreadTaskSource(std::vector<scoped_refptr<TaskRunner>> task_runners,size_t num_tasks)312 CrossThreadTaskSource(std::vector<scoped_refptr<TaskRunner>> task_runners,
313 size_t num_tasks)
314 : num_queues_(task_runners.size()),
315 num_tasks_(num_tasks),
316 task_closure_(
317 BindRepeating(&CrossThreadTaskSource::TestTask, Unretained(this))),
318 task_runners_(std::move(task_runners)) {}
319
Start()320 void Start() override {
321 num_tasks_in_flight_ = 0;
322 num_tasks_to_run_ = num_tasks_;
323
324 for (size_t i = 0; i < num_tasks_; i++) {
325 while (num_tasks_in_flight_.load(std::memory_order_acquire) >
326 max_tasks_in_flight_) {
327 PlatformThread::YieldCurrentThread();
328 }
329 // Choose a queue weighted towards queue 0.
330 unsigned int queue = i % (num_queues_ + 1);
331 if (queue == num_queues_) {
332 queue = 0;
333 }
334 PostTask(queue);
335 num_tasks_in_flight_++;
336 }
337 }
338
339 protected:
340 virtual void PostTask(unsigned int queue) = 0;
341
342 // Will be called on the main thread.
343 virtual void SignalDone() = 0;
344
TestTask()345 void TestTask() {
346 if (num_tasks_to_run_.fetch_sub(1) == 1) {
347 SignalDone();
348 return;
349 }
350 num_tasks_in_flight_--;
351 }
352
353 const size_t num_queues_;
354 const size_t num_tasks_;
355 const RepeatingClosure task_closure_;
356 const std::vector<scoped_refptr<TaskRunner>> task_runners_;
357 const unsigned int max_tasks_in_flight_ = 200;
358 std::atomic<unsigned int> num_tasks_in_flight_;
359 std::atomic<unsigned int> num_tasks_to_run_;
360 };
361
362 class SingleThreadImmediateTestCase : public TestCase {
363 public:
SingleThreadImmediateTestCase(PerfTestDelegate * delegate,std::vector<scoped_refptr<TaskRunner>> task_runners)364 SingleThreadImmediateTestCase(
365 PerfTestDelegate* delegate,
366 std::vector<scoped_refptr<TaskRunner>> task_runners)
367 : TestCase(delegate),
368 task_source_(std::make_unique<SingleThreadImmediateTaskSource>(
369 delegate,
370 std::move(task_runners),
371 kNumTasks)) {}
372
Start()373 void Start() override { task_source_->Start(); }
374
375 private:
376 class SingleThreadImmediateTaskSource : public SameThreadTaskSource {
377 public:
SingleThreadImmediateTaskSource(PerfTestDelegate * delegate,std::vector<scoped_refptr<TaskRunner>> task_runners,size_t num_tasks)378 SingleThreadImmediateTaskSource(
379 PerfTestDelegate* delegate,
380 std::vector<scoped_refptr<TaskRunner>> task_runners,
381 size_t num_tasks)
382 : SameThreadTaskSource(std::move(task_runners), num_tasks),
383 delegate_(delegate) {}
384
385 ~SingleThreadImmediateTaskSource() override = default;
386
PostTask(unsigned int queue)387 void PostTask(unsigned int queue) override {
388 task_runners_[queue]->PostTask(FROM_HERE, task_closure_);
389 }
390
SignalDone()391 void SignalDone() override { delegate_->SignalDone(); }
392
393 raw_ptr<PerfTestDelegate> delegate_; // NOT OWNED.
394 };
395
396 const std::unique_ptr<TaskSource> task_source_;
397 };
398
399 class SingleThreadDelayedTestCase : public TestCase {
400 public:
SingleThreadDelayedTestCase(PerfTestDelegate * delegate,std::vector<scoped_refptr<TaskRunner>> task_runners)401 SingleThreadDelayedTestCase(
402 PerfTestDelegate* delegate,
403 std::vector<scoped_refptr<TaskRunner>> task_runners)
404 : TestCase(delegate),
405 task_source_(std::make_unique<SingleThreadDelayedTaskSource>(
406 delegate,
407 std::move(task_runners),
408 kNumTasks)) {}
409
Start()410 void Start() override { task_source_->Start(); }
411
412 private:
413 class SingleThreadDelayedTaskSource : public SameThreadTaskSource {
414 public:
SingleThreadDelayedTaskSource(PerfTestDelegate * delegate,std::vector<scoped_refptr<TaskRunner>> task_runners,size_t num_tasks)415 explicit SingleThreadDelayedTaskSource(
416 PerfTestDelegate* delegate,
417 std::vector<scoped_refptr<TaskRunner>> task_runners,
418 size_t num_tasks)
419 : SameThreadTaskSource(std::move(task_runners), num_tasks),
420 delegate_(delegate) {}
421
422 ~SingleThreadDelayedTaskSource() override = default;
423
PostTask(unsigned int queue)424 void PostTask(unsigned int queue) override {
425 unsigned int delay =
426 num_tasks_to_post_ % 2 ? 1 : (10 + num_tasks_to_post_ % 10);
427 task_runners_[queue]->PostDelayedTask(FROM_HERE, task_closure_,
428 Milliseconds(delay));
429 }
430
SignalDone()431 void SignalDone() override { delegate_->SignalDone(); }
432
433 raw_ptr<PerfTestDelegate> delegate_; // NOT OWNED.
434 };
435
436 const std::unique_ptr<TaskSource> task_source_;
437 };
438
439 class TwoThreadTestCase : public TestCase {
440 public:
TwoThreadTestCase(PerfTestDelegate * delegate,std::vector<scoped_refptr<TaskRunner>> task_runners)441 TwoThreadTestCase(PerfTestDelegate* delegate,
442 std::vector<scoped_refptr<TaskRunner>> task_runners)
443 : TestCase(delegate),
444 task_runners_(std::move(task_runners)),
445 num_tasks_(kNumTasks),
446 auxiliary_thread_("auxillary thread") {
447 auxiliary_thread_.Start();
448 }
449
~TwoThreadTestCase()450 ~TwoThreadTestCase() override { auxiliary_thread_.Stop(); }
451
452 protected:
Start()453 void Start() override {
454 done_count_ = 0;
455 same_thread_task_source_ =
456 std::make_unique<SingleThreadImmediateTaskSource>(this, task_runners_,
457 num_tasks_ / 2);
458 cross_thread_task_scorce_ =
459 std::make_unique<CrossThreadImmediateTaskSource>(this, task_runners_,
460 num_tasks_ / 2);
461
462 auxiliary_thread_.task_runner()->PostTask(
463 FROM_HERE, base::BindOnce(&CrossThreadImmediateTaskSource::Start,
464 Unretained(cross_thread_task_scorce_.get())));
465 same_thread_task_source_->Start();
466 }
467
468 class SingleThreadImmediateTaskSource : public SameThreadTaskSource {
469 public:
SingleThreadImmediateTaskSource(TwoThreadTestCase * two_thread_test_case,std::vector<scoped_refptr<TaskRunner>> task_runners,size_t num_tasks)470 SingleThreadImmediateTaskSource(
471 TwoThreadTestCase* two_thread_test_case,
472 std::vector<scoped_refptr<TaskRunner>> task_runners,
473 size_t num_tasks)
474 : SameThreadTaskSource(std::move(task_runners), num_tasks),
475 two_thread_test_case_(two_thread_test_case) {}
476
477 ~SingleThreadImmediateTaskSource() override = default;
478
PostTask(unsigned int queue)479 void PostTask(unsigned int queue) override {
480 task_runners_[queue]->PostTask(FROM_HERE, task_closure_);
481 }
482
483 // Will be called on the main thread.
SignalDone()484 void SignalDone() override { two_thread_test_case_->SignalDone(); }
485
486 raw_ptr<TwoThreadTestCase> two_thread_test_case_; // NOT OWNED.
487 };
488
489 class CrossThreadImmediateTaskSource : public CrossThreadTaskSource {
490 public:
CrossThreadImmediateTaskSource(TwoThreadTestCase * two_thread_test_case,std::vector<scoped_refptr<TaskRunner>> task_runners,size_t num_tasks)491 CrossThreadImmediateTaskSource(
492 TwoThreadTestCase* two_thread_test_case,
493 std::vector<scoped_refptr<TaskRunner>> task_runners,
494 size_t num_tasks)
495 : CrossThreadTaskSource(std::move(task_runners), num_tasks),
496 two_thread_test_case_(two_thread_test_case) {}
497
498 ~CrossThreadImmediateTaskSource() override = default;
499
PostTask(unsigned int queue)500 void PostTask(unsigned int queue) override {
501 task_runners_[queue]->PostTask(FROM_HERE, task_closure_);
502 }
503
504 // Will be called on the main thread.
SignalDone()505 void SignalDone() override { two_thread_test_case_->SignalDone(); }
506
507 raw_ptr<TwoThreadTestCase> two_thread_test_case_; // NOT OWNED.
508 };
509
SignalDone()510 void SignalDone() {
511 if (++done_count_ == 2)
512 delegate_->SignalDone();
513 }
514
515 private:
516 const std::vector<scoped_refptr<TaskRunner>> task_runners_;
517 const size_t num_tasks_;
518 Thread auxiliary_thread_;
519 std::unique_ptr<SingleThreadImmediateTaskSource> same_thread_task_source_;
520 std::unique_ptr<CrossThreadImmediateTaskSource> cross_thread_task_scorce_;
521 int done_count_ = 0;
522 };
523
524 class SequenceManagerPerfTest : public testing::TestWithParam<PerfTestType> {
525 public:
526 SequenceManagerPerfTest() = default;
527
SetUp()528 void SetUp() override { delegate_ = CreateDelegate(); }
529
TearDown()530 void TearDown() override { delegate_.reset(); }
531
CreateDelegate()532 std::unique_ptr<PerfTestDelegate> CreateDelegate() {
533 switch (GetParam()) {
534 case PerfTestType::kUseSequenceManagerWithMessagePump:
535 return std::make_unique<SequenceManagerWithMessagePumpPerfTestDelegate>(
536 " SequenceManager with MessagePumpDefault ",
537 MessagePumpType::DEFAULT);
538
539 case PerfTestType::kUseSequenceManagerWithUIMessagePump:
540 return std::make_unique<SequenceManagerWithMessagePumpPerfTestDelegate>(
541 " SequenceManager with MessagePumpForUI ", MessagePumpType::UI);
542
543 case PerfTestType::kUseSequenceManagerWithIOMessagePump:
544 return std::make_unique<SequenceManagerWithMessagePumpPerfTestDelegate>(
545 " SequenceManager with MessagePumpForIO ", MessagePumpType::IO);
546
547 case PerfTestType::kUseSequenceManagerWithMessagePumpAndRandomSampling:
548 return std::make_unique<SequenceManagerWithMessagePumpPerfTestDelegate>(
549 " SequenceManager with MessagePumpDefault and random sampling ",
550 MessagePumpType::DEFAULT, true);
551
552 case PerfTestType::kUseSingleThreadInThreadPool:
553 return std::make_unique<SingleThreadInThreadPoolPerfTestDelegate>();
554
555 default:
556 NOTREACHED();
557 }
558 }
559
ShouldMeasureQueueScaling() const560 bool ShouldMeasureQueueScaling() const {
561 // To limit test run time, we only measure multiple queues specific sequence
562 // manager configurations.
563 return delegate_->MultipleQueuesSupported() &&
564 GetParam() == PerfTestType::kUseSequenceManagerWithUIMessagePump;
565 }
566
CreateTaskRunners(int num)567 std::vector<scoped_refptr<TaskRunner>> CreateTaskRunners(int num) {
568 std::vector<scoped_refptr<TaskRunner>> task_runners;
569 for (int i = 0; i < num; i++) {
570 task_runners.push_back(delegate_->CreateTaskRunner());
571 }
572 return task_runners;
573 }
574
Benchmark(const std::string & story_prefix,TestCase * TestCase)575 void Benchmark(const std::string& story_prefix, TestCase* TestCase) {
576 TimeTicks start = TimeTicks::Now();
577 TimeTicks now;
578 TestCase->Start();
579 delegate_->WaitUntilDone();
580 now = TimeTicks::Now();
581
582 auto reporter = SetUpReporter(story_prefix + delegate_->GetName());
583 reporter.AddResult(
584 kMetricPostTimePerTask,
585 (now - start).InMicroseconds() / static_cast<double>(kNumTasks));
586 }
587
588 std::unique_ptr<PerfTestDelegate> delegate_;
589 };
590
591 INSTANTIATE_TEST_SUITE_P(
592 All,
593 SequenceManagerPerfTest,
594 testing::Values(
595 PerfTestType::kUseSequenceManagerWithMessagePump,
596 PerfTestType::kUseSequenceManagerWithUIMessagePump,
597 PerfTestType::kUseSequenceManagerWithIOMessagePump,
598 PerfTestType::kUseSingleThreadInThreadPool,
599 PerfTestType::kUseSequenceManagerWithMessagePumpAndRandomSampling));
TEST_P(SequenceManagerPerfTest,PostDelayedTasks_OneQueue)600 TEST_P(SequenceManagerPerfTest, PostDelayedTasks_OneQueue) {
601 if (!delegate_->VirtualTimeIsSupported()) {
602 LOG(INFO) << "Unsupported";
603 return;
604 }
605
606 SingleThreadDelayedTestCase task_source(delegate_.get(),
607 CreateTaskRunners(1));
608 Benchmark("post delayed tasks with one queue", &task_source);
609 }
610
TEST_P(SequenceManagerPerfTest,PostDelayedTasks_FourQueues)611 TEST_P(SequenceManagerPerfTest, PostDelayedTasks_FourQueues) {
612 if (!delegate_->VirtualTimeIsSupported() || !ShouldMeasureQueueScaling()) {
613 LOG(INFO) << "Unsupported";
614 return;
615 }
616
617 SingleThreadDelayedTestCase task_source(delegate_.get(),
618 CreateTaskRunners(4));
619 Benchmark("post delayed tasks with four queues", &task_source);
620 }
621
TEST_P(SequenceManagerPerfTest,PostDelayedTasks_EightQueues)622 TEST_P(SequenceManagerPerfTest, PostDelayedTasks_EightQueues) {
623 if (!delegate_->VirtualTimeIsSupported() || !ShouldMeasureQueueScaling()) {
624 LOG(INFO) << "Unsupported";
625 return;
626 }
627
628 SingleThreadDelayedTestCase task_source(delegate_.get(),
629 CreateTaskRunners(8));
630 Benchmark("post delayed tasks with eight queues", &task_source);
631 }
632
TEST_P(SequenceManagerPerfTest,PostDelayedTasks_ThirtyTwoQueues)633 TEST_P(SequenceManagerPerfTest, PostDelayedTasks_ThirtyTwoQueues) {
634 if (!delegate_->VirtualTimeIsSupported() || !ShouldMeasureQueueScaling()) {
635 LOG(INFO) << "Unsupported";
636 return;
637 }
638
639 SingleThreadDelayedTestCase task_source(delegate_.get(),
640 CreateTaskRunners(32));
641 Benchmark("post delayed tasks with thirty two queues", &task_source);
642 }
643
TEST_P(SequenceManagerPerfTest,PostImmediateTasks_OneQueue)644 TEST_P(SequenceManagerPerfTest, PostImmediateTasks_OneQueue) {
645 SingleThreadImmediateTestCase task_source(delegate_.get(),
646 CreateTaskRunners(1));
647 Benchmark("post immediate tasks with one queue", &task_source);
648 }
649
TEST_P(SequenceManagerPerfTest,PostImmediateTasks_FourQueues)650 TEST_P(SequenceManagerPerfTest, PostImmediateTasks_FourQueues) {
651 if (!ShouldMeasureQueueScaling()) {
652 LOG(INFO) << "Unsupported";
653 return;
654 }
655
656 SingleThreadImmediateTestCase task_source(delegate_.get(),
657 CreateTaskRunners(4));
658 Benchmark("post immediate tasks with four queues", &task_source);
659 }
660
TEST_P(SequenceManagerPerfTest,PostImmediateTasks_EightQueues)661 TEST_P(SequenceManagerPerfTest, PostImmediateTasks_EightQueues) {
662 if (!ShouldMeasureQueueScaling()) {
663 LOG(INFO) << "Unsupported";
664 return;
665 }
666
667 SingleThreadImmediateTestCase task_source(delegate_.get(),
668 CreateTaskRunners(8));
669 Benchmark("post immediate tasks with eight queues", &task_source);
670 }
671
TEST_P(SequenceManagerPerfTest,PostImmediateTasks_ThirtyTwoQueues)672 TEST_P(SequenceManagerPerfTest, PostImmediateTasks_ThirtyTwoQueues) {
673 if (!ShouldMeasureQueueScaling()) {
674 LOG(INFO) << "Unsupported";
675 return;
676 }
677
678 SingleThreadImmediateTestCase task_source(delegate_.get(),
679 CreateTaskRunners(32));
680 Benchmark("post immediate tasks with thirty two queues", &task_source);
681 }
682
TEST_P(SequenceManagerPerfTest,PostImmediateTasksFromTwoThreads_OneQueue)683 TEST_P(SequenceManagerPerfTest, PostImmediateTasksFromTwoThreads_OneQueue) {
684 TwoThreadTestCase task_source(delegate_.get(), CreateTaskRunners(1));
685 Benchmark("post immediate tasks with one queue from two threads",
686 &task_source);
687 }
688
TEST_P(SequenceManagerPerfTest,PostImmediateTasksFromTwoThreads_FourQueues)689 TEST_P(SequenceManagerPerfTest, PostImmediateTasksFromTwoThreads_FourQueues) {
690 if (!ShouldMeasureQueueScaling()) {
691 LOG(INFO) << "Unsupported";
692 return;
693 }
694
695 TwoThreadTestCase task_source(delegate_.get(), CreateTaskRunners(4));
696 Benchmark("post immediate tasks with four queues from two threads",
697 &task_source);
698 }
699
TEST_P(SequenceManagerPerfTest,PostImmediateTasksFromTwoThreads_EightQueues)700 TEST_P(SequenceManagerPerfTest, PostImmediateTasksFromTwoThreads_EightQueues) {
701 if (!ShouldMeasureQueueScaling()) {
702 LOG(INFO) << "Unsupported";
703 return;
704 }
705
706 TwoThreadTestCase task_source(delegate_.get(), CreateTaskRunners(8));
707 Benchmark("post immediate tasks with eight queues from two threads",
708 &task_source);
709 }
710
TEST_P(SequenceManagerPerfTest,PostImmediateTasksFromTwoThreads_ThirtyTwoQueues)711 TEST_P(SequenceManagerPerfTest,
712 PostImmediateTasksFromTwoThreads_ThirtyTwoQueues) {
713 if (!ShouldMeasureQueueScaling()) {
714 LOG(INFO) << "Unsupported";
715 return;
716 }
717
718 TwoThreadTestCase task_source(delegate_.get(), CreateTaskRunners(32));
719 Benchmark("post immediate tasks with thirty two queues from two threads",
720 &task_source);
721 }
722
723 // TODO(alexclarke): Add additional tests with different mixes of non-delayed vs
724 // delayed tasks.
725
726 } // namespace sequence_manager
727 } // namespace base
728