OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/task_scheduler/scheduler_worker_thread.h" | 5 #include "base/task_scheduler/scheduler_worker.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include <memory> | 9 #include <memory> |
10 #include <vector> | 10 #include <vector> |
11 | 11 |
12 #include "base/bind.h" | 12 #include "base/bind.h" |
13 #include "base/bind_helpers.h" | 13 #include "base/bind_helpers.h" |
14 #include "base/macros.h" | 14 #include "base/macros.h" |
15 #include "base/memory/ptr_util.h" | 15 #include "base/memory/ptr_util.h" |
16 #include "base/synchronization/condition_variable.h" | 16 #include "base/synchronization/condition_variable.h" |
17 #include "base/task_scheduler/scheduler_lock.h" | 17 #include "base/task_scheduler/scheduler_lock.h" |
18 #include "base/task_scheduler/sequence.h" | 18 #include "base/task_scheduler/sequence.h" |
19 #include "base/task_scheduler/task.h" | 19 #include "base/task_scheduler/task.h" |
20 #include "base/task_scheduler/task_tracker.h" | 20 #include "base/task_scheduler/task_tracker.h" |
21 #include "base/time/time.h" | 21 #include "base/time/time.h" |
22 #include "testing/gtest/include/gtest/gtest.h" | 22 #include "testing/gtest/include/gtest/gtest.h" |
23 | 23 |
24 namespace base { | 24 namespace base { |
25 namespace internal { | 25 namespace internal { |
26 namespace { | 26 namespace { |
27 | 27 |
28 const size_t kNumSequencesPerTest = 150; | 28 const size_t kNumSequencesPerTest = 150; |
29 | 29 |
30 // The test parameter is the number of Tasks per Sequence returned by GetWork(). | 30 // The test parameter is the number of Tasks per Sequence returned by GetWork(). |
31 class TaskSchedulerWorkerThreadTest : public testing::TestWithParam<size_t> { | 31 class TaskSchedulerWorkerTest : public testing::TestWithParam<size_t> { |
32 protected: | 32 protected: |
33 TaskSchedulerWorkerThreadTest() | 33 TaskSchedulerWorkerTest() |
34 : main_entry_called_(WaitableEvent::ResetPolicy::MANUAL, | 34 : main_entry_called_(WaitableEvent::ResetPolicy::MANUAL, |
35 WaitableEvent::InitialState::NOT_SIGNALED), | 35 WaitableEvent::InitialState::NOT_SIGNALED), |
36 num_get_work_cv_(lock_.CreateConditionVariable()), | 36 num_get_work_cv_(lock_.CreateConditionVariable()), |
37 worker_thread_set_(WaitableEvent::ResetPolicy::MANUAL, | 37 worker_set_(WaitableEvent::ResetPolicy::MANUAL, |
38 WaitableEvent::InitialState::NOT_SIGNALED) {} | 38 WaitableEvent::InitialState::NOT_SIGNALED) {} |
39 | 39 |
40 void SetUp() override { | 40 void SetUp() override { |
41 worker_thread_ = SchedulerWorkerThread::Create( | 41 worker_ = SchedulerWorker::Create( |
42 ThreadPriority::NORMAL, | 42 ThreadPriority::NORMAL, |
43 WrapUnique(new TestSchedulerWorkerThreadDelegate(this)), | 43 WrapUnique(new TestSchedulerWorkerDelegate(this)), |
44 &task_tracker_); | 44 &task_tracker_); |
45 ASSERT_TRUE(worker_thread_); | 45 ASSERT_TRUE(worker_); |
46 worker_thread_set_.Signal(); | 46 worker_set_.Signal(); |
47 main_entry_called_.Wait(); | 47 main_entry_called_.Wait(); |
48 } | 48 } |
49 | 49 |
50 void TearDown() override { | 50 void TearDown() override { |
51 worker_thread_->JoinForTesting(); | 51 worker_->JoinForTesting(); |
52 } | 52 } |
53 | 53 |
54 size_t TasksPerSequence() const { return GetParam(); } | 54 size_t TasksPerSequence() const { return GetParam(); } |
55 | 55 |
56 // Wait until GetWork() has been called |num_get_work| times. | 56 // Wait until GetWork() has been called |num_get_work| times. |
57 void WaitForNumGetWork(size_t num_get_work) { | 57 void WaitForNumGetWork(size_t num_get_work) { |
58 AutoSchedulerLock auto_lock(lock_); | 58 AutoSchedulerLock auto_lock(lock_); |
59 while (num_get_work_ < num_get_work) | 59 while (num_get_work_ < num_get_work) |
60 num_get_work_cv_->Wait(); | 60 num_get_work_cv_->Wait(); |
61 } | 61 } |
(...skipping 17 matching lines...) Expand all Loading... |
79 std::vector<scoped_refptr<Sequence>> CreatedSequences() { | 79 std::vector<scoped_refptr<Sequence>> CreatedSequences() { |
80 AutoSchedulerLock auto_lock(lock_); | 80 AutoSchedulerLock auto_lock(lock_); |
81 return created_sequences_; | 81 return created_sequences_; |
82 } | 82 } |
83 | 83 |
84 std::vector<scoped_refptr<Sequence>> EnqueuedSequences() { | 84 std::vector<scoped_refptr<Sequence>> EnqueuedSequences() { |
85 AutoSchedulerLock auto_lock(lock_); | 85 AutoSchedulerLock auto_lock(lock_); |
86 return re_enqueued_sequences_; | 86 return re_enqueued_sequences_; |
87 } | 87 } |
88 | 88 |
89 std::unique_ptr<SchedulerWorkerThread> worker_thread_; | 89 std::unique_ptr<SchedulerWorker> worker_; |
90 | 90 |
91 private: | 91 private: |
92 class TestSchedulerWorkerThreadDelegate | 92 class TestSchedulerWorkerDelegate |
93 : public SchedulerWorkerThread::Delegate { | 93 : public SchedulerWorker::Delegate { |
94 public: | 94 public: |
95 TestSchedulerWorkerThreadDelegate(TaskSchedulerWorkerThreadTest* outer) | 95 TestSchedulerWorkerDelegate(TaskSchedulerWorkerTest* outer) |
96 : outer_(outer) {} | 96 : outer_(outer) {} |
97 | 97 |
98 // SchedulerWorkerThread::Delegate: | 98 // SchedulerWorker::Delegate: |
99 void OnMainEntry(SchedulerWorkerThread* worker_thread) override { | 99 void OnMainEntry(SchedulerWorker* worker) override { |
100 outer_->worker_thread_set_.Wait(); | 100 outer_->worker_set_.Wait(); |
101 EXPECT_EQ(outer_->worker_thread_.get(), worker_thread); | 101 EXPECT_EQ(outer_->worker_.get(), worker); |
102 | 102 |
103 // Without synchronization, OnMainEntry() could be called twice without | 103 // Without synchronization, OnMainEntry() could be called twice without |
104 // generating an error. | 104 // generating an error. |
105 AutoSchedulerLock auto_lock(outer_->lock_); | 105 AutoSchedulerLock auto_lock(outer_->lock_); |
106 EXPECT_FALSE(outer_->main_entry_called_.IsSignaled()); | 106 EXPECT_FALSE(outer_->main_entry_called_.IsSignaled()); |
107 outer_->main_entry_called_.Signal(); | 107 outer_->main_entry_called_.Signal(); |
108 } | 108 } |
109 | 109 |
110 scoped_refptr<Sequence> GetWork( | 110 scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override { |
111 SchedulerWorkerThread* worker_thread) override { | 111 EXPECT_EQ(outer_->worker_.get(), worker); |
112 EXPECT_EQ(outer_->worker_thread_.get(), worker_thread); | |
113 | 112 |
114 { | 113 { |
115 AutoSchedulerLock auto_lock(outer_->lock_); | 114 AutoSchedulerLock auto_lock(outer_->lock_); |
116 | 115 |
117 // Increment the number of times that this method has been called. | 116 // Increment the number of times that this method has been called. |
118 ++outer_->num_get_work_; | 117 ++outer_->num_get_work_; |
119 outer_->num_get_work_cv_->Signal(); | 118 outer_->num_get_work_cv_->Signal(); |
120 | 119 |
121 // Verify that this method isn't called more times than expected. | 120 // Verify that this method isn't called more times than expected. |
122 EXPECT_LE(outer_->num_get_work_, outer_->max_get_work_); | 121 EXPECT_LE(outer_->num_get_work_, outer_->max_get_work_); |
123 | 122 |
124 // Check if a Sequence should be returned. | 123 // Check if a Sequence should be returned. |
125 if (outer_->num_sequences_to_create_ == 0) | 124 if (outer_->num_sequences_to_create_ == 0) |
126 return nullptr; | 125 return nullptr; |
127 --outer_->num_sequences_to_create_; | 126 --outer_->num_sequences_to_create_; |
128 } | 127 } |
129 | 128 |
130 // Create a Sequence with TasksPerSequence() Tasks. | 129 // Create a Sequence with TasksPerSequence() Tasks. |
131 scoped_refptr<Sequence> sequence(new Sequence); | 130 scoped_refptr<Sequence> sequence(new Sequence); |
132 for (size_t i = 0; i < outer_->TasksPerSequence(); ++i) { | 131 for (size_t i = 0; i < outer_->TasksPerSequence(); ++i) { |
133 std::unique_ptr<Task> task(new Task( | 132 std::unique_ptr<Task> task(new Task( |
134 FROM_HERE, Bind(&TaskSchedulerWorkerThreadTest::RunTaskCallback, | 133 FROM_HERE, Bind(&TaskSchedulerWorkerTest::RunTaskCallback, |
135 Unretained(outer_)), | 134 Unretained(outer_)), |
136 TaskTraits(), TimeDelta())); | 135 TaskTraits(), TimeDelta())); |
137 EXPECT_TRUE(outer_->task_tracker_.WillPostTask(task.get())); | 136 EXPECT_TRUE(outer_->task_tracker_.WillPostTask(task.get())); |
138 sequence->PushTask(std::move(task)); | 137 sequence->PushTask(std::move(task)); |
139 } | 138 } |
140 | 139 |
141 { | 140 { |
142 // Add the Sequence to the vector of created Sequences. | 141 // Add the Sequence to the vector of created Sequences. |
143 AutoSchedulerLock auto_lock(outer_->lock_); | 142 AutoSchedulerLock auto_lock(outer_->lock_); |
144 outer_->created_sequences_.push_back(sequence); | 143 outer_->created_sequences_.push_back(sequence); |
(...skipping 21 matching lines...) Expand all Loading... |
166 outer_->re_enqueued_sequences_.push_back(std::move(sequence)); | 165 outer_->re_enqueued_sequences_.push_back(std::move(sequence)); |
167 EXPECT_LE(outer_->re_enqueued_sequences_.size(), | 166 EXPECT_LE(outer_->re_enqueued_sequences_.size(), |
168 outer_->created_sequences_.size()); | 167 outer_->created_sequences_.size()); |
169 } | 168 } |
170 | 169 |
171 TimeDelta GetSleepTimeout() override { | 170 TimeDelta GetSleepTimeout() override { |
172 return TimeDelta::Max(); | 171 return TimeDelta::Max(); |
173 } | 172 } |
174 | 173 |
175 private: | 174 private: |
176 TaskSchedulerWorkerThreadTest* outer_; | 175 TaskSchedulerWorkerTest* outer_; |
177 }; | 176 }; |
178 | 177 |
179 void RunTaskCallback() { | 178 void RunTaskCallback() { |
180 AutoSchedulerLock auto_lock(lock_); | 179 AutoSchedulerLock auto_lock(lock_); |
181 ++num_run_tasks_; | 180 ++num_run_tasks_; |
182 EXPECT_LE(num_run_tasks_, created_sequences_.size()); | 181 EXPECT_LE(num_run_tasks_, created_sequences_.size()); |
183 } | 182 } |
184 | 183 |
185 TaskTracker task_tracker_; | 184 TaskTracker task_tracker_; |
186 | 185 |
(...skipping 18 matching lines...) Expand all Loading... |
205 | 204 |
206 // Sequences created by GetWork(). | 205 // Sequences created by GetWork(). |
207 std::vector<scoped_refptr<Sequence>> created_sequences_; | 206 std::vector<scoped_refptr<Sequence>> created_sequences_; |
208 | 207 |
209 // Sequences passed to EnqueueSequence(). | 208 // Sequences passed to EnqueueSequence(). |
210 std::vector<scoped_refptr<Sequence>> re_enqueued_sequences_; | 209 std::vector<scoped_refptr<Sequence>> re_enqueued_sequences_; |
211 | 210 |
212 // Number of times that RunTaskCallback() has been called. | 211 // Number of times that RunTaskCallback() has been called. |
213 size_t num_run_tasks_ = 0; | 212 size_t num_run_tasks_ = 0; |
214 | 213 |
215 // Signaled after |worker_thread_| is set. | 214 // Signaled after |worker_| is set. |
216 WaitableEvent worker_thread_set_; | 215 WaitableEvent worker_set_; |
217 | 216 |
218 DISALLOW_COPY_AND_ASSIGN(TaskSchedulerWorkerThreadTest); | 217 DISALLOW_COPY_AND_ASSIGN(TaskSchedulerWorkerTest); |
219 }; | 218 }; |
220 | 219 |
221 // Verify that when GetWork() continuously returns Sequences, all Tasks in these | 220 // Verify that when GetWork() continuously returns Sequences, all Tasks in these |
222 // Sequences run successfully. The test wakes up the SchedulerWorkerThread once. | 221 // Sequences run successfully. The test wakes up the SchedulerWorker once. |
223 TEST_P(TaskSchedulerWorkerThreadTest, ContinuousWork) { | 222 TEST_P(TaskSchedulerWorkerTest, ContinuousWork) { |
224 // Set GetWork() to return |kNumSequencesPerTest| Sequences before starting to | 223 // Set GetWork() to return |kNumSequencesPerTest| Sequences before starting to |
225 // return nullptr. | 224 // return nullptr. |
226 SetNumSequencesToCreate(kNumSequencesPerTest); | 225 SetNumSequencesToCreate(kNumSequencesPerTest); |
227 | 226 |
228 // Expect |kNumSequencesPerTest| calls to GetWork() in which it returns a | 227 // Expect |kNumSequencesPerTest| calls to GetWork() in which it returns a |
229 // Sequence and one call in which its returns nullptr. | 228 // Sequence and one call in which its returns nullptr. |
230 const size_t kExpectedNumGetWork = kNumSequencesPerTest + 1; | 229 const size_t kExpectedNumGetWork = kNumSequencesPerTest + 1; |
231 SetMaxGetWork(kExpectedNumGetWork); | 230 SetMaxGetWork(kExpectedNumGetWork); |
232 | 231 |
233 // Wake up |worker_thread_| and wait until GetWork() has been invoked the | 232 // Wake up |worker_| and wait until GetWork() has been invoked the |
234 // expected amount of times. | 233 // expected amount of times. |
235 worker_thread_->WakeUp(); | 234 worker_->WakeUp(); |
236 WaitForNumGetWork(kExpectedNumGetWork); | 235 WaitForNumGetWork(kExpectedNumGetWork); |
237 | 236 |
238 // All tasks should have run. | 237 // All tasks should have run. |
239 EXPECT_EQ(kNumSequencesPerTest, NumRunTasks()); | 238 EXPECT_EQ(kNumSequencesPerTest, NumRunTasks()); |
240 | 239 |
241 // If Sequences returned by GetWork() contain more than one Task, they aren't | 240 // If Sequences returned by GetWork() contain more than one Task, they aren't |
242 // empty after the worker thread pops Tasks from them and thus should be | 241 // empty after the worker pops Tasks from them and thus should be returned to |
243 // returned to EnqueueSequence(). | 242 // EnqueueSequence(). |
244 if (TasksPerSequence() > 1) | 243 if (TasksPerSequence() > 1) |
245 EXPECT_EQ(CreatedSequences(), EnqueuedSequences()); | 244 EXPECT_EQ(CreatedSequences(), EnqueuedSequences()); |
246 else | 245 else |
247 EXPECT_TRUE(EnqueuedSequences().empty()); | 246 EXPECT_TRUE(EnqueuedSequences().empty()); |
248 } | 247 } |
249 | 248 |
250 // Verify that when GetWork() alternates between returning a Sequence and | 249 // Verify that when GetWork() alternates between returning a Sequence and |
251 // returning nullptr, all Tasks in the returned Sequences run successfully. The | 250 // returning nullptr, all Tasks in the returned Sequences run successfully. The |
252 // test wakes up the SchedulerWorkerThread once for each Sequence. | 251 // test wakes up the SchedulerWorker once for each Sequence. |
253 TEST_P(TaskSchedulerWorkerThreadTest, IntermittentWork) { | 252 TEST_P(TaskSchedulerWorkerTest, IntermittentWork) { |
254 for (size_t i = 0; i < kNumSequencesPerTest; ++i) { | 253 for (size_t i = 0; i < kNumSequencesPerTest; ++i) { |
255 // Set GetWork() to return 1 Sequence before starting to return | 254 // Set GetWork() to return 1 Sequence before starting to return |
256 // nullptr. | 255 // nullptr. |
257 SetNumSequencesToCreate(1); | 256 SetNumSequencesToCreate(1); |
258 | 257 |
259 // Expect |i + 1| calls to GetWork() in which it returns a Sequence and | 258 // Expect |i + 1| calls to GetWork() in which it returns a Sequence and |
260 // |i + 1| calls in which it returns nullptr. | 259 // |i + 1| calls in which it returns nullptr. |
261 const size_t expected_num_get_work = 2 * (i + 1); | 260 const size_t expected_num_get_work = 2 * (i + 1); |
262 SetMaxGetWork(expected_num_get_work); | 261 SetMaxGetWork(expected_num_get_work); |
263 | 262 |
264 // Wake up |worker_thread_| and wait until GetWork() has been invoked | 263 // Wake up |worker_| and wait until GetWork() has been invoked |
265 // the expected amount of times. | 264 // the expected amount of times. |
266 worker_thread_->WakeUp(); | 265 worker_->WakeUp(); |
267 WaitForNumGetWork(expected_num_get_work); | 266 WaitForNumGetWork(expected_num_get_work); |
268 | 267 |
269 // The Task should have run | 268 // The Task should have run |
270 EXPECT_EQ(i + 1, NumRunTasks()); | 269 EXPECT_EQ(i + 1, NumRunTasks()); |
271 | 270 |
272 // If Sequences returned by GetWork() contain more than one Task, they | 271 // If Sequences returned by GetWork() contain more than one Task, they |
273 // aren't empty after the worker thread pops Tasks from them and thus should | 272 // aren't empty after the worker pops Tasks from them and thus should be |
274 // be returned to EnqueueSequence(). | 273 // returned to EnqueueSequence(). |
275 if (TasksPerSequence() > 1) | 274 if (TasksPerSequence() > 1) |
276 EXPECT_EQ(CreatedSequences(), EnqueuedSequences()); | 275 EXPECT_EQ(CreatedSequences(), EnqueuedSequences()); |
277 else | 276 else |
278 EXPECT_TRUE(EnqueuedSequences().empty()); | 277 EXPECT_TRUE(EnqueuedSequences().empty()); |
279 } | 278 } |
280 } | 279 } |
281 | 280 |
282 INSTANTIATE_TEST_CASE_P(OneTaskPerSequence, | 281 INSTANTIATE_TEST_CASE_P(OneTaskPerSequence, |
283 TaskSchedulerWorkerThreadTest, | 282 TaskSchedulerWorkerTest, |
284 ::testing::Values(1)); | 283 ::testing::Values(1)); |
285 INSTANTIATE_TEST_CASE_P(TwoTasksPerSequence, | 284 INSTANTIATE_TEST_CASE_P(TwoTasksPerSequence, |
286 TaskSchedulerWorkerThreadTest, | 285 TaskSchedulerWorkerTest, |
287 ::testing::Values(2)); | 286 ::testing::Values(2)); |
288 | 287 |
289 } // namespace | 288 } // namespace |
290 } // namespace internal | 289 } // namespace internal |
291 } // namespace base | 290 } // namespace base |
OLD | NEW |