xref: /aosp_15_r20/external/cronet/base/task/sequence_manager/sequence_manager_perftest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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