• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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