• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  // Copyright 2018 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/message_loop/message_loop_task_runner.h"
6  
7  #include <string>
8  #include <utility>
9  
10  #include "base/bind_helpers.h"
11  #include "base/callback.h"
12  #include "base/debug/task_annotator.h"
13  #include "base/macros.h"
14  #include "base/memory/scoped_refptr.h"
15  #include "base/message_loop/incoming_task_queue.h"
16  #include "base/message_loop/message_loop.h"
17  #include "base/message_loop/message_loop_task_runner.h"
18  #include "base/message_loop/message_pump.h"
19  #include "base/run_loop.h"
20  #include "base/strings/stringprintf.h"
21  #include "base/time/time.h"
22  #include "testing/gtest/include/gtest/gtest.h"
23  #include "testing/perf/perf_test.h"
24  
25  namespace base {
26  
27  namespace {
28  
29  // Tests below will post tasks in a loop until |kPostTaskPerfTestDuration| has
30  // elapsed.
31  constexpr TimeDelta kPostTaskPerfTestDuration =
32      base::TimeDelta::FromSeconds(30);
33  
34  }  // namespace
35  
36  class FakeObserver : public internal::IncomingTaskQueue::Observer {
37   public:
38    // IncomingTaskQueue::Observer
WillQueueTask(PendingTask * task)39    void WillQueueTask(PendingTask* task) override {}
DidQueueTask(bool was_empty)40    void DidQueueTask(bool was_empty) override {}
41  
RunTask(PendingTask * task)42    virtual void RunTask(PendingTask* task) { std::move(task->task).Run(); }
43  };
44  
45  // Exercises MessageLoopTaskRunner's multi-threaded queue in isolation.
46  class BasicPostTaskPerfTest : public testing::Test {
47   public:
Run(int batch_size,int tasks_per_reload,std::unique_ptr<FakeObserver> task_source_observer)48    void Run(int batch_size,
49             int tasks_per_reload,
50             std::unique_ptr<FakeObserver> task_source_observer) {
51      base::TimeTicks start = base::TimeTicks::Now();
52      base::TimeTicks now;
53      FakeObserver* task_source_observer_raw = task_source_observer.get();
54      scoped_refptr<internal::IncomingTaskQueue> queue(
55          base::MakeRefCounted<internal::IncomingTaskQueue>(
56              std::move(task_source_observer)));
57      scoped_refptr<SingleThreadTaskRunner> task_runner(
58          base::MakeRefCounted<internal::MessageLoopTaskRunner>(queue));
59      uint32_t num_posted = 0;
60      do {
61        for (int i = 0; i < batch_size; ++i) {
62          for (int j = 0; j < tasks_per_reload; ++j) {
63            task_runner->PostTask(FROM_HERE, DoNothing());
64            num_posted++;
65          }
66          TaskQueue loop_local_queue;
67          queue->ReloadWorkQueue(&loop_local_queue);
68          while (!loop_local_queue.empty()) {
69            PendingTask t = std::move(loop_local_queue.front());
70            loop_local_queue.pop();
71            task_source_observer_raw->RunTask(&t);
72          }
73        }
74  
75        now = base::TimeTicks::Now();
76      } while (now - start < kPostTaskPerfTestDuration);
77      std::string trace = StringPrintf("%d_tasks_per_reload", tasks_per_reload);
78      perf_test::PrintResult(
79          "task", "", trace,
80          (now - start).InMicroseconds() / static_cast<double>(num_posted),
81          "us/task", true);
82    }
83  };
84  
TEST_F(BasicPostTaskPerfTest,OneTaskPerReload)85  TEST_F(BasicPostTaskPerfTest, OneTaskPerReload) {
86    Run(10000, 1, std::make_unique<FakeObserver>());
87  }
88  
TEST_F(BasicPostTaskPerfTest,TenTasksPerReload)89  TEST_F(BasicPostTaskPerfTest, TenTasksPerReload) {
90    Run(10000, 10, std::make_unique<FakeObserver>());
91  }
92  
TEST_F(BasicPostTaskPerfTest,OneHundredTasksPerReload)93  TEST_F(BasicPostTaskPerfTest, OneHundredTasksPerReload) {
94    Run(1000, 100, std::make_unique<FakeObserver>());
95  }
96  
97  class StubMessagePump : public MessagePump {
98   public:
99    StubMessagePump() = default;
100    ~StubMessagePump() override = default;
101  
102    // MessagePump:
Run(Delegate * delegate)103    void Run(Delegate* delegate) override {}
Quit()104    void Quit() override {}
ScheduleWork()105    void ScheduleWork() override {}
ScheduleDelayedWork(const TimeTicks & delayed_work_time)106    void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override {}
107  };
108  
109  // Simulates the overhead of hooking TaskAnnotator and ScheduleWork() to the
110  // post task machinery.
111  class FakeObserverSimulatingOverhead : public FakeObserver {
112   public:
113    FakeObserverSimulatingOverhead() = default;
114  
115    // FakeObserver:
WillQueueTask(PendingTask * task)116    void WillQueueTask(PendingTask* task) final {
117      task_annotator_.WillQueueTask("MessageLoop::PostTask", task);
118    }
119  
DidQueueTask(bool was_empty)120    void DidQueueTask(bool was_empty) final {
121      AutoLock scoped_lock(message_loop_lock_);
122      pump_->ScheduleWork();
123    }
124  
RunTask(PendingTask * task)125    void RunTask(PendingTask* task) final {
126      task_annotator_.RunTask("MessageLoop::PostTask", task);
127    }
128  
129   private:
130    // Simulates overhead from ScheduleWork() and TaskAnnotator calls involved in
131    // a real PostTask (stores the StubMessagePump in a pointer to force a virtual
132    // dispatch for ScheduleWork() and be closer to reality).
133    Lock message_loop_lock_;
134    std::unique_ptr<MessagePump> pump_{std::make_unique<StubMessagePump>()};
135    debug::TaskAnnotator task_annotator_;
136  
137    DISALLOW_COPY_AND_ASSIGN(FakeObserverSimulatingOverhead);
138  };
139  
TEST_F(BasicPostTaskPerfTest,OneTaskPerReloadWithOverhead)140  TEST_F(BasicPostTaskPerfTest, OneTaskPerReloadWithOverhead) {
141    Run(10000, 1, std::make_unique<FakeObserverSimulatingOverhead>());
142  }
143  
TEST_F(BasicPostTaskPerfTest,TenTasksPerReloadWithOverhead)144  TEST_F(BasicPostTaskPerfTest, TenTasksPerReloadWithOverhead) {
145    Run(10000, 10, std::make_unique<FakeObserverSimulatingOverhead>());
146  }
147  
TEST_F(BasicPostTaskPerfTest,OneHundredTasksPerReloadWithOverhead)148  TEST_F(BasicPostTaskPerfTest, OneHundredTasksPerReloadWithOverhead) {
149    Run(1000, 100, std::make_unique<FakeObserverSimulatingOverhead>());
150  }
151  
152  // Exercises the full MessageLoop/RunLoop machinery.
153  class IntegratedPostTaskPerfTest : public testing::Test {
154   public:
Run(int batch_size,int tasks_per_reload)155    void Run(int batch_size, int tasks_per_reload) {
156      base::TimeTicks start = base::TimeTicks::Now();
157      base::TimeTicks now;
158      MessageLoop loop;
159      uint32_t num_posted = 0;
160      do {
161        for (int i = 0; i < batch_size; ++i) {
162          for (int j = 0; j < tasks_per_reload; ++j) {
163            loop->task_runner()->PostTask(FROM_HERE, DoNothing());
164            num_posted++;
165          }
166          RunLoop().RunUntilIdle();
167        }
168  
169        now = base::TimeTicks::Now();
170      } while (now - start < kPostTaskPerfTestDuration);
171      std::string trace = StringPrintf("%d_tasks_per_reload", tasks_per_reload);
172      perf_test::PrintResult(
173          "task", "", trace,
174          (now - start).InMicroseconds() / static_cast<double>(num_posted),
175          "us/task", true);
176    }
177  };
178  
TEST_F(IntegratedPostTaskPerfTest,OneTaskPerReload)179  TEST_F(IntegratedPostTaskPerfTest, OneTaskPerReload) {
180    Run(10000, 1);
181  }
182  
TEST_F(IntegratedPostTaskPerfTest,TenTasksPerReload)183  TEST_F(IntegratedPostTaskPerfTest, TenTasksPerReload) {
184    Run(10000, 10);
185  }
186  
TEST_F(IntegratedPostTaskPerfTest,OneHundredTasksPerReload)187  TEST_F(IntegratedPostTaskPerfTest, OneHundredTasksPerReload) {
188    Run(1000, 100);
189  }
190  
191  }  // namespace base
192