• 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