Chromium Code Reviews| OLD | NEW |
|---|---|
| (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/scheduler_worker_thread.h" | |
| 6 | |
| 7 #include <stddef.h> | |
| 8 | |
| 9 #include <vector> | |
| 10 | |
| 11 #include "base/bind.h" | |
| 12 #include "base/bind_helpers.h" | |
| 13 #include "base/macros.h" | |
| 14 #include "base/memory/scoped_ptr.h" | |
| 15 #include "base/synchronization/condition_variable.h" | |
| 16 #include "base/task_scheduler/scheduler_lock.h" | |
| 17 #include "base/task_scheduler/sequence.h" | |
| 18 #include "base/task_scheduler/task.h" | |
| 19 #include "base/task_scheduler/task_tracker.h" | |
| 20 #include "testing/gtest/include/gtest/gtest.h" | |
| 21 | |
| 22 namespace base { | |
| 23 namespace internal { | |
| 24 namespace { | |
| 25 | |
| 26 const size_t kNumSequencesPerTest = 150; | |
| 27 | |
| 28 class TaskSchedulerWorkerThreadTest : public testing::Test { | |
| 29 protected: | |
| 30 TaskSchedulerWorkerThreadTest() | |
| 31 : num_main_entry_callback_cv_(lock_.CreateConditionVariable()), | |
| 32 num_get_work_callback_cv_(lock_.CreateConditionVariable()), | |
| 33 run_sequences_cv_(lock_.CreateConditionVariable()) {} | |
| 34 | |
| 35 void SetUp() override { | |
| 36 worker_thread_ = SchedulerWorkerThread::CreateSchedulerWorkerThread( | |
| 37 ThreadPriority::NORMAL, | |
| 38 Bind(&TaskSchedulerWorkerThreadTest::MainEntryCallback, | |
| 39 Unretained(this)), | |
| 40 Bind(&TaskSchedulerWorkerThreadTest::GetWorkCallback, Unretained(this)), | |
| 41 Bind(&TaskSchedulerWorkerThreadTest::RanTaskFromSequenceCallback, | |
| 42 Unretained(this)), | |
| 43 &task_tracker_); | |
| 44 ASSERT_TRUE(worker_thread_); | |
| 45 WaitForNumMainEntryCallback(1); | |
| 46 } | |
| 47 | |
| 48 void TearDown() override { | |
| 49 worker_thread_->JoinForTesting(); | |
| 50 | |
| 51 AutoSchedulerLock auto_lock(lock_); | |
| 52 EXPECT_EQ(1U, num_main_entry_callback_); | |
| 53 } | |
|
gab
2016/04/05 23:35:20
Would be nice to test that the tests observed ever
fdoray
2016/04/07 13:56:47
Added "EXPECT_LE(num_run_tasks_, created_sequences
| |
| 54 | |
| 55 // Wait until MainEntryCallback() has been called |num_main_entry_callback| | |
| 56 // times. | |
| 57 void WaitForNumMainEntryCallback(size_t num_main_entry_callback) { | |
| 58 AutoSchedulerLock auto_lock(lock_); | |
| 59 while (num_main_entry_callback_ < num_main_entry_callback) | |
| 60 num_main_entry_callback_cv_->Wait(); | |
| 61 } | |
| 62 | |
| 63 // Wait until GetWorkCallback() has been called |num_get_work_callback| times. | |
| 64 void WaitForNumGetWorkCallback(size_t num_get_work_callback) { | |
| 65 AutoSchedulerLock auto_lock(lock_); | |
| 66 while (num_get_work_callback_ < num_get_work_callback) | |
| 67 num_get_work_callback_cv_->Wait(); | |
| 68 } | |
| 69 | |
| 70 // Wait until there is no more Sequences to create and | |
| 71 // RanTaskFromSequenceCallback() has been invoked once for each Sequence | |
| 72 // returned by GetWorkCallback(). | |
| 73 void WaitForAllSequencesToRun() { | |
| 74 AutoSchedulerLock auto_lock(lock_); | |
| 75 | |
| 76 while (num_sequences_to_create_ > 0 || | |
| 77 run_sequences_.size() < created_sequences_.size()) { | |
| 78 run_sequences_cv_->Wait(); | |
| 79 } | |
| 80 | |
| 81 // Verify that RanTaskFromSequenceCallback() has been invoked with the | |
| 82 // same Sequences that were returned by GetWorkCallback(). | |
| 83 EXPECT_EQ(created_sequences_, run_sequences_); | |
| 84 | |
| 85 // Verify that RunTaskCallback() has been invoked once for each Sequence | |
| 86 // returned by GetWorkCallback(). | |
| 87 EXPECT_EQ(created_sequences_.size(), num_run_tasks_); | |
| 88 } | |
| 89 | |
| 90 void SetNumSequencesToCreate(size_t num_sequences_to_create) { | |
| 91 AutoSchedulerLock auto_lock(lock_); | |
| 92 EXPECT_EQ(0U, num_sequences_to_create_); | |
| 93 num_sequences_to_create_ = num_sequences_to_create; | |
| 94 } | |
| 95 | |
| 96 size_t NumGetWorkCallback() const { | |
| 97 AutoSchedulerLock auto_lock(lock_); | |
| 98 return num_get_work_callback_; | |
| 99 } | |
| 100 | |
| 101 scoped_ptr<SchedulerWorkerThread> worker_thread_; | |
| 102 | |
| 103 private: | |
| 104 void MainEntryCallback() { | |
| 105 AutoSchedulerLock auto_lock(lock_); | |
| 106 ++num_main_entry_callback_; | |
| 107 num_main_entry_callback_cv_->Signal(); | |
| 108 } | |
| 109 | |
| 110 // Returns a Sequence that contains 1 Task if |num_sequences_to_create_| is | |
| 111 // greater than 0. | |
| 112 scoped_refptr<Sequence> GetWorkCallback( | |
| 113 SchedulerWorkerThread* worker_thread) { | |
| 114 EXPECT_EQ(worker_thread_.get(), worker_thread); | |
| 115 | |
| 116 { | |
| 117 AutoSchedulerLock auto_lock(lock_); | |
| 118 | |
| 119 // Increment the number of times that this callback has been invoked. | |
| 120 ++num_get_work_callback_; | |
| 121 num_get_work_callback_cv_->Signal(); | |
| 122 | |
| 123 // Check if a Sequence should be returned. | |
| 124 if (num_sequences_to_create_ == 0) | |
| 125 return nullptr; | |
| 126 --num_sequences_to_create_; | |
| 127 } | |
| 128 | |
| 129 // Create a Sequence that contains 1 Task. | |
| 130 scoped_refptr<Sequence> sequence(new Sequence); | |
| 131 task_tracker_.PostTask( | |
| 132 Bind(IgnoreResult(&Sequence::PushTask), Unretained(sequence.get())), | |
| 133 make_scoped_ptr(new Task( | |
| 134 FROM_HERE, Bind(&TaskSchedulerWorkerThreadTest::RunTaskCallback, | |
| 135 Unretained(this)), | |
| 136 TaskTraits()))); | |
| 137 | |
| 138 { | |
| 139 // Add the Sequence to the vector of created Sequences. | |
| 140 AutoSchedulerLock auto_lock(lock_); | |
| 141 created_sequences_.push_back(sequence); | |
| 142 } | |
| 143 | |
| 144 return sequence; | |
| 145 } | |
| 146 | |
| 147 void RanTaskFromSequenceCallback(const SchedulerWorkerThread* worker_thread, | |
| 148 scoped_refptr<Sequence> sequence) { | |
| 149 EXPECT_EQ(worker_thread_.get(), worker_thread); | |
| 150 | |
| 151 AutoSchedulerLock auto_lock(lock_); | |
| 152 run_sequences_.push_back(std::move(sequence)); | |
| 153 run_sequences_cv_->Signal(); | |
| 154 } | |
| 155 | |
| 156 void RunTaskCallback() { | |
| 157 AutoSchedulerLock auto_lock(lock_); | |
| 158 ++num_run_tasks_; | |
| 159 } | |
| 160 | |
| 161 TaskTracker task_tracker_; | |
| 162 | |
| 163 // Synchronizes access to all members below. | |
| 164 mutable SchedulerLock lock_; | |
| 165 | |
| 166 // Number of times that MainEntryCallback() has been called. | |
| 167 size_t num_main_entry_callback_ = 0; | |
| 168 | |
| 169 // Condition variable signaled when |num_main_entry_callback_| is incremented. | |
| 170 scoped_ptr<ConditionVariable> num_main_entry_callback_cv_; | |
| 171 | |
| 172 // Number of Sequences that should be created by GetWorkCallback(). When this | |
| 173 // is 0, GetWorkCallback() returns nullptr. | |
| 174 size_t num_sequences_to_create_ = 0; | |
| 175 | |
| 176 // Number of times that GetWorkCallback() has been called. | |
| 177 size_t num_get_work_callback_ = 0; | |
| 178 | |
| 179 // Condition variable signaled when |num_get_work_callback_| is incremented. | |
| 180 scoped_ptr<ConditionVariable> num_get_work_callback_cv_; | |
| 181 | |
| 182 // Sequences created by GetWorkCallback(). | |
| 183 std::vector<scoped_refptr<Sequence>> created_sequences_; | |
| 184 | |
| 185 // Sequences passed to RanTaskFromSequenceCallback(). | |
| 186 std::vector<scoped_refptr<Sequence>> run_sequences_; | |
| 187 | |
| 188 // Condition variable signaled when a Sequence is added to |run_sequences_|. | |
| 189 scoped_ptr<ConditionVariable> run_sequences_cv_; | |
| 190 | |
| 191 // Number of times that RunTaskCallback() has been called. | |
| 192 size_t num_run_tasks_ = 0; | |
| 193 | |
| 194 DISALLOW_COPY_AND_ASSIGN(TaskSchedulerWorkerThreadTest); | |
| 195 }; | |
| 196 | |
| 197 // Verify that when GetWorkCallback() continuously returns Sequences, all Tasks | |
| 198 // in these Sequences run successfully. The SchedulerWorkerThread is woken up | |
| 199 // once. | |
| 200 TEST_F(TaskSchedulerWorkerThreadTest, ContinousWork) { | |
|
gab
2016/04/05 23:35:20
Continuous Work
^
fdoray
2016/04/07 13:56:47
Done.
| |
| 201 // Set GetWorkCallback() to return |kNumSequencesPerTest| Sequences before | |
| 202 // starting to return nullptr. | |
| 203 SetNumSequencesToCreate(kNumSequencesPerTest); | |
| 204 | |
| 205 // Wake up |worker_thread_| and wait until it has run all the Tasks returned | |
| 206 // by GetWorkCallback(). | |
| 207 worker_thread_->WakeUp(); | |
| 208 WaitForAllSequencesToRun(); | |
| 209 | |
| 210 // Expect |kNumSequencesPerTest| calls to GetWorkCallback() in which it | |
| 211 // returned a Sequence and 1 call in which it returned nullptr. | |
| 212 const size_t expected_num_get_work_callback = kNumSequencesPerTest + 1; | |
|
gab
2016/04/05 23:35:20
kExpectedNumGetWorkCallback
fdoray
2016/04/07 13:56:47
Done.
| |
| 213 WaitForNumGetWorkCallback(expected_num_get_work_callback); | |
|
gab
2016/04/05 23:35:20
If all sequences ran we shouldn't need to wait her
fdoray
2016/04/07 13:56:47
Yes, we need to wait for the call to GetWork() tha
| |
| 214 EXPECT_EQ(expected_num_get_work_callback, NumGetWorkCallback()); | |
|
gab
2016/04/05 23:35:20
if we don't need to wait above maybe make |num_get
fdoray
2016/04/07 13:56:47
We do need to wait above.
| |
| 215 } | |
|
gab
2016/04/05 23:35:20
Test num wakeups? Since it's stated in test descri
fdoray
2016/04/07 13:56:47
I updated the test description. The test calls Wak
| |
| 216 | |
| 217 // Verify that when GetWorkCallback() alternates between returning a Sequence | |
| 218 // and returning nullptr, all Tasks in the returned Sequences run successfully. | |
| 219 // The SchedulerWorkerThread is woken up once for each Sequence. | |
| 220 TEST_F(TaskSchedulerWorkerThreadTest, IntermittentWork) { | |
| 221 for (size_t i = 0; i < kNumSequencesPerTest; ++i) { | |
| 222 // Set GetWorkCallback() to return 1 Sequence before starting to return | |
| 223 // nullptr. | |
| 224 SetNumSequencesToCreate(1); | |
| 225 | |
| 226 // Wake up |worker_thread_| and wait until it has run all the Tasks returned | |
| 227 // by GetWorkCallback(). | |
| 228 worker_thread_->WakeUp(); | |
| 229 WaitForAllSequencesToRun(); | |
| 230 | |
| 231 // Expect |i| calls to GetWorkCallback() in which it returned a Sequence and | |
| 232 // |i| calls in which it returned nullptr. | |
| 233 const size_t expected_num_get_work_callback = 2 * (i + 1); | |
| 234 WaitForNumGetWorkCallback(expected_num_get_work_callback); | |
| 235 EXPECT_EQ(expected_num_get_work_callback, NumGetWorkCallback()); | |
| 236 } | |
| 237 } | |
|
gab
2016/04/05 23:35:20
Test num wakeups?
fdoray
2016/04/07 13:56:47
ditto
| |
| 238 | |
| 239 } // namespace | |
| 240 } // namespace internal | |
| 241 } // namespace base | |
| OLD | NEW |