| // Copyright 2015 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/memory/raw_ptr.h" |
| #include "base/task/sequence_manager/sequence_manager.h" |
| |
| #include <stddef.h> |
| #include <memory> |
| |
| #include "base/functional/bind.h" |
| #include "base/logging.h" |
| #include "base/message_loop/message_pump_default.h" |
| #include "base/message_loop/message_pump_type.h" |
| #include "base/run_loop.h" |
| #include "base/sequence_checker.h" |
| #include "base/synchronization/condition_variable.h" |
| #include "base/task/sequence_manager/task_queue.h" |
| #include "base/task/sequence_manager/test/mock_time_domain.h" |
| #include "base/task/sequence_manager/test/sequence_manager_for_test.h" |
| #include "base/task/sequence_manager/test/test_task_time_observer.h" |
| #include "base/task/sequence_manager/thread_controller_with_message_pump_impl.h" |
| #include "base/task/single_thread_task_runner.h" |
| #include "base/task/task_traits.h" |
| #include "base/task/thread_pool.h" |
| #include "base/task/thread_pool/thread_pool_impl.h" |
| #include "base/task/thread_pool/thread_pool_instance.h" |
| #include "base/threading/thread.h" |
| #include "base/time/default_tick_clock.h" |
| #include "build/build_config.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "testing/perf/perf_result_reporter.h" |
| #include "third_party/abseil-cpp/absl/types/optional.h" |
| |
| namespace base { |
| namespace sequence_manager { |
| namespace { |
| const int kNumTasks = 1000000; |
| |
| constexpr char kMetricPrefixSequenceManager[] = "SequenceManager."; |
| constexpr char kMetricPostTimePerTask[] = "post_time_per_task"; |
| |
| perf_test::PerfResultReporter SetUpReporter(const std::string& story_name) { |
| perf_test::PerfResultReporter reporter(kMetricPrefixSequenceManager, |
| story_name); |
| reporter.RegisterImportantMetric(kMetricPostTimePerTask, "us"); |
| return reporter; |
| } |
| |
| } // namespace |
| |
| // To reduce noise related to the OS timer, we use a mock time domain to |
| // fast forward the timers. |
| class PerfTestTimeDomain : public MockTimeDomain { |
| public: |
| PerfTestTimeDomain() : MockTimeDomain(TimeTicks::Now()) {} |
| PerfTestTimeDomain(const PerfTestTimeDomain&) = delete; |
| PerfTestTimeDomain& operator=(const PerfTestTimeDomain&) = delete; |
| ~PerfTestTimeDomain() override = default; |
| |
| bool MaybeFastForwardToWakeUp(absl::optional<WakeUp> wake_up, |
| bool quit_when_idle_requested) override { |
| if (wake_up) { |
| SetNowTicks(wake_up->time); |
| return true; |
| } |
| return false; |
| } |
| }; |
| |
| enum class PerfTestType { |
| // A SequenceManager with a ThreadControllerWithMessagePumpImpl driving the |
| // thread. |
| kUseSequenceManagerWithMessagePump, |
| kUseSequenceManagerWithUIMessagePump, |
| kUseSequenceManagerWithIOMessagePump, |
| kUseSequenceManagerWithMessagePumpAndRandomSampling, |
| |
| // A SingleThreadTaskRunner in the thread pool. |
| kUseSingleThreadInThreadPool, |
| }; |
| |
| // Customization point for SequenceManagerPerfTest which allows us to test |
| // various implementations. |
| class PerfTestDelegate { |
| public: |
| virtual ~PerfTestDelegate() = default; |
| |
| virtual const char* GetName() const = 0; |
| |
| virtual bool VirtualTimeIsSupported() const = 0; |
| |
| virtual bool MultipleQueuesSupported() const = 0; |
| |
| virtual scoped_refptr<TaskRunner> CreateTaskRunner() = 0; |
| |
| virtual void WaitUntilDone() = 0; |
| |
| virtual void SignalDone() = 0; |
| }; |
| |
| class BaseSequenceManagerPerfTestDelegate : public PerfTestDelegate { |
| public: |
| BaseSequenceManagerPerfTestDelegate() {} |
| |
| ~BaseSequenceManagerPerfTestDelegate() override = default; |
| |
| bool VirtualTimeIsSupported() const override { return true; } |
| |
| bool MultipleQueuesSupported() const override { return true; } |
| |
| scoped_refptr<TaskRunner> CreateTaskRunner() override { |
| scoped_refptr<TaskQueue> task_queue = |
| manager_->CreateTaskQueue(TaskQueue::Spec(QueueName::TEST_TQ)); |
| owned_task_queues_.push_back(task_queue); |
| return task_queue->task_runner(); |
| } |
| |
| void WaitUntilDone() override { |
| run_loop_ = std::make_unique<RunLoop>(); |
| run_loop_->Run(); |
| } |
| |
| void SignalDone() override { run_loop_->Quit(); } |
| |
| SequenceManager* GetManager() const { return manager_.get(); } |
| |
| void SetSequenceManager(std::unique_ptr<SequenceManager> manager) { |
| manager_ = std::move(manager); |
| time_domain_ = std::make_unique<PerfTestTimeDomain>(); |
| manager_->SetTimeDomain(time_domain_.get()); |
| } |
| |
| void ShutDown() { |
| owned_task_queues_.clear(); |
| manager_->ResetTimeDomain(); |
| manager_.reset(); |
| } |
| |
| private: |
| std::unique_ptr<SequenceManager> manager_; |
| std::unique_ptr<TimeDomain> time_domain_; |
| std::unique_ptr<RunLoop> run_loop_; |
| std::vector<scoped_refptr<TaskQueue>> owned_task_queues_; |
| }; |
| |
| class SequenceManagerWithMessagePumpPerfTestDelegate |
| : public BaseSequenceManagerPerfTestDelegate { |
| public: |
| SequenceManagerWithMessagePumpPerfTestDelegate( |
| const char* name, |
| MessagePumpType type, |
| bool randomised_sampling_enabled = false) |
| : name_(name) { |
| auto settings = |
| SequenceManager::Settings::Builder() |
| .SetRandomisedSamplingEnabled(randomised_sampling_enabled) |
| .Build(); |
| SetSequenceManager(SequenceManagerForTest::Create( |
| std::make_unique<internal::ThreadControllerWithMessagePumpImpl>( |
| MessagePump::Create(type), settings), |
| std::move(settings))); |
| |
| // ThreadControllerWithMessagePumpImpl doesn't provide a default task |
| // runner. |
| scoped_refptr<TaskQueue> default_task_queue = |
| GetManager()->CreateTaskQueue(TaskQueue::Spec(QueueName::DEFAULT_TQ)); |
| GetManager()->SetDefaultTaskRunner(default_task_queue->task_runner()); |
| } |
| |
| ~SequenceManagerWithMessagePumpPerfTestDelegate() override { ShutDown(); } |
| |
| const char* GetName() const override { return name_; } |
| |
| private: |
| const char* const name_; |
| }; |
| |
| class SingleThreadInThreadPoolPerfTestDelegate : public PerfTestDelegate { |
| public: |
| SingleThreadInThreadPoolPerfTestDelegate() : done_cond_(&done_lock_) { |
| ThreadPoolInstance::Set( |
| std::make_unique<::base::internal::ThreadPoolImpl>("Test")); |
| ThreadPoolInstance::Get()->StartWithDefaultParams(); |
| } |
| |
| ~SingleThreadInThreadPoolPerfTestDelegate() override { |
| ThreadPoolInstance::Get()->JoinForTesting(); |
| ThreadPoolInstance::Set(nullptr); |
| } |
| |
| const char* GetName() const override { |
| return " single thread in ThreadPool "; |
| } |
| |
| bool VirtualTimeIsSupported() const override { return false; } |
| |
| bool MultipleQueuesSupported() const override { return false; } |
| |
| scoped_refptr<TaskRunner> CreateTaskRunner() override { |
| return ThreadPool::CreateSingleThreadTaskRunner( |
| {TaskPriority::USER_BLOCKING}); |
| } |
| |
| void WaitUntilDone() override { |
| AutoLock auto_lock(done_lock_); |
| done_cond_.Wait(); |
| } |
| |
| void SignalDone() override { |
| AutoLock auto_lock(done_lock_); |
| done_cond_.Signal(); |
| } |
| |
| private: |
| Lock done_lock_; |
| ConditionVariable done_cond_; |
| }; |
| |
| class TestCase { |
| public: |
| // |delegate| is assumed to outlive TestCase. |
| explicit TestCase(PerfTestDelegate* delegate) : delegate_(delegate) {} |
| |
| virtual ~TestCase() = default; |
| |
| virtual void Start() = 0; |
| |
| protected: |
| const raw_ptr<PerfTestDelegate> delegate_; // NOT OWNED |
| }; |
| |
| class TaskSource { |
| public: |
| virtual ~TaskSource() = default; |
| |
| virtual void Start() = 0; |
| }; |
| |
| class SameThreadTaskSource : public TaskSource { |
| public: |
| SameThreadTaskSource(std::vector<scoped_refptr<TaskRunner>> task_runners, |
| size_t num_tasks) |
| : num_queues_(task_runners.size()), |
| num_tasks_(num_tasks), |
| task_closure_( |
| BindRepeating(&SameThreadTaskSource::TestTask, Unretained(this))), |
| task_runners_(std::move(task_runners)) { |
| DETACH_FROM_SEQUENCE(sequence_checker_); |
| } |
| |
| void Start() override { |
| num_tasks_in_flight_ = 1; |
| num_tasks_to_post_ = num_tasks_; |
| num_tasks_to_run_ = num_tasks_; |
| // Post the initial task instead of running it synchronously to ensure that |
| // all invocations happen on the same sequence. |
| PostTask(0); |
| } |
| |
| protected: |
| virtual void PostTask(unsigned int queue) = 0; |
| |
| virtual void SignalDone() = 0; |
| |
| void TestTask() { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| |
| if (--num_tasks_to_run_ == 0) { |
| SignalDone(); |
| return; |
| } |
| |
| num_tasks_in_flight_--; |
| // NOTE there are only up to max_tasks_in_flight_ pending delayed tasks at |
| // any one time. Thanks to the lower_num_tasks_to_post going to zero if |
| // there are a lot of tasks in flight, the total number of task in flight at |
| // any one time is very variable. |
| unsigned int lower_num_tasks_to_post = |
| num_tasks_in_flight_ < (max_tasks_in_flight_ / 2) ? 1 : 0; |
| unsigned int max_tasks_to_post = |
| num_tasks_to_post_ % 2 ? lower_num_tasks_to_post : 10; |
| for (unsigned int i = 0; |
| i < max_tasks_to_post && num_tasks_in_flight_ < max_tasks_in_flight_ && |
| num_tasks_to_post_ > 0; |
| i++) { |
| // Choose a queue weighted towards queue 0. |
| unsigned int queue = num_tasks_to_post_ % (num_queues_ + 1); |
| if (queue == num_queues_) { |
| queue = 0; |
| } |
| PostTask(queue); |
| num_tasks_in_flight_++; |
| num_tasks_to_post_--; |
| } |
| } |
| |
| const size_t num_queues_; |
| const size_t num_tasks_; |
| const RepeatingClosure task_closure_; |
| const std::vector<scoped_refptr<TaskRunner>> task_runners_; |
| const unsigned int max_tasks_in_flight_ = 200; |
| unsigned int num_tasks_in_flight_; |
| unsigned int num_tasks_to_post_; |
| unsigned int num_tasks_to_run_; |
| SEQUENCE_CHECKER(sequence_checker_); |
| }; |
| |
| class CrossThreadTaskSource : public TaskSource { |
| public: |
| CrossThreadTaskSource(std::vector<scoped_refptr<TaskRunner>> task_runners, |
| size_t num_tasks) |
| : num_queues_(task_runners.size()), |
| num_tasks_(num_tasks), |
| task_closure_( |
| BindRepeating(&CrossThreadTaskSource::TestTask, Unretained(this))), |
| task_runners_(std::move(task_runners)) {} |
| |
| void Start() override { |
| num_tasks_in_flight_ = 0; |
| num_tasks_to_run_ = num_tasks_; |
| |
| for (size_t i = 0; i < num_tasks_; i++) { |
| while (num_tasks_in_flight_.load(std::memory_order_acquire) > |
| max_tasks_in_flight_) { |
| PlatformThread::YieldCurrentThread(); |
| } |
| // Choose a queue weighted towards queue 0. |
| unsigned int queue = i % (num_queues_ + 1); |
| if (queue == num_queues_) { |
| queue = 0; |
| } |
| PostTask(queue); |
| num_tasks_in_flight_++; |
| } |
| } |
| |
| protected: |
| virtual void PostTask(unsigned int queue) = 0; |
| |
| // Will be called on the main thread. |
| virtual void SignalDone() = 0; |
| |
| void TestTask() { |
| if (num_tasks_to_run_.fetch_sub(1) == 1) { |
| SignalDone(); |
| return; |
| } |
| num_tasks_in_flight_--; |
| } |
| |
| const size_t num_queues_; |
| const size_t num_tasks_; |
| const RepeatingClosure task_closure_; |
| const std::vector<scoped_refptr<TaskRunner>> task_runners_; |
| const unsigned int max_tasks_in_flight_ = 200; |
| std::atomic<unsigned int> num_tasks_in_flight_; |
| std::atomic<unsigned int> num_tasks_to_run_; |
| }; |
| |
| class SingleThreadImmediateTestCase : public TestCase { |
| public: |
| SingleThreadImmediateTestCase( |
| PerfTestDelegate* delegate, |
| std::vector<scoped_refptr<TaskRunner>> task_runners) |
| : TestCase(delegate), |
| task_source_(std::make_unique<SingleThreadImmediateTaskSource>( |
| delegate, |
| std::move(task_runners), |
| kNumTasks)) {} |
| |
| void Start() override { task_source_->Start(); } |
| |
| private: |
| class SingleThreadImmediateTaskSource : public SameThreadTaskSource { |
| public: |
| SingleThreadImmediateTaskSource( |
| PerfTestDelegate* delegate, |
| std::vector<scoped_refptr<TaskRunner>> task_runners, |
| size_t num_tasks) |
| : SameThreadTaskSource(std::move(task_runners), num_tasks), |
| delegate_(delegate) {} |
| |
| ~SingleThreadImmediateTaskSource() override = default; |
| |
| void PostTask(unsigned int queue) override { |
| task_runners_[queue]->PostTask(FROM_HERE, task_closure_); |
| } |
| |
| void SignalDone() override { delegate_->SignalDone(); } |
| |
| raw_ptr<PerfTestDelegate> delegate_; // NOT OWNED. |
| }; |
| |
| const std::unique_ptr<TaskSource> task_source_; |
| }; |
| |
| class SingleThreadDelayedTestCase : public TestCase { |
| public: |
| SingleThreadDelayedTestCase( |
| PerfTestDelegate* delegate, |
| std::vector<scoped_refptr<TaskRunner>> task_runners) |
| : TestCase(delegate), |
| task_source_(std::make_unique<SingleThreadDelayedTaskSource>( |
| delegate, |
| std::move(task_runners), |
| kNumTasks)) {} |
| |
| void Start() override { task_source_->Start(); } |
| |
| private: |
| class SingleThreadDelayedTaskSource : public SameThreadTaskSource { |
| public: |
| explicit SingleThreadDelayedTaskSource( |
| PerfTestDelegate* delegate, |
| std::vector<scoped_refptr<TaskRunner>> task_runners, |
| size_t num_tasks) |
| : SameThreadTaskSource(std::move(task_runners), num_tasks), |
| delegate_(delegate) {} |
| |
| ~SingleThreadDelayedTaskSource() override = default; |
| |
| void PostTask(unsigned int queue) override { |
| unsigned int delay = |
| num_tasks_to_post_ % 2 ? 1 : (10 + num_tasks_to_post_ % 10); |
| task_runners_[queue]->PostDelayedTask(FROM_HERE, task_closure_, |
| Milliseconds(delay)); |
| } |
| |
| void SignalDone() override { delegate_->SignalDone(); } |
| |
| raw_ptr<PerfTestDelegate> delegate_; // NOT OWNED. |
| }; |
| |
| const std::unique_ptr<TaskSource> task_source_; |
| }; |
| |
| class TwoThreadTestCase : public TestCase { |
| public: |
| TwoThreadTestCase(PerfTestDelegate* delegate, |
| std::vector<scoped_refptr<TaskRunner>> task_runners) |
| : TestCase(delegate), |
| task_runners_(std::move(task_runners)), |
| num_tasks_(kNumTasks), |
| auxiliary_thread_("auxillary thread") { |
| auxiliary_thread_.Start(); |
| } |
| |
| ~TwoThreadTestCase() override { auxiliary_thread_.Stop(); } |
| |
| protected: |
| void Start() override { |
| done_count_ = 0; |
| same_thread_task_source_ = |
| std::make_unique<SingleThreadImmediateTaskSource>(this, task_runners_, |
| num_tasks_ / 2); |
| cross_thread_task_scorce_ = |
| std::make_unique<CrossThreadImmediateTaskSource>(this, task_runners_, |
| num_tasks_ / 2); |
| |
| auxiliary_thread_.task_runner()->PostTask( |
| FROM_HERE, base::BindOnce(&CrossThreadImmediateTaskSource::Start, |
| Unretained(cross_thread_task_scorce_.get()))); |
| same_thread_task_source_->Start(); |
| } |
| |
| class SingleThreadImmediateTaskSource : public SameThreadTaskSource { |
| public: |
| SingleThreadImmediateTaskSource( |
| TwoThreadTestCase* two_thread_test_case, |
| std::vector<scoped_refptr<TaskRunner>> task_runners, |
| size_t num_tasks) |
| : SameThreadTaskSource(std::move(task_runners), num_tasks), |
| two_thread_test_case_(two_thread_test_case) {} |
| |
| ~SingleThreadImmediateTaskSource() override = default; |
| |
| void PostTask(unsigned int queue) override { |
| task_runners_[queue]->PostTask(FROM_HERE, task_closure_); |
| } |
| |
| // Will be called on the main thread. |
| void SignalDone() override { two_thread_test_case_->SignalDone(); } |
| |
| raw_ptr<TwoThreadTestCase> two_thread_test_case_; // NOT OWNED. |
| }; |
| |
| class CrossThreadImmediateTaskSource : public CrossThreadTaskSource { |
| public: |
| CrossThreadImmediateTaskSource( |
| TwoThreadTestCase* two_thread_test_case, |
| std::vector<scoped_refptr<TaskRunner>> task_runners, |
| size_t num_tasks) |
| : CrossThreadTaskSource(std::move(task_runners), num_tasks), |
| two_thread_test_case_(two_thread_test_case) {} |
| |
| ~CrossThreadImmediateTaskSource() override = default; |
| |
| void PostTask(unsigned int queue) override { |
| task_runners_[queue]->PostTask(FROM_HERE, task_closure_); |
| } |
| |
| // Will be called on the main thread. |
| void SignalDone() override { two_thread_test_case_->SignalDone(); } |
| |
| raw_ptr<TwoThreadTestCase> two_thread_test_case_; // NOT OWNED. |
| }; |
| |
| void SignalDone() { |
| if (++done_count_ == 2) |
| delegate_->SignalDone(); |
| } |
| |
| private: |
| const std::vector<scoped_refptr<TaskRunner>> task_runners_; |
| const size_t num_tasks_; |
| Thread auxiliary_thread_; |
| std::unique_ptr<SingleThreadImmediateTaskSource> same_thread_task_source_; |
| std::unique_ptr<CrossThreadImmediateTaskSource> cross_thread_task_scorce_; |
| int done_count_ = 0; |
| }; |
| |
| class SequenceManagerPerfTest : public testing::TestWithParam<PerfTestType> { |
| public: |
| SequenceManagerPerfTest() = default; |
| |
| void SetUp() override { delegate_ = CreateDelegate(); } |
| |
| void TearDown() override { delegate_.reset(); } |
| |
| std::unique_ptr<PerfTestDelegate> CreateDelegate() { |
| switch (GetParam()) { |
| case PerfTestType::kUseSequenceManagerWithMessagePump: |
| return std::make_unique<SequenceManagerWithMessagePumpPerfTestDelegate>( |
| " SequenceManager with MessagePumpDefault ", |
| MessagePumpType::DEFAULT); |
| |
| case PerfTestType::kUseSequenceManagerWithUIMessagePump: |
| return std::make_unique<SequenceManagerWithMessagePumpPerfTestDelegate>( |
| " SequenceManager with MessagePumpForUI ", MessagePumpType::UI); |
| |
| case PerfTestType::kUseSequenceManagerWithIOMessagePump: |
| return std::make_unique<SequenceManagerWithMessagePumpPerfTestDelegate>( |
| " SequenceManager with MessagePumpForIO ", MessagePumpType::IO); |
| |
| case PerfTestType::kUseSequenceManagerWithMessagePumpAndRandomSampling: |
| return std::make_unique<SequenceManagerWithMessagePumpPerfTestDelegate>( |
| " SequenceManager with MessagePumpDefault and random sampling ", |
| MessagePumpType::DEFAULT, true); |
| |
| case PerfTestType::kUseSingleThreadInThreadPool: |
| return std::make_unique<SingleThreadInThreadPoolPerfTestDelegate>(); |
| |
| default: |
| NOTREACHED(); |
| return nullptr; |
| } |
| } |
| |
| bool ShouldMeasureQueueScaling() const { |
| // To limit test run time, we only measure multiple queues specific sequence |
| // manager configurations. |
| return delegate_->MultipleQueuesSupported() && |
| GetParam() == PerfTestType::kUseSequenceManagerWithUIMessagePump; |
| } |
| |
| std::vector<scoped_refptr<TaskRunner>> CreateTaskRunners(int num) { |
| std::vector<scoped_refptr<TaskRunner>> task_runners; |
| for (int i = 0; i < num; i++) { |
| task_runners.push_back(delegate_->CreateTaskRunner()); |
| } |
| return task_runners; |
| } |
| |
| void Benchmark(const std::string& story_prefix, TestCase* TestCase) { |
| TimeTicks start = TimeTicks::Now(); |
| TimeTicks now; |
| TestCase->Start(); |
| delegate_->WaitUntilDone(); |
| now = TimeTicks::Now(); |
| |
| auto reporter = SetUpReporter(story_prefix + delegate_->GetName()); |
| reporter.AddResult( |
| kMetricPostTimePerTask, |
| (now - start).InMicroseconds() / static_cast<double>(kNumTasks)); |
| } |
| |
| std::unique_ptr<PerfTestDelegate> delegate_; |
| }; |
| |
| INSTANTIATE_TEST_SUITE_P( |
| All, |
| SequenceManagerPerfTest, |
| testing::Values( |
| PerfTestType::kUseSequenceManagerWithMessagePump, |
| PerfTestType::kUseSequenceManagerWithUIMessagePump, |
| PerfTestType::kUseSequenceManagerWithIOMessagePump, |
| PerfTestType::kUseSingleThreadInThreadPool, |
| PerfTestType::kUseSequenceManagerWithMessagePumpAndRandomSampling)); |
| TEST_P(SequenceManagerPerfTest, PostDelayedTasks_OneQueue) { |
| if (!delegate_->VirtualTimeIsSupported()) { |
| LOG(INFO) << "Unsupported"; |
| return; |
| } |
| |
| SingleThreadDelayedTestCase task_source(delegate_.get(), |
| CreateTaskRunners(1)); |
| Benchmark("post delayed tasks with one queue", &task_source); |
| } |
| |
| TEST_P(SequenceManagerPerfTest, PostDelayedTasks_FourQueues) { |
| if (!delegate_->VirtualTimeIsSupported() || !ShouldMeasureQueueScaling()) { |
| LOG(INFO) << "Unsupported"; |
| return; |
| } |
| |
| SingleThreadDelayedTestCase task_source(delegate_.get(), |
| CreateTaskRunners(4)); |
| Benchmark("post delayed tasks with four queues", &task_source); |
| } |
| |
| TEST_P(SequenceManagerPerfTest, PostDelayedTasks_EightQueues) { |
| if (!delegate_->VirtualTimeIsSupported() || !ShouldMeasureQueueScaling()) { |
| LOG(INFO) << "Unsupported"; |
| return; |
| } |
| |
| SingleThreadDelayedTestCase task_source(delegate_.get(), |
| CreateTaskRunners(8)); |
| Benchmark("post delayed tasks with eight queues", &task_source); |
| } |
| |
| TEST_P(SequenceManagerPerfTest, PostDelayedTasks_ThirtyTwoQueues) { |
| if (!delegate_->VirtualTimeIsSupported() || !ShouldMeasureQueueScaling()) { |
| LOG(INFO) << "Unsupported"; |
| return; |
| } |
| |
| SingleThreadDelayedTestCase task_source(delegate_.get(), |
| CreateTaskRunners(32)); |
| Benchmark("post delayed tasks with thirty two queues", &task_source); |
| } |
| |
| TEST_P(SequenceManagerPerfTest, PostImmediateTasks_OneQueue) { |
| SingleThreadImmediateTestCase task_source(delegate_.get(), |
| CreateTaskRunners(1)); |
| Benchmark("post immediate tasks with one queue", &task_source); |
| } |
| |
| TEST_P(SequenceManagerPerfTest, PostImmediateTasks_FourQueues) { |
| if (!ShouldMeasureQueueScaling()) { |
| LOG(INFO) << "Unsupported"; |
| return; |
| } |
| |
| SingleThreadImmediateTestCase task_source(delegate_.get(), |
| CreateTaskRunners(4)); |
| Benchmark("post immediate tasks with four queues", &task_source); |
| } |
| |
| TEST_P(SequenceManagerPerfTest, PostImmediateTasks_EightQueues) { |
| if (!ShouldMeasureQueueScaling()) { |
| LOG(INFO) << "Unsupported"; |
| return; |
| } |
| |
| SingleThreadImmediateTestCase task_source(delegate_.get(), |
| CreateTaskRunners(8)); |
| Benchmark("post immediate tasks with eight queues", &task_source); |
| } |
| |
| TEST_P(SequenceManagerPerfTest, PostImmediateTasks_ThirtyTwoQueues) { |
| if (!ShouldMeasureQueueScaling()) { |
| LOG(INFO) << "Unsupported"; |
| return; |
| } |
| |
| SingleThreadImmediateTestCase task_source(delegate_.get(), |
| CreateTaskRunners(32)); |
| Benchmark("post immediate tasks with thirty two queues", &task_source); |
| } |
| |
| TEST_P(SequenceManagerPerfTest, PostImmediateTasksFromTwoThreads_OneQueue) { |
| TwoThreadTestCase task_source(delegate_.get(), CreateTaskRunners(1)); |
| Benchmark("post immediate tasks with one queue from two threads", |
| &task_source); |
| } |
| |
| TEST_P(SequenceManagerPerfTest, PostImmediateTasksFromTwoThreads_FourQueues) { |
| if (!ShouldMeasureQueueScaling()) { |
| LOG(INFO) << "Unsupported"; |
| return; |
| } |
| |
| TwoThreadTestCase task_source(delegate_.get(), CreateTaskRunners(4)); |
| Benchmark("post immediate tasks with four queues from two threads", |
| &task_source); |
| } |
| |
| TEST_P(SequenceManagerPerfTest, PostImmediateTasksFromTwoThreads_EightQueues) { |
| if (!ShouldMeasureQueueScaling()) { |
| LOG(INFO) << "Unsupported"; |
| return; |
| } |
| |
| TwoThreadTestCase task_source(delegate_.get(), CreateTaskRunners(8)); |
| Benchmark("post immediate tasks with eight queues from two threads", |
| &task_source); |
| } |
| |
| TEST_P(SequenceManagerPerfTest, |
| PostImmediateTasksFromTwoThreads_ThirtyTwoQueues) { |
| if (!ShouldMeasureQueueScaling()) { |
| LOG(INFO) << "Unsupported"; |
| return; |
| } |
| |
| TwoThreadTestCase task_source(delegate_.get(), CreateTaskRunners(32)); |
| Benchmark("post immediate tasks with thirty two queues from two threads", |
| &task_source); |
| } |
| |
| // TODO(alexclarke): Add additional tests with different mixes of non-delayed vs |
| // delayed tasks. |
| |
| } // namespace sequence_manager |
| } // namespace base |