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/memory/raw_ptr.h"
6 #include "base/task/sequence_manager/sequence_manager.h"
7
8 #include <stddef.h>
9 #include <memory>
10
11 #include "base/functional/bind.h"
12 #include "base/logging.h"
13 #include "base/message_loop/message_pump_default.h"
14 #include "base/message_loop/message_pump_type.h"
15 #include "base/run_loop.h"
16 #include "base/sequence_checker.h"
17 #include "base/synchronization/condition_variable.h"
18 #include "base/task/sequence_manager/task_queue.h"
19 #include "base/task/sequence_manager/test/mock_time_domain.h"
20 #include "base/task/sequence_manager/test/sequence_manager_for_test.h"
21 #include "base/task/sequence_manager/test/test_task_time_observer.h"
22 #include "base/task/sequence_manager/thread_controller_with_message_pump_impl.h"
23 #include "base/task/single_thread_task_runner.h"
24 #include "base/task/task_traits.h"
25 #include "base/task/thread_pool.h"
26 #include "base/task/thread_pool/thread_pool_impl.h"
27 #include "base/task/thread_pool/thread_pool_instance.h"
28 #include "base/threading/thread.h"
29 #include "base/time/default_tick_clock.h"
30 #include "build/build_config.h"
31 #include "testing/gtest/include/gtest/gtest.h"
32 #include "testing/perf/perf_result_reporter.h"
33 #include "third_party/abseil-cpp/absl/types/optional.h"
34
35 namespace base {
36 namespace sequence_manager {
37 namespace {
38 const int kNumTasks = 1000000;
39
40 constexpr char kMetricPrefixSequenceManager[] = "SequenceManager.";
41 constexpr char kMetricPostTimePerTask[] = "post_time_per_task";
42
SetUpReporter(const std::string & story_name)43 perf_test::PerfResultReporter SetUpReporter(const std::string& story_name) {
44 perf_test::PerfResultReporter reporter(kMetricPrefixSequenceManager,
45 story_name);
46 reporter.RegisterImportantMetric(kMetricPostTimePerTask, "us");
47 return reporter;
48 }
49
50 } // namespace
51
52 // To reduce noise related to the OS timer, we use a mock time domain to
53 // fast forward the timers.
54 class PerfTestTimeDomain : public MockTimeDomain {
55 public:
PerfTestTimeDomain()56 PerfTestTimeDomain() : MockTimeDomain(TimeTicks::Now()) {}
57 PerfTestTimeDomain(const PerfTestTimeDomain&) = delete;
58 PerfTestTimeDomain& operator=(const PerfTestTimeDomain&) = delete;
59 ~PerfTestTimeDomain() override = default;
60
MaybeFastForwardToWakeUp(absl::optional<WakeUp> wake_up,bool quit_when_idle_requested)61 bool MaybeFastForwardToWakeUp(absl::optional<WakeUp> wake_up,
62 bool quit_when_idle_requested) override {
63 if (wake_up) {
64 SetNowTicks(wake_up->time);
65 return true;
66 }
67 return false;
68 }
69 };
70
71 enum class PerfTestType {
72 // A SequenceManager with a ThreadControllerWithMessagePumpImpl driving the
73 // thread.
74 kUseSequenceManagerWithMessagePump,
75 kUseSequenceManagerWithUIMessagePump,
76 kUseSequenceManagerWithIOMessagePump,
77 kUseSequenceManagerWithMessagePumpAndRandomSampling,
78
79 // A SingleThreadTaskRunner in the thread pool.
80 kUseSingleThreadInThreadPool,
81 };
82
83 // Customization point for SequenceManagerPerfTest which allows us to test
84 // various implementations.
85 class PerfTestDelegate {
86 public:
87 virtual ~PerfTestDelegate() = default;
88
89 virtual const char* GetName() const = 0;
90
91 virtual bool VirtualTimeIsSupported() const = 0;
92
93 virtual bool MultipleQueuesSupported() const = 0;
94
95 virtual scoped_refptr<TaskRunner> CreateTaskRunner() = 0;
96
97 virtual void WaitUntilDone() = 0;
98
99 virtual void SignalDone() = 0;
100 };
101
102 class BaseSequenceManagerPerfTestDelegate : public PerfTestDelegate {
103 public:
BaseSequenceManagerPerfTestDelegate()104 BaseSequenceManagerPerfTestDelegate() {}
105
106 ~BaseSequenceManagerPerfTestDelegate() override = default;
107
VirtualTimeIsSupported() const108 bool VirtualTimeIsSupported() const override { return true; }
109
MultipleQueuesSupported() const110 bool MultipleQueuesSupported() const override { return true; }
111
CreateTaskRunner()112 scoped_refptr<TaskRunner> CreateTaskRunner() override {
113 owned_task_queues_.push_back(
114 manager_->CreateTaskQueue(TaskQueue::Spec(QueueName::TEST_TQ)));
115 return owned_task_queues_.back()->task_runner();
116 }
117
WaitUntilDone()118 void WaitUntilDone() override {
119 run_loop_ = std::make_unique<RunLoop>();
120 run_loop_->Run();
121 }
122
SignalDone()123 void SignalDone() override { run_loop_->Quit(); }
124
GetManager() const125 SequenceManager* GetManager() const { return manager_.get(); }
126
SetSequenceManager(std::unique_ptr<SequenceManager> manager)127 void SetSequenceManager(std::unique_ptr<SequenceManager> manager) {
128 manager_ = std::move(manager);
129 time_domain_ = std::make_unique<PerfTestTimeDomain>();
130 manager_->SetTimeDomain(time_domain_.get());
131 }
132
ShutDown()133 void ShutDown() {
134 owned_task_queues_.clear();
135 manager_->ResetTimeDomain();
136 manager_.reset();
137 }
138
139 private:
140 std::unique_ptr<SequenceManager> manager_;
141 std::unique_ptr<TimeDomain> time_domain_;
142 std::unique_ptr<RunLoop> run_loop_;
143 std::vector<TaskQueue::Handle> owned_task_queues_;
144 };
145
146 class SequenceManagerWithMessagePumpPerfTestDelegate
147 : public BaseSequenceManagerPerfTestDelegate {
148 public:
SequenceManagerWithMessagePumpPerfTestDelegate(const char * name,MessagePumpType type,bool randomised_sampling_enabled=false)149 SequenceManagerWithMessagePumpPerfTestDelegate(
150 const char* name,
151 MessagePumpType type,
152 bool randomised_sampling_enabled = false)
153 : name_(name) {
154 auto settings =
155 SequenceManager::Settings::Builder()
156 .SetRandomisedSamplingEnabled(randomised_sampling_enabled)
157 .Build();
158 SetSequenceManager(SequenceManagerForTest::Create(
159 std::make_unique<internal::ThreadControllerWithMessagePumpImpl>(
160 MessagePump::Create(type), settings),
161 std::move(settings)));
162
163 // ThreadControllerWithMessagePumpImpl doesn't provide a default task
164 // runner.
165 default_task_queue_ =
166 GetManager()->CreateTaskQueue(TaskQueue::Spec(QueueName::DEFAULT_TQ));
167 GetManager()->SetDefaultTaskRunner(default_task_queue_->task_runner());
168 }
169
~SequenceManagerWithMessagePumpPerfTestDelegate()170 ~SequenceManagerWithMessagePumpPerfTestDelegate() override { ShutDown(); }
171
GetName() const172 const char* GetName() const override { return name_; }
173
174 private:
175 const char* const name_;
176 TaskQueue::Handle default_task_queue_;
177 };
178
179 class SingleThreadInThreadPoolPerfTestDelegate : public PerfTestDelegate {
180 public:
SingleThreadInThreadPoolPerfTestDelegate()181 SingleThreadInThreadPoolPerfTestDelegate() : done_cond_(&done_lock_) {
182 ThreadPoolInstance::Set(
183 std::make_unique<::base::internal::ThreadPoolImpl>("Test"));
184 ThreadPoolInstance::Get()->StartWithDefaultParams();
185 }
186
~SingleThreadInThreadPoolPerfTestDelegate()187 ~SingleThreadInThreadPoolPerfTestDelegate() override {
188 ThreadPoolInstance::Get()->JoinForTesting();
189 ThreadPoolInstance::Set(nullptr);
190 }
191
GetName() const192 const char* GetName() const override {
193 return " single thread in ThreadPool ";
194 }
195
VirtualTimeIsSupported() const196 bool VirtualTimeIsSupported() const override { return false; }
197
MultipleQueuesSupported() const198 bool MultipleQueuesSupported() const override { return false; }
199
CreateTaskRunner()200 scoped_refptr<TaskRunner> CreateTaskRunner() override {
201 return ThreadPool::CreateSingleThreadTaskRunner(
202 {TaskPriority::USER_BLOCKING});
203 }
204
WaitUntilDone()205 void WaitUntilDone() override {
206 AutoLock auto_lock(done_lock_);
207 done_cond_.Wait();
208 }
209
SignalDone()210 void SignalDone() override {
211 AutoLock auto_lock(done_lock_);
212 done_cond_.Signal();
213 }
214
215 private:
216 Lock done_lock_;
217 ConditionVariable done_cond_;
218 };
219
220 class TestCase {
221 public:
222 // |delegate| is assumed to outlive TestCase.
TestCase(PerfTestDelegate * delegate)223 explicit TestCase(PerfTestDelegate* delegate) : delegate_(delegate) {}
224
225 virtual ~TestCase() = default;
226
227 virtual void Start() = 0;
228
229 protected:
230 const raw_ptr<PerfTestDelegate> delegate_; // NOT OWNED
231 };
232
233 class TaskSource {
234 public:
235 virtual ~TaskSource() = default;
236
237 virtual void Start() = 0;
238 };
239
240 class SameThreadTaskSource : public TaskSource {
241 public:
SameThreadTaskSource(std::vector<scoped_refptr<TaskRunner>> task_runners,size_t num_tasks)242 SameThreadTaskSource(std::vector<scoped_refptr<TaskRunner>> task_runners,
243 size_t num_tasks)
244 : num_queues_(task_runners.size()),
245 num_tasks_(num_tasks),
246 task_closure_(
247 BindRepeating(&SameThreadTaskSource::TestTask, Unretained(this))),
248 task_runners_(std::move(task_runners)) {
249 DETACH_FROM_SEQUENCE(sequence_checker_);
250 }
251
Start()252 void Start() override {
253 num_tasks_in_flight_ = 1;
254 num_tasks_to_post_ = num_tasks_;
255 num_tasks_to_run_ = num_tasks_;
256 // Post the initial task instead of running it synchronously to ensure that
257 // all invocations happen on the same sequence.
258 PostTask(0);
259 }
260
261 protected:
262 virtual void PostTask(unsigned int queue) = 0;
263
264 virtual void SignalDone() = 0;
265
TestTask()266 void TestTask() {
267 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
268
269 if (--num_tasks_to_run_ == 0) {
270 SignalDone();
271 return;
272 }
273
274 num_tasks_in_flight_--;
275 // NOTE there are only up to max_tasks_in_flight_ pending delayed tasks at
276 // any one time. Thanks to the lower_num_tasks_to_post going to zero if
277 // there are a lot of tasks in flight, the total number of task in flight at
278 // any one time is very variable.
279 unsigned int lower_num_tasks_to_post =
280 num_tasks_in_flight_ < (max_tasks_in_flight_ / 2) ? 1 : 0;
281 unsigned int max_tasks_to_post =
282 num_tasks_to_post_ % 2 ? lower_num_tasks_to_post : 10;
283 for (unsigned int i = 0;
284 i < max_tasks_to_post && num_tasks_in_flight_ < max_tasks_in_flight_ &&
285 num_tasks_to_post_ > 0;
286 i++) {
287 // Choose a queue weighted towards queue 0.
288 unsigned int queue = num_tasks_to_post_ % (num_queues_ + 1);
289 if (queue == num_queues_) {
290 queue = 0;
291 }
292 PostTask(queue);
293 num_tasks_in_flight_++;
294 num_tasks_to_post_--;
295 }
296 }
297
298 const size_t num_queues_;
299 const size_t num_tasks_;
300 const RepeatingClosure task_closure_;
301 const std::vector<scoped_refptr<TaskRunner>> task_runners_;
302 const unsigned int max_tasks_in_flight_ = 200;
303 unsigned int num_tasks_in_flight_;
304 unsigned int num_tasks_to_post_;
305 unsigned int num_tasks_to_run_;
306 SEQUENCE_CHECKER(sequence_checker_);
307 };
308
309 class CrossThreadTaskSource : public TaskSource {
310 public:
CrossThreadTaskSource(std::vector<scoped_refptr<TaskRunner>> task_runners,size_t num_tasks)311 CrossThreadTaskSource(std::vector<scoped_refptr<TaskRunner>> task_runners,
312 size_t num_tasks)
313 : num_queues_(task_runners.size()),
314 num_tasks_(num_tasks),
315 task_closure_(
316 BindRepeating(&CrossThreadTaskSource::TestTask, Unretained(this))),
317 task_runners_(std::move(task_runners)) {}
318
Start()319 void Start() override {
320 num_tasks_in_flight_ = 0;
321 num_tasks_to_run_ = num_tasks_;
322
323 for (size_t i = 0; i < num_tasks_; i++) {
324 while (num_tasks_in_flight_.load(std::memory_order_acquire) >
325 max_tasks_in_flight_) {
326 PlatformThread::YieldCurrentThread();
327 }
328 // Choose a queue weighted towards queue 0.
329 unsigned int queue = i % (num_queues_ + 1);
330 if (queue == num_queues_) {
331 queue = 0;
332 }
333 PostTask(queue);
334 num_tasks_in_flight_++;
335 }
336 }
337
338 protected:
339 virtual void PostTask(unsigned int queue) = 0;
340
341 // Will be called on the main thread.
342 virtual void SignalDone() = 0;
343
TestTask()344 void TestTask() {
345 if (num_tasks_to_run_.fetch_sub(1) == 1) {
346 SignalDone();
347 return;
348 }
349 num_tasks_in_flight_--;
350 }
351
352 const size_t num_queues_;
353 const size_t num_tasks_;
354 const RepeatingClosure task_closure_;
355 const std::vector<scoped_refptr<TaskRunner>> task_runners_;
356 const unsigned int max_tasks_in_flight_ = 200;
357 std::atomic<unsigned int> num_tasks_in_flight_;
358 std::atomic<unsigned int> num_tasks_to_run_;
359 };
360
361 class SingleThreadImmediateTestCase : public TestCase {
362 public:
SingleThreadImmediateTestCase(PerfTestDelegate * delegate,std::vector<scoped_refptr<TaskRunner>> task_runners)363 SingleThreadImmediateTestCase(
364 PerfTestDelegate* delegate,
365 std::vector<scoped_refptr<TaskRunner>> task_runners)
366 : TestCase(delegate),
367 task_source_(std::make_unique<SingleThreadImmediateTaskSource>(
368 delegate,
369 std::move(task_runners),
370 kNumTasks)) {}
371
Start()372 void Start() override { task_source_->Start(); }
373
374 private:
375 class SingleThreadImmediateTaskSource : public SameThreadTaskSource {
376 public:
SingleThreadImmediateTaskSource(PerfTestDelegate * delegate,std::vector<scoped_refptr<TaskRunner>> task_runners,size_t num_tasks)377 SingleThreadImmediateTaskSource(
378 PerfTestDelegate* delegate,
379 std::vector<scoped_refptr<TaskRunner>> task_runners,
380 size_t num_tasks)
381 : SameThreadTaskSource(std::move(task_runners), num_tasks),
382 delegate_(delegate) {}
383
384 ~SingleThreadImmediateTaskSource() override = default;
385
PostTask(unsigned int queue)386 void PostTask(unsigned int queue) override {
387 task_runners_[queue]->PostTask(FROM_HERE, task_closure_);
388 }
389
SignalDone()390 void SignalDone() override { delegate_->SignalDone(); }
391
392 raw_ptr<PerfTestDelegate> delegate_; // NOT OWNED.
393 };
394
395 const std::unique_ptr<TaskSource> task_source_;
396 };
397
398 class SingleThreadDelayedTestCase : public TestCase {
399 public:
SingleThreadDelayedTestCase(PerfTestDelegate * delegate,std::vector<scoped_refptr<TaskRunner>> task_runners)400 SingleThreadDelayedTestCase(
401 PerfTestDelegate* delegate,
402 std::vector<scoped_refptr<TaskRunner>> task_runners)
403 : TestCase(delegate),
404 task_source_(std::make_unique<SingleThreadDelayedTaskSource>(
405 delegate,
406 std::move(task_runners),
407 kNumTasks)) {}
408
Start()409 void Start() override { task_source_->Start(); }
410
411 private:
412 class SingleThreadDelayedTaskSource : public SameThreadTaskSource {
413 public:
SingleThreadDelayedTaskSource(PerfTestDelegate * delegate,std::vector<scoped_refptr<TaskRunner>> task_runners,size_t num_tasks)414 explicit SingleThreadDelayedTaskSource(
415 PerfTestDelegate* delegate,
416 std::vector<scoped_refptr<TaskRunner>> task_runners,
417 size_t num_tasks)
418 : SameThreadTaskSource(std::move(task_runners), num_tasks),
419 delegate_(delegate) {}
420
421 ~SingleThreadDelayedTaskSource() override = default;
422
PostTask(unsigned int queue)423 void PostTask(unsigned int queue) override {
424 unsigned int delay =
425 num_tasks_to_post_ % 2 ? 1 : (10 + num_tasks_to_post_ % 10);
426 task_runners_[queue]->PostDelayedTask(FROM_HERE, task_closure_,
427 Milliseconds(delay));
428 }
429
SignalDone()430 void SignalDone() override { delegate_->SignalDone(); }
431
432 raw_ptr<PerfTestDelegate> delegate_; // NOT OWNED.
433 };
434
435 const std::unique_ptr<TaskSource> task_source_;
436 };
437
438 class TwoThreadTestCase : public TestCase {
439 public:
TwoThreadTestCase(PerfTestDelegate * delegate,std::vector<scoped_refptr<TaskRunner>> task_runners)440 TwoThreadTestCase(PerfTestDelegate* delegate,
441 std::vector<scoped_refptr<TaskRunner>> task_runners)
442 : TestCase(delegate),
443 task_runners_(std::move(task_runners)),
444 num_tasks_(kNumTasks),
445 auxiliary_thread_("auxillary thread") {
446 auxiliary_thread_.Start();
447 }
448
~TwoThreadTestCase()449 ~TwoThreadTestCase() override { auxiliary_thread_.Stop(); }
450
451 protected:
Start()452 void Start() override {
453 done_count_ = 0;
454 same_thread_task_source_ =
455 std::make_unique<SingleThreadImmediateTaskSource>(this, task_runners_,
456 num_tasks_ / 2);
457 cross_thread_task_scorce_ =
458 std::make_unique<CrossThreadImmediateTaskSource>(this, task_runners_,
459 num_tasks_ / 2);
460
461 auxiliary_thread_.task_runner()->PostTask(
462 FROM_HERE, base::BindOnce(&CrossThreadImmediateTaskSource::Start,
463 Unretained(cross_thread_task_scorce_.get())));
464 same_thread_task_source_->Start();
465 }
466
467 class SingleThreadImmediateTaskSource : public SameThreadTaskSource {
468 public:
SingleThreadImmediateTaskSource(TwoThreadTestCase * two_thread_test_case,std::vector<scoped_refptr<TaskRunner>> task_runners,size_t num_tasks)469 SingleThreadImmediateTaskSource(
470 TwoThreadTestCase* two_thread_test_case,
471 std::vector<scoped_refptr<TaskRunner>> task_runners,
472 size_t num_tasks)
473 : SameThreadTaskSource(std::move(task_runners), num_tasks),
474 two_thread_test_case_(two_thread_test_case) {}
475
476 ~SingleThreadImmediateTaskSource() override = default;
477
PostTask(unsigned int queue)478 void PostTask(unsigned int queue) override {
479 task_runners_[queue]->PostTask(FROM_HERE, task_closure_);
480 }
481
482 // Will be called on the main thread.
SignalDone()483 void SignalDone() override { two_thread_test_case_->SignalDone(); }
484
485 raw_ptr<TwoThreadTestCase> two_thread_test_case_; // NOT OWNED.
486 };
487
488 class CrossThreadImmediateTaskSource : public CrossThreadTaskSource {
489 public:
CrossThreadImmediateTaskSource(TwoThreadTestCase * two_thread_test_case,std::vector<scoped_refptr<TaskRunner>> task_runners,size_t num_tasks)490 CrossThreadImmediateTaskSource(
491 TwoThreadTestCase* two_thread_test_case,
492 std::vector<scoped_refptr<TaskRunner>> task_runners,
493 size_t num_tasks)
494 : CrossThreadTaskSource(std::move(task_runners), num_tasks),
495 two_thread_test_case_(two_thread_test_case) {}
496
497 ~CrossThreadImmediateTaskSource() override = default;
498
PostTask(unsigned int queue)499 void PostTask(unsigned int queue) override {
500 task_runners_[queue]->PostTask(FROM_HERE, task_closure_);
501 }
502
503 // Will be called on the main thread.
SignalDone()504 void SignalDone() override { two_thread_test_case_->SignalDone(); }
505
506 raw_ptr<TwoThreadTestCase> two_thread_test_case_; // NOT OWNED.
507 };
508
SignalDone()509 void SignalDone() {
510 if (++done_count_ == 2)
511 delegate_->SignalDone();
512 }
513
514 private:
515 const std::vector<scoped_refptr<TaskRunner>> task_runners_;
516 const size_t num_tasks_;
517 Thread auxiliary_thread_;
518 std::unique_ptr<SingleThreadImmediateTaskSource> same_thread_task_source_;
519 std::unique_ptr<CrossThreadImmediateTaskSource> cross_thread_task_scorce_;
520 int done_count_ = 0;
521 };
522
523 class SequenceManagerPerfTest : public testing::TestWithParam<PerfTestType> {
524 public:
525 SequenceManagerPerfTest() = default;
526
SetUp()527 void SetUp() override { delegate_ = CreateDelegate(); }
528
TearDown()529 void TearDown() override { delegate_.reset(); }
530
CreateDelegate()531 std::unique_ptr<PerfTestDelegate> CreateDelegate() {
532 switch (GetParam()) {
533 case PerfTestType::kUseSequenceManagerWithMessagePump:
534 return std::make_unique<SequenceManagerWithMessagePumpPerfTestDelegate>(
535 " SequenceManager with MessagePumpDefault ",
536 MessagePumpType::DEFAULT);
537
538 case PerfTestType::kUseSequenceManagerWithUIMessagePump:
539 return std::make_unique<SequenceManagerWithMessagePumpPerfTestDelegate>(
540 " SequenceManager with MessagePumpForUI ", MessagePumpType::UI);
541
542 case PerfTestType::kUseSequenceManagerWithIOMessagePump:
543 return std::make_unique<SequenceManagerWithMessagePumpPerfTestDelegate>(
544 " SequenceManager with MessagePumpForIO ", MessagePumpType::IO);
545
546 case PerfTestType::kUseSequenceManagerWithMessagePumpAndRandomSampling:
547 return std::make_unique<SequenceManagerWithMessagePumpPerfTestDelegate>(
548 " SequenceManager with MessagePumpDefault and random sampling ",
549 MessagePumpType::DEFAULT, true);
550
551 case PerfTestType::kUseSingleThreadInThreadPool:
552 return std::make_unique<SingleThreadInThreadPoolPerfTestDelegate>();
553
554 default:
555 NOTREACHED();
556 return nullptr;
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