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