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