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:
BaseSequenceManagerPerfTestDelegate()105 BaseSequenceManagerPerfTestDelegate() {}
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 return nullptr;
558 }
559 }
560
ShouldMeasureQueueScaling() const561 bool ShouldMeasureQueueScaling() const {
562 // To limit test run time, we only measure multiple queues specific sequence
563 // manager configurations.
564 return delegate_->MultipleQueuesSupported() &&
565 GetParam() == PerfTestType::kUseSequenceManagerWithUIMessagePump;
566 }
567
CreateTaskRunners(int num)568 std::vector<scoped_refptr<TaskRunner>> CreateTaskRunners(int num) {
569 std::vector<scoped_refptr<TaskRunner>> task_runners;
570 for (int i = 0; i < num; i++) {
571 task_runners.push_back(delegate_->CreateTaskRunner());
572 }
573 return task_runners;
574 }
575
Benchmark(const std::string & story_prefix,TestCase * TestCase)576 void Benchmark(const std::string& story_prefix, TestCase* TestCase) {
577 TimeTicks start = TimeTicks::Now();
578 TimeTicks now;
579 TestCase->Start();
580 delegate_->WaitUntilDone();
581 now = TimeTicks::Now();
582
583 auto reporter = SetUpReporter(story_prefix + delegate_->GetName());
584 reporter.AddResult(
585 kMetricPostTimePerTask,
586 (now - start).InMicroseconds() / static_cast<double>(kNumTasks));
587 }
588
589 std::unique_ptr<PerfTestDelegate> delegate_;
590 };
591
592 INSTANTIATE_TEST_SUITE_P(
593 All,
594 SequenceManagerPerfTest,
595 testing::Values(
596 PerfTestType::kUseSequenceManagerWithMessagePump,
597 PerfTestType::kUseSequenceManagerWithUIMessagePump,
598 PerfTestType::kUseSequenceManagerWithIOMessagePump,
599 PerfTestType::kUseSingleThreadInThreadPool,
600 PerfTestType::kUseSequenceManagerWithMessagePumpAndRandomSampling));
TEST_P(SequenceManagerPerfTest,PostDelayedTasks_OneQueue)601 TEST_P(SequenceManagerPerfTest, PostDelayedTasks_OneQueue) {
602 if (!delegate_->VirtualTimeIsSupported()) {
603 LOG(INFO) << "Unsupported";
604 return;
605 }
606
607 SingleThreadDelayedTestCase task_source(delegate_.get(),
608 CreateTaskRunners(1));
609 Benchmark("post delayed tasks with one queue", &task_source);
610 }
611
TEST_P(SequenceManagerPerfTest,PostDelayedTasks_FourQueues)612 TEST_P(SequenceManagerPerfTest, PostDelayedTasks_FourQueues) {
613 if (!delegate_->VirtualTimeIsSupported() || !ShouldMeasureQueueScaling()) {
614 LOG(INFO) << "Unsupported";
615 return;
616 }
617
618 SingleThreadDelayedTestCase task_source(delegate_.get(),
619 CreateTaskRunners(4));
620 Benchmark("post delayed tasks with four queues", &task_source);
621 }
622
TEST_P(SequenceManagerPerfTest,PostDelayedTasks_EightQueues)623 TEST_P(SequenceManagerPerfTest, PostDelayedTasks_EightQueues) {
624 if (!delegate_->VirtualTimeIsSupported() || !ShouldMeasureQueueScaling()) {
625 LOG(INFO) << "Unsupported";
626 return;
627 }
628
629 SingleThreadDelayedTestCase task_source(delegate_.get(),
630 CreateTaskRunners(8));
631 Benchmark("post delayed tasks with eight queues", &task_source);
632 }
633
TEST_P(SequenceManagerPerfTest,PostDelayedTasks_ThirtyTwoQueues)634 TEST_P(SequenceManagerPerfTest, PostDelayedTasks_ThirtyTwoQueues) {
635 if (!delegate_->VirtualTimeIsSupported() || !ShouldMeasureQueueScaling()) {
636 LOG(INFO) << "Unsupported";
637 return;
638 }
639
640 SingleThreadDelayedTestCase task_source(delegate_.get(),
641 CreateTaskRunners(32));
642 Benchmark("post delayed tasks with thirty two queues", &task_source);
643 }
644
TEST_P(SequenceManagerPerfTest,PostImmediateTasks_OneQueue)645 TEST_P(SequenceManagerPerfTest, PostImmediateTasks_OneQueue) {
646 SingleThreadImmediateTestCase task_source(delegate_.get(),
647 CreateTaskRunners(1));
648 Benchmark("post immediate tasks with one queue", &task_source);
649 }
650
TEST_P(SequenceManagerPerfTest,PostImmediateTasks_FourQueues)651 TEST_P(SequenceManagerPerfTest, PostImmediateTasks_FourQueues) {
652 if (!ShouldMeasureQueueScaling()) {
653 LOG(INFO) << "Unsupported";
654 return;
655 }
656
657 SingleThreadImmediateTestCase task_source(delegate_.get(),
658 CreateTaskRunners(4));
659 Benchmark("post immediate tasks with four queues", &task_source);
660 }
661
TEST_P(SequenceManagerPerfTest,PostImmediateTasks_EightQueues)662 TEST_P(SequenceManagerPerfTest, PostImmediateTasks_EightQueues) {
663 if (!ShouldMeasureQueueScaling()) {
664 LOG(INFO) << "Unsupported";
665 return;
666 }
667
668 SingleThreadImmediateTestCase task_source(delegate_.get(),
669 CreateTaskRunners(8));
670 Benchmark("post immediate tasks with eight queues", &task_source);
671 }
672
TEST_P(SequenceManagerPerfTest,PostImmediateTasks_ThirtyTwoQueues)673 TEST_P(SequenceManagerPerfTest, PostImmediateTasks_ThirtyTwoQueues) {
674 if (!ShouldMeasureQueueScaling()) {
675 LOG(INFO) << "Unsupported";
676 return;
677 }
678
679 SingleThreadImmediateTestCase task_source(delegate_.get(),
680 CreateTaskRunners(32));
681 Benchmark("post immediate tasks with thirty two queues", &task_source);
682 }
683
TEST_P(SequenceManagerPerfTest,PostImmediateTasksFromTwoThreads_OneQueue)684 TEST_P(SequenceManagerPerfTest, PostImmediateTasksFromTwoThreads_OneQueue) {
685 TwoThreadTestCase task_source(delegate_.get(), CreateTaskRunners(1));
686 Benchmark("post immediate tasks with one queue from two threads",
687 &task_source);
688 }
689
TEST_P(SequenceManagerPerfTest,PostImmediateTasksFromTwoThreads_FourQueues)690 TEST_P(SequenceManagerPerfTest, PostImmediateTasksFromTwoThreads_FourQueues) {
691 if (!ShouldMeasureQueueScaling()) {
692 LOG(INFO) << "Unsupported";
693 return;
694 }
695
696 TwoThreadTestCase task_source(delegate_.get(), CreateTaskRunners(4));
697 Benchmark("post immediate tasks with four queues from two threads",
698 &task_source);
699 }
700
TEST_P(SequenceManagerPerfTest,PostImmediateTasksFromTwoThreads_EightQueues)701 TEST_P(SequenceManagerPerfTest, PostImmediateTasksFromTwoThreads_EightQueues) {
702 if (!ShouldMeasureQueueScaling()) {
703 LOG(INFO) << "Unsupported";
704 return;
705 }
706
707 TwoThreadTestCase task_source(delegate_.get(), CreateTaskRunners(8));
708 Benchmark("post immediate tasks with eight queues from two threads",
709 &task_source);
710 }
711
TEST_P(SequenceManagerPerfTest,PostImmediateTasksFromTwoThreads_ThirtyTwoQueues)712 TEST_P(SequenceManagerPerfTest,
713 PostImmediateTasksFromTwoThreads_ThirtyTwoQueues) {
714 if (!ShouldMeasureQueueScaling()) {
715 LOG(INFO) << "Unsupported";
716 return;
717 }
718
719 TwoThreadTestCase task_source(delegate_.get(), CreateTaskRunners(32));
720 Benchmark("post immediate tasks with thirty two queues from two threads",
721 &task_source);
722 }
723
724 // TODO(alexclarke): Add additional tests with different mixes of non-delayed vs
725 // delayed tasks.
726
727 } // namespace sequence_manager
728 } // namespace base
729