Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(461)

Side by Side Diff: base/task_scheduler/thread_pool_unittest.cc

Issue 1685423002: Task Scheduler. (Closed) Base URL: https://luckyluke-private.googlesource.com/src@a_master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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_scheduler/thread_pool.h"
6
7 #include "base/bind.h"
8 #include "base/callback_forward.h"
9 #include "base/synchronization/condition_variable.h"
10 #include "base/task_scheduler/scheduler_lock.h"
11 #include "base/task_scheduler/shutdown_manager.h"
12 #include "base/task_scheduler/worker_thread.h"
13 #include "base/threading/platform_thread.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15
16 namespace base {
17 namespace task_scheduler {
18
19 namespace {
20 class SingleThreadChecker {
21 public:
22 SingleThreadChecker() : ran_all_tasks_on_same_thread_(true) {}
23
24 void RunTask() {
25 AutoSchedulerLock auto_lock(lock_);
26
27 if (!last_thread_handle_.is_null() &&
28 !PlatformThread::CurrentHandle().is_equal(last_thread_handle_)) {
29 ran_all_tasks_on_same_thread_ = false;
30 }
31 last_thread_handle_ = PlatformThread::CurrentHandle();
32 }
33
34 bool ran_all_tasks_on_same_thread() const {
35 return ran_all_tasks_on_same_thread_;
36 }
37
38 private:
39 PlatformThreadHandle last_thread_handle_;
40 bool ran_all_tasks_on_same_thread_;
41 SchedulerLock lock_;
42 };
43 } // namespace
44
45 class TaskSchedulerThreadPoolTest : public testing::Test {
46 protected:
47 TaskSchedulerThreadPoolTest()
48 : thread_pool_(ThreadPool::CreateThreadPool(
49 ThreadPriority::NORMAL,
50 4,
51 Bind(&TaskSchedulerThreadPoolTest::ReinsertSequenceCallback,
52 Unretained(this)),
53 &shutdown_manager_)),
54 cv_(lock_.RawLockForConditionVariable()),
55 last_posted_task_index_(0),
56 last_run_task_index_(0),
57 ran_task_that_should_not_run_(false) {}
58
59 Closure GetTaskThatShouldRunClosure(
60 SingleThreadChecker* single_thread_checker) {
61 ++last_posted_task_index_;
62 return Bind(&TaskSchedulerThreadPoolTest::RunTaskThatShouldRun,
63 Unretained(this), last_posted_task_index_,
64 single_thread_checker);
65 }
66
67 Closure GetTaskThatShouldNotRunClosure() {
68 return Bind(&TaskSchedulerThreadPoolTest::RunTaskThatShouldNotRun,
69 Unretained(this));
70 }
71
72 void WaitUntilLastPostedTaskHasRun() {
73 AutoSchedulerLock auto_lock(lock_);
74 while (last_posted_task_index_ != last_run_task_index_)
75 cv_.Wait();
76 }
77
78 void Shutdown() {
79 shutdown_manager_.Shutdown();
80 thread_pool_->JoinAllThreadsForTesting();
81 }
82
83 bool ran_task_that_should_not_run() const {
84 return ran_task_that_should_not_run_;
85 }
86
87 scoped_ptr<ThreadPool> thread_pool_;
88 ShutdownManager shutdown_manager_;
89
90 private:
91 void ReinsertSequenceCallback(scoped_refptr<Sequence> sequence,
92 const WorkerThread* worker_thread) {
93 thread_pool_->ReinsertSequence(sequence, sequence->GetSortKey(),
94 worker_thread);
95 }
96
97 void RunTaskThatShouldRun(size_t index,
98 SingleThreadChecker* single_thread_checker) {
99 AutoSchedulerLock auto_lock(lock_);
100
101 if (single_thread_checker)
102 single_thread_checker->RunTask();
103
104 // Wait until the task with index (|index| - 1) has run. If tasks are
105 // executed in the wrong order, this can block forever and make the test
106 // fail.
107 //
108 // Note: It isn't correct to assume that this condition will always be
109 // immediatly true if tasks are popped from the priority queue in the right
110 // order. Indeed, a thread A could start running task #2 before a thread B
111 // starts running task #1 despite the fact that thread B has popped task #1
112 // before thread A has popped task #2.
113 while (last_run_task_index_ != index - 1)
114 cv_.Wait();
115
116 ++last_run_task_index_;
117 cv_.Broadcast();
118 }
119
120 void RunTaskThatShouldNotRun() { ran_task_that_should_not_run_ = true; }
121
122 // Lock protecting |cv_|.
123 SchedulerLock lock_;
124
125 // Condition variable signaled each time a task completes its execution.
126 ConditionVariable cv_;
127
128 // Index of the last posted task.
129 size_t last_posted_task_index_;
130
131 // Index of the last run task.
132 size_t last_run_task_index_;
133
134 // True if a task that shouldn't run has run.
135 bool ran_task_that_should_not_run_;
136 };
137
138 TEST_F(TaskSchedulerThreadPoolTest, PostSingleParallelTask) {
139 ASSERT_TRUE(thread_pool_.get());
140
141 thread_pool_->CreateTaskRunnerWithTraits(TaskTraits(),
142 ExecutionMode::PARALLEL)
143 ->PostTask(FROM_HERE, GetTaskThatShouldRunClosure(nullptr));
144
145 WaitUntilLastPostedTaskHasRun();
146 Shutdown();
147 }
148
149 TEST_F(TaskSchedulerThreadPoolTest, PostSingleSequencedTask) {
150 ASSERT_TRUE(thread_pool_.get());
151
152 thread_pool_->CreateTaskRunnerWithTraits(TaskTraits(),
153 ExecutionMode::SEQUENCED)
154 ->PostTask(FROM_HERE, GetTaskThatShouldRunClosure(nullptr));
155
156 WaitUntilLastPostedTaskHasRun();
157 Shutdown();
158 }
159
160 TEST_F(TaskSchedulerThreadPoolTest, PostSingleSingleThreadedTask) {
161 ASSERT_TRUE(thread_pool_.get());
162
163 thread_pool_->CreateTaskRunnerWithTraits(TaskTraits(),
164 ExecutionMode::SINGLE_THREADED)
165 ->PostTask(FROM_HERE, GetTaskThatShouldRunClosure(nullptr));
166
167 WaitUntilLastPostedTaskHasRun();
168 Shutdown();
169 }
170
171 TEST_F(TaskSchedulerThreadPoolTest, PostMultipleTasksNoWaitBetweenPosts) {
172 ASSERT_TRUE(thread_pool_.get());
173
174 for (size_t i = 0; i < 100; ++i) {
175 thread_pool_->CreateTaskRunnerWithTraits(TaskTraits(),
176 ExecutionMode::PARALLEL)
177 ->PostTask(FROM_HERE, GetTaskThatShouldRunClosure(nullptr));
178 }
179
180 WaitUntilLastPostedTaskHasRun();
181 Shutdown();
182 }
183
184 TEST_F(TaskSchedulerThreadPoolTest, PostMultipleTasksWaitBetweenPosts) {
185 ASSERT_TRUE(thread_pool_.get());
186
187 for (size_t i = 0; i < 100; ++i) {
188 thread_pool_->CreateTaskRunnerWithTraits(TaskTraits(),
189 ExecutionMode::PARALLEL)
190 ->PostTask(FROM_HERE, GetTaskThatShouldRunClosure(nullptr));
191 WaitUntilLastPostedTaskHasRun();
192 }
193
194 Shutdown();
195 }
196
197 TEST_F(TaskSchedulerThreadPoolTest, PostMultipleTasksInSameSequence) {
198 ASSERT_TRUE(thread_pool_.get());
199
200 auto task_runner = thread_pool_->CreateTaskRunnerWithTraits(
201 TaskTraits(), ExecutionMode::SEQUENCED);
202
203 for (size_t i = 0; i < 100; ++i)
204 task_runner->PostTask(FROM_HERE, GetTaskThatShouldRunClosure(nullptr));
205
206 WaitUntilLastPostedTaskHasRun();
207 Shutdown();
208 }
209
210 TEST_F(TaskSchedulerThreadPoolTest, PostMultipleTasksInTwoSequences) {
211 ASSERT_TRUE(thread_pool_.get());
212
213 auto task_runner_a = thread_pool_->CreateTaskRunnerWithTraits(
214 TaskTraits(), ExecutionMode::SEQUENCED);
215 auto task_runner_b = thread_pool_->CreateTaskRunnerWithTraits(
216 TaskTraits(), ExecutionMode::SEQUENCED);
217
218 for (size_t i = 0; i < 100; ++i) {
219 task_runner_a->PostTask(FROM_HERE, GetTaskThatShouldRunClosure(nullptr));
220 task_runner_b->PostTask(FROM_HERE, GetTaskThatShouldRunClosure(nullptr));
221 }
222
223 WaitUntilLastPostedTaskHasRun();
224 Shutdown();
225 }
226
227 TEST_F(TaskSchedulerThreadPoolTest, PostMultipleSingleThreadedTasks) {
228 ASSERT_TRUE(thread_pool_.get());
229
230 auto task_runner = thread_pool_->CreateTaskRunnerWithTraits(
231 TaskTraits(), ExecutionMode::SINGLE_THREADED);
232 SingleThreadChecker single_thread_checker;
233
234 for (size_t i = 0; i < 100; ++i) {
235 task_runner->PostTask(FROM_HERE,
236 GetTaskThatShouldRunClosure(&single_thread_checker));
237 }
238
239 WaitUntilLastPostedTaskHasRun();
240 Shutdown();
241 EXPECT_TRUE(single_thread_checker.ran_all_tasks_on_same_thread());
242 }
243
244 TEST_F(TaskSchedulerThreadPoolTest, PostParallelDelayedTasks) {
245 ASSERT_TRUE(thread_pool_.get());
246
247 auto task_runner = thread_pool_->CreateTaskRunnerWithTraits(
248 TaskTraits(), ExecutionMode::PARALLEL);
249
250 for (size_t i = 0; i < 10; ++i) {
251 task_runner->PostDelayedTask(FROM_HERE,
252 GetTaskThatShouldRunClosure(nullptr),
253 TimeDelta::FromMilliseconds(i * 50));
254 }
255
256 WaitUntilLastPostedTaskHasRun();
257 Shutdown();
258 }
259
260 TEST_F(TaskSchedulerThreadPoolTest, PostSequencedDelayedTasks) {
261 ASSERT_TRUE(thread_pool_.get());
262
263 auto task_runner = thread_pool_->CreateTaskRunnerWithTraits(
264 TaskTraits(), ExecutionMode::SEQUENCED);
265
266 for (size_t i = 0; i < 10; ++i) {
267 task_runner->PostDelayedTask(FROM_HERE,
268 GetTaskThatShouldRunClosure(nullptr),
269 TimeDelta::FromMilliseconds(i * 50));
270 }
271
272 WaitUntilLastPostedTaskHasRun();
273 Shutdown();
274 }
275
276 TEST_F(TaskSchedulerThreadPoolTest, ShutdownBehavior) {
277 ASSERT_TRUE(thread_pool_.get());
278
279 shutdown_manager_.SetIsShuttingDownForTesting();
280
281 // Post tasks with different shutdown behaviors.
282 thread_pool_->CreateTaskRunnerWithTraits(
283 TaskTraits().WithShutdownBehavior(
284 TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN),
285 ExecutionMode::PARALLEL)
286 ->PostTask(FROM_HERE, GetTaskThatShouldNotRunClosure());
287 thread_pool_->CreateTaskRunnerWithTraits(
288 TaskTraits().WithShutdownBehavior(
289 TaskShutdownBehavior::SKIP_ON_SHUTDOWN),
290 ExecutionMode::PARALLEL)
291 ->PostTask(FROM_HERE, GetTaskThatShouldNotRunClosure());
292 thread_pool_->CreateTaskRunnerWithTraits(
293 TaskTraits().WithShutdownBehavior(
294 TaskShutdownBehavior::BLOCK_SHUTDOWN),
295 ExecutionMode::PARALLEL)
296 ->PostTask(FROM_HERE, GetTaskThatShouldRunClosure(nullptr));
297
298 WaitUntilLastPostedTaskHasRun();
299 Shutdown();
300 EXPECT_FALSE(ran_task_that_should_not_run());
301 }
302
303 } // namespace task_scheduler
304 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698