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