Chromium Code Reviews| 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_thread_pool.h" | 5 #include "base/task_scheduler/scheduler_thread_pool.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <memory> | 9 #include <memory> |
| 10 #include <unordered_set> | 10 #include <unordered_set> |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 27 #include "testing/gtest/include/gtest/gtest.h" | 27 #include "testing/gtest/include/gtest/gtest.h" |
| 28 | 28 |
| 29 namespace base { | 29 namespace base { |
| 30 namespace internal { | 30 namespace internal { |
| 31 namespace { | 31 namespace { |
| 32 | 32 |
| 33 const size_t kNumThreadsInThreadPool = 4; | 33 const size_t kNumThreadsInThreadPool = 4; |
| 34 const size_t kNumThreadsPostingTasks = 4; | 34 const size_t kNumThreadsPostingTasks = 4; |
| 35 const size_t kNumTasksPostedPerThread = 150; | 35 const size_t kNumTasksPostedPerThread = 150; |
| 36 | 36 |
| 37 class TaskSchedulerThreadPoolTest : public testing::Test { | 37 class TaskSchedulerThreadPoolTest |
| 38 : public testing::TestWithParam<ExecutionMode> { | |
| 38 protected: | 39 protected: |
| 39 TaskSchedulerThreadPoolTest() = default; | 40 TaskSchedulerThreadPoolTest() = default; |
| 40 | 41 |
| 41 void SetUp() override { | 42 void SetUp() override { |
| 42 thread_pool_ = SchedulerThreadPool::CreateThreadPool( | 43 thread_pool_ = SchedulerThreadPool::CreateThreadPool( |
| 43 ThreadPriority::NORMAL, kNumThreadsInThreadPool, | 44 ThreadPriority::NORMAL, kNumThreadsInThreadPool, |
| 44 Bind(&TaskSchedulerThreadPoolTest::EnqueueSequenceCallback, | 45 Bind(&TaskSchedulerThreadPoolTest::EnqueueSequenceCallback, |
| 45 Unretained(this)), | 46 Unretained(this)), |
| 46 &task_tracker_); | 47 &task_tracker_); |
| 47 ASSERT_TRUE(thread_pool_); | 48 ASSERT_TRUE(thread_pool_); |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 63 thread_pool_->EnqueueSequence(std::move(sequence), sort_key); | 64 thread_pool_->EnqueueSequence(std::move(sequence), sort_key); |
| 64 } | 65 } |
| 65 | 66 |
| 66 TaskTracker task_tracker_; | 67 TaskTracker task_tracker_; |
| 67 | 68 |
| 68 DISALLOW_COPY_AND_ASSIGN(TaskSchedulerThreadPoolTest); | 69 DISALLOW_COPY_AND_ASSIGN(TaskSchedulerThreadPoolTest); |
| 69 }; | 70 }; |
| 70 | 71 |
| 71 class TaskFactory { | 72 class TaskFactory { |
| 72 public: | 73 public: |
| 73 TaskFactory() : cv_(&lock_) {} | 74 // Constructs a TaskFactory that posts tasks with |execution_mode| to |
| 75 // |thread_pool|. | |
| 76 TaskFactory(SchedulerThreadPool* thread_pool, ExecutionMode execution_mode) | |
| 77 : cv_(&lock_), | |
| 78 task_runner_(thread_pool->CreateTaskRunnerWithTraits(TaskTraits(), | |
| 79 execution_mode)), | |
| 80 execution_mode_(execution_mode) {} | |
| 74 | 81 |
| 75 // Posts a task through |task_runner|. If |post_nested_task| is true, the task | 82 // Posts a task through |task_runner_|. If |post_nested_task| is true, the |
| 76 // will post a new task through |task_runner| when it runs. If |event| is set, | 83 // task will post a new task when it runs. If |event| is set, the task will |
| 77 // the task will block until it is signaled. | 84 // block until it is signaled. |
| 78 void PostTestTask(scoped_refptr<TaskRunner> task_runner, | 85 void PostTestTask(bool post_nested_task, WaitableEvent* event) { |
| 79 bool post_nested_task, | |
| 80 WaitableEvent* event) { | |
| 81 AutoLock auto_lock(lock_); | 86 AutoLock auto_lock(lock_); |
| 82 EXPECT_TRUE(task_runner->PostTask( | 87 EXPECT_TRUE(task_runner_->PostTask( |
| 83 FROM_HERE, Bind(&TaskFactory::RunTaskCallback, Unretained(this), | 88 FROM_HERE, |
| 84 num_created_tasks_++, task_runner, post_nested_task, | 89 Bind(&TaskFactory::RunTaskCallback, Unretained(this), |
| 85 Unretained(event)))); | 90 num_created_tasks_++, post_nested_task, Unretained(event)))); |
| 86 } | 91 } |
| 87 | 92 |
| 88 // Waits for all tasks posted by PostTestTask() to start running. It is not | 93 // Waits for all tasks posted by PostTestTask() to start running. It is not |
| 89 // guaranteed that the tasks have completed their execution when this returns. | 94 // guaranteed that the tasks have completed their execution when this returns. |
| 90 void WaitForAllTasksToRun() const { | 95 void WaitForAllTasksToRun() const { |
| 91 AutoLock auto_lock(lock_); | 96 AutoLock auto_lock(lock_); |
| 92 while (ran_tasks_.size() < num_created_tasks_) | 97 while (ran_tasks_.size() < num_created_tasks_) |
| 93 cv_.Wait(); | 98 cv_.Wait(); |
| 94 } | 99 } |
| 95 | 100 |
| 96 size_t NumRunTasks() const { | 101 size_t NumRunTasks() const { |
| 97 AutoLock auto_lock(lock_); | 102 AutoLock auto_lock(lock_); |
| 98 return ran_tasks_.size(); | 103 return ran_tasks_.size(); |
| 99 } | 104 } |
| 100 | 105 |
| 106 const TaskRunner* task_runner() const { return task_runner_.get(); } | |
| 107 | |
| 101 private: | 108 private: |
| 102 void RunTaskCallback(size_t task_index, | 109 void RunTaskCallback(size_t task_index, |
| 103 scoped_refptr<TaskRunner> task_runner, | |
| 104 bool post_nested_task, | 110 bool post_nested_task, |
| 105 WaitableEvent* event) { | 111 WaitableEvent* event) { |
| 106 if (post_nested_task) | 112 if (post_nested_task) |
| 107 PostTestTask(task_runner, false, nullptr); | 113 PostTestTask(false, nullptr); |
| 108 | 114 |
| 109 EXPECT_TRUE(task_runner->RunsTasksOnCurrentThread()); | 115 EXPECT_TRUE(task_runner_->RunsTasksOnCurrentThread()); |
| 110 | 116 |
| 111 { | 117 { |
| 112 AutoLock auto_lock(lock_); | 118 AutoLock auto_lock(lock_); |
| 113 | 119 |
| 120 if (execution_mode_ == ExecutionMode::SEQUENCED && | |
| 121 task_index != ran_tasks_.size()) { | |
| 122 ADD_FAILURE() << "A SEQUENCED task didn't run in the expected order."; | |
| 123 } | |
| 124 | |
| 114 if (ran_tasks_.find(task_index) != ran_tasks_.end()) | 125 if (ran_tasks_.find(task_index) != ran_tasks_.end()) |
| 115 ADD_FAILURE() << "A task ran more than once."; | 126 ADD_FAILURE() << "A task ran more than once."; |
| 116 ran_tasks_.insert(task_index); | 127 ran_tasks_.insert(task_index); |
| 117 | 128 |
| 118 cv_.Signal(); | 129 cv_.Signal(); |
| 119 } | 130 } |
| 120 | 131 |
| 121 if (event) | 132 if (event) |
| 122 event->Wait(); | 133 event->Wait(); |
| 123 } | 134 } |
| 124 | 135 |
| 125 // Synchronizes access to all members below. | 136 // Synchronizes access to all members below. |
| 126 mutable Lock lock_; | 137 mutable Lock lock_; |
| 127 | 138 |
| 128 // Condition variable signaled when a task runs. | 139 // Condition variable signaled when a task runs. |
| 129 mutable ConditionVariable cv_; | 140 mutable ConditionVariable cv_; |
| 130 | 141 |
| 142 // Task runner through which this factory posts tasks. | |
| 143 const scoped_refptr<TaskRunner> task_runner_; | |
| 144 | |
| 145 // Execution mode of |task_runner_|. | |
| 146 const ExecutionMode execution_mode_; | |
| 147 | |
| 131 // Number of tasks posted by PostTestTask(). | 148 // Number of tasks posted by PostTestTask(). |
| 132 size_t num_created_tasks_ = 0; | 149 size_t num_created_tasks_ = 0; |
| 133 | 150 |
| 134 // Indexes of tasks that ran. | 151 // Indexes of tasks that ran. |
| 135 std::unordered_set<size_t> ran_tasks_; | 152 std::unordered_set<size_t> ran_tasks_; |
| 136 | 153 |
| 137 DISALLOW_COPY_AND_ASSIGN(TaskFactory); | 154 DISALLOW_COPY_AND_ASSIGN(TaskFactory); |
| 138 }; | 155 }; |
| 139 | 156 |
| 140 class ThreadPostingTasks : public SimpleThread { | 157 class ThreadPostingTasks : public SimpleThread { |
| 141 public: | 158 public: |
| 142 // Constructs a thread that posts tasks to |thread_pool| through an | 159 // Constructs a thread that posts tasks to |thread_pool| through an |
| 143 // |execution_mode| task runner. If |wait_for_all_threads_idle| is true, the | 160 // |execution_mode| task runner. If |wait_for_all_threads_idle| is true, the |
| 144 // thread wait until all worker threads in |thread_pool| are idle before | 161 // thread wait until all worker threads in |thread_pool| are idle before |
| 145 // posting a new task. If |post_nested_task| is true, each task posted by this | 162 // posting a new task. If |post_nested_task| is true, each task posted by this |
| 146 // thread posts another task when it runs. | 163 // thread posts another task when it runs. |
| 147 ThreadPostingTasks(SchedulerThreadPool* thread_pool, | 164 ThreadPostingTasks(SchedulerThreadPool* thread_pool, |
| 148 ExecutionMode execution_mode, | 165 ExecutionMode execution_mode, |
| 149 bool wait_for_all_threads_idle, | 166 bool wait_for_all_threads_idle, |
| 150 bool post_nested_task) | 167 bool post_nested_task) |
| 151 : SimpleThread("ThreadPostingTasks"), | 168 : SimpleThread("ThreadPostingTasks"), |
| 152 thread_pool_(thread_pool), | 169 thread_pool_(thread_pool), |
| 153 task_runner_(thread_pool_->CreateTaskRunnerWithTraits(TaskTraits(), | |
| 154 execution_mode)), | |
| 155 wait_for_all_threads_idle_(wait_for_all_threads_idle), | 170 wait_for_all_threads_idle_(wait_for_all_threads_idle), |
| 156 post_nested_task_(post_nested_task) { | 171 post_nested_task_(post_nested_task), |
| 172 factory_(thread_pool_, execution_mode) { | |
| 157 DCHECK(thread_pool_); | 173 DCHECK(thread_pool_); |
| 158 } | 174 } |
| 159 | 175 |
| 160 const TaskFactory* factory() const { return &factory_; } | 176 const TaskFactory* factory() const { return &factory_; } |
| 161 | 177 |
| 162 private: | 178 private: |
| 163 void Run() override { | 179 void Run() override { |
| 164 EXPECT_FALSE(task_runner_->RunsTasksOnCurrentThread()); | 180 EXPECT_FALSE(factory_.task_runner()->RunsTasksOnCurrentThread()); |
| 165 | 181 |
| 166 for (size_t i = 0; i < kNumTasksPostedPerThread; ++i) { | 182 for (size_t i = 0; i < kNumTasksPostedPerThread; ++i) { |
| 167 if (wait_for_all_threads_idle_) | 183 if (wait_for_all_threads_idle_) |
| 168 thread_pool_->WaitForAllWorkerThreadsIdleForTesting(); | 184 thread_pool_->WaitForAllWorkerThreadsIdleForTesting(); |
| 169 factory_.PostTestTask(task_runner_, post_nested_task_, nullptr); | 185 factory_.PostTestTask(post_nested_task_, nullptr); |
| 170 } | 186 } |
| 171 } | 187 } |
| 172 | 188 |
| 173 SchedulerThreadPool* const thread_pool_; | 189 SchedulerThreadPool* const thread_pool_; |
| 174 const scoped_refptr<TaskRunner> task_runner_; | 190 const scoped_refptr<TaskRunner> task_runner_; |
| 175 const bool wait_for_all_threads_idle_; | 191 const bool wait_for_all_threads_idle_; |
| 176 const bool post_nested_task_; | 192 const bool post_nested_task_; |
| 177 TaskFactory factory_; | 193 TaskFactory factory_; |
| 178 | 194 |
| 179 DISALLOW_COPY_AND_ASSIGN(ThreadPostingTasks); | 195 DISALLOW_COPY_AND_ASSIGN(ThreadPostingTasks); |
| 180 }; | 196 }; |
| 181 | 197 |
| 182 TEST_F(TaskSchedulerThreadPoolTest, PostParallelTasks) { | 198 TEST_P(TaskSchedulerThreadPoolTest, PostTasks) { |
| 183 // Create threads to post tasks to PARALLEL TaskRunners. | 199 // Create threads to post tasks. |
| 184 std::vector<std::unique_ptr<ThreadPostingTasks>> threads_posting_tasks; | 200 std::vector<std::unique_ptr<ThreadPostingTasks>> threads_posting_tasks; |
| 185 for (size_t i = 0; i < kNumThreadsPostingTasks; ++i) { | 201 for (size_t i = 0; i < kNumThreadsPostingTasks; ++i) { |
| 186 const bool kWaitForAllThreadIdle = false; | 202 const bool kWaitForAllThreadIdle = false; |
| 187 const bool kPostNestedTasks = false; | 203 const bool kPostNestedTasks = false; |
| 188 threads_posting_tasks.push_back(WrapUnique( | 204 threads_posting_tasks.push_back(WrapUnique( |
| 189 new ThreadPostingTasks(thread_pool_.get(), ExecutionMode::PARALLEL, | 205 new ThreadPostingTasks(thread_pool_.get(), GetParam(), |
| 190 kWaitForAllThreadIdle, kPostNestedTasks))); | 206 kWaitForAllThreadIdle, kPostNestedTasks))); |
| 191 threads_posting_tasks.back()->Start(); | 207 threads_posting_tasks.back()->Start(); |
| 192 } | 208 } |
| 193 | 209 |
| 194 // Wait for all tasks to run. | 210 // Wait for all tasks to run. |
| 195 for (const auto& thread_posting_tasks : threads_posting_tasks) { | 211 for (const auto& thread_posting_tasks : threads_posting_tasks) { |
| 196 thread_posting_tasks->Join(); | 212 thread_posting_tasks->Join(); |
| 197 thread_posting_tasks->factory()->WaitForAllTasksToRun(); | 213 thread_posting_tasks->factory()->WaitForAllTasksToRun(); |
| 198 EXPECT_EQ(kNumTasksPostedPerThread, | 214 EXPECT_EQ(kNumTasksPostedPerThread, |
| 199 thread_posting_tasks->factory()->NumRunTasks()); | 215 thread_posting_tasks->factory()->NumRunTasks()); |
| 200 } | 216 } |
| 201 | 217 |
| 202 // Wait until all worker threads are idle to be sure that no task accesses | 218 // Wait until all worker threads are idle to be sure that no task accesses |
| 203 // its TaskFactory after |thread_posting_tasks| is destroyed. | 219 // its TaskFactory after |thread_posting_tasks| is destroyed. |
| 204 thread_pool_->WaitForAllWorkerThreadsIdleForTesting(); | 220 thread_pool_->WaitForAllWorkerThreadsIdleForTesting(); |
| 205 } | 221 } |
| 206 | 222 |
| 207 TEST_F(TaskSchedulerThreadPoolTest, PostParallelTasksWaitAllThreadsIdle) { | 223 TEST_P(TaskSchedulerThreadPoolTest, PostTasksWaitAllThreadsIdle) { |
| 208 // Create threads to post tasks to PARALLEL TaskRunners. To verify that | 224 // Create threads to post tasks. To verify that worker threads can sleep and |
| 209 // worker threads can sleep and be woken up when new tasks are posted, wait | 225 // be woken up when new tasks are posted, wait for all threads to become idle |
| 210 // for all threads to become idle before posting a new task. | 226 // before posting a new task. |
| 211 std::vector<std::unique_ptr<ThreadPostingTasks>> threads_posting_tasks; | 227 std::vector<std::unique_ptr<ThreadPostingTasks>> threads_posting_tasks; |
| 212 for (size_t i = 0; i < kNumThreadsPostingTasks; ++i) { | 228 for (size_t i = 0; i < kNumThreadsPostingTasks; ++i) { |
| 213 const bool kWaitForAllThreadIdle = true; | 229 const bool kWaitForAllThreadIdle = true; |
| 214 const bool kPostNestedTasks = false; | 230 const bool kPostNestedTasks = false; |
| 215 threads_posting_tasks.push_back(WrapUnique( | 231 threads_posting_tasks.push_back(WrapUnique( |
| 216 new ThreadPostingTasks(thread_pool_.get(), ExecutionMode::PARALLEL, | 232 new ThreadPostingTasks(thread_pool_.get(), GetParam(), |
| 217 kWaitForAllThreadIdle, kPostNestedTasks))); | 233 kWaitForAllThreadIdle, kPostNestedTasks))); |
| 218 threads_posting_tasks.back()->Start(); | 234 threads_posting_tasks.back()->Start(); |
| 219 } | 235 } |
| 220 | 236 |
| 221 // Wait for all tasks to run. | 237 // Wait for all tasks to run. |
| 222 for (const auto& thread_posting_tasks : threads_posting_tasks) { | 238 for (const auto& thread_posting_tasks : threads_posting_tasks) { |
| 223 thread_posting_tasks->Join(); | 239 thread_posting_tasks->Join(); |
| 224 thread_posting_tasks->factory()->WaitForAllTasksToRun(); | 240 thread_posting_tasks->factory()->WaitForAllTasksToRun(); |
| 225 EXPECT_EQ(kNumTasksPostedPerThread, | 241 EXPECT_EQ(kNumTasksPostedPerThread, |
| 226 thread_posting_tasks->factory()->NumRunTasks()); | 242 thread_posting_tasks->factory()->NumRunTasks()); |
| 227 } | 243 } |
| 228 | 244 |
| 229 // Wait until all worker threads are idle to be sure that no task accesses | 245 // Wait until all worker threads are idle to be sure that no task accesses |
| 230 // its TaskFactory after |thread_posting_tasks| is destroyed. | 246 // its TaskFactory after |thread_posting_tasks| is destroyed. |
| 231 thread_pool_->WaitForAllWorkerThreadsIdleForTesting(); | 247 thread_pool_->WaitForAllWorkerThreadsIdleForTesting(); |
| 232 } | 248 } |
| 233 | 249 |
| 234 TEST_F(TaskSchedulerThreadPoolTest, NestedPostParallelTasks) { | 250 TEST_P(TaskSchedulerThreadPoolTest, NestedPostTasks) { |
| 235 // Create threads to post tasks to PARALLEL TaskRunners. Each task posted by | 251 // Create threads to post tasks. Each task posted by these threads will post |
| 236 // these threads will post another task when it runs. | 252 // another task when it runs. |
| 237 std::vector<std::unique_ptr<ThreadPostingTasks>> threads_posting_tasks; | 253 std::vector<std::unique_ptr<ThreadPostingTasks>> threads_posting_tasks; |
| 238 for (size_t i = 0; i < kNumThreadsPostingTasks; ++i) { | 254 for (size_t i = 0; i < kNumThreadsPostingTasks; ++i) { |
| 239 const bool kWaitForAllThreadIdle = false; | 255 const bool kWaitForAllThreadIdle = false; |
| 240 const bool kPostNestedTasks = true; | 256 const bool kPostNestedTasks = true; |
| 241 threads_posting_tasks.push_back(WrapUnique( | 257 threads_posting_tasks.push_back(WrapUnique( |
| 242 new ThreadPostingTasks(thread_pool_.get(), ExecutionMode::PARALLEL, | 258 new ThreadPostingTasks(thread_pool_.get(), GetParam(), |
| 243 kWaitForAllThreadIdle, kPostNestedTasks))); | 259 kWaitForAllThreadIdle, kPostNestedTasks))); |
| 244 threads_posting_tasks.back()->Start(); | 260 threads_posting_tasks.back()->Start(); |
| 245 } | 261 } |
| 246 | 262 |
| 247 // Wait for all tasks to run. | 263 // Wait for all tasks to run. |
| 248 for (const auto& thread_posting_tasks : threads_posting_tasks) { | 264 for (const auto& thread_posting_tasks : threads_posting_tasks) { |
| 249 thread_posting_tasks->Join(); | 265 thread_posting_tasks->Join(); |
| 250 thread_posting_tasks->factory()->WaitForAllTasksToRun(); | 266 thread_posting_tasks->factory()->WaitForAllTasksToRun(); |
| 251 EXPECT_EQ(2 * kNumTasksPostedPerThread, | 267 EXPECT_EQ(2 * kNumTasksPostedPerThread, |
| 252 thread_posting_tasks->factory()->NumRunTasks()); | 268 thread_posting_tasks->factory()->NumRunTasks()); |
| 253 } | 269 } |
| 254 | 270 |
| 255 // Wait until all worker threads are idle to be sure that no task accesses | 271 // Wait until all worker threads are idle to be sure that no task accesses |
| 256 // its TaskFactory after |thread_posting_tasks| is destroyed. | 272 // its TaskFactory after |thread_posting_tasks| is destroyed. |
| 257 thread_pool_->WaitForAllWorkerThreadsIdleForTesting(); | 273 thread_pool_->WaitForAllWorkerThreadsIdleForTesting(); |
| 258 } | 274 } |
| 259 | 275 |
| 260 TEST_F(TaskSchedulerThreadPoolTest, PostParallelTasksWithOneAvailableThread) { | 276 TEST_P(TaskSchedulerThreadPoolTest, PostTasksWithOneAvailableThread) { |
| 261 TaskFactory factory; | |
| 262 | |
| 263 // Post tasks to keep all threads busy except one until |event| is signaled. | 277 // Post tasks to keep all threads busy except one until |event| is signaled. |
| 278 // Use different factories so that tasks are added to different sequences and | |
| 279 // can run simultaneously when the execution mode is SEQUENCED. | |
| 264 WaitableEvent event(true, false); | 280 WaitableEvent event(true, false); |
| 265 auto task_runner = thread_pool_->CreateTaskRunnerWithTraits( | 281 std::vector<std::unique_ptr<TaskFactory>> blocked_task_factories; |
| 266 TaskTraits(), ExecutionMode::PARALLEL); | 282 for (size_t i = 0; i < (kNumThreadsInThreadPool - 1); ++i) { |
| 267 for (size_t i = 0; i < (kNumThreadsInThreadPool - 1); ++i) | 283 blocked_task_factories.push_back( |
| 268 factory.PostTestTask(task_runner, false, &event); | 284 WrapUnique(new TaskFactory(thread_pool_.get(), GetParam()))); |
| 269 factory.WaitForAllTasksToRun(); | 285 blocked_task_factories.back()->PostTestTask(false, &event); |
| 286 blocked_task_factories.back()->WaitForAllTasksToRun(); | |
| 287 } | |
| 270 | 288 |
| 271 // Post |kNumTasksPostedPerThread| tasks that should all run despite the fact | 289 // Post |kNumTasksPostedPerThread| tasks that should all run despite the fact |
| 272 // that only one thread in |thread_pool_| isn't busy. | 290 // that only one thread in |thread_pool_| isn't busy. |
| 291 TaskFactory short_task_factory(thread_pool_.get(), GetParam()); | |
| 273 for (size_t i = 0; i < kNumTasksPostedPerThread; ++i) | 292 for (size_t i = 0; i < kNumTasksPostedPerThread; ++i) |
| 274 factory.PostTestTask(task_runner, false, nullptr); | 293 short_task_factory.PostTestTask(false, nullptr); |
| 275 factory.WaitForAllTasksToRun(); | 294 short_task_factory.WaitForAllTasksToRun(); |
| 276 | 295 |
| 277 // Release tasks waiting on |event|. | 296 // Release tasks waiting on |event|. |
| 278 event.Signal(); | 297 event.Signal(); |
| 279 | 298 |
| 280 // Wait until all worker threads are idle to be sure that no task accesses | 299 // Wait until all worker threads are idle to be sure that no task accesses |
| 281 // |factory| after it is destroyed. | 300 // its TaskFactory after it is destroyed. |
| 282 thread_pool_->WaitForAllWorkerThreadsIdleForTesting(); | 301 thread_pool_->WaitForAllWorkerThreadsIdleForTesting(); |
| 283 } | 302 } |
| 284 | 303 |
| 285 TEST_F(TaskSchedulerThreadPoolTest, Saturate) { | 304 TEST_P(TaskSchedulerThreadPoolTest, Saturate) { |
| 286 TaskFactory factory; | 305 // Verify that it is possible to have |kNumThreadsInThreadPool| |
| 287 | 306 // tasks/sequences running simultaneously. Use different factories so that |
| 288 // Verify that it is possible to have |kNumThreadsInThreadPool| tasks running | 307 // tasks are added to different sequences and can run simultaneously when the |
| 289 // simultaneously. | 308 // execution mode is SEQUENCED. |
| 290 WaitableEvent event(true, false); | 309 WaitableEvent event(true, false); |
| 291 auto task_runner = thread_pool_->CreateTaskRunnerWithTraits( | 310 std::vector<std::unique_ptr<TaskFactory>> factories; |
| 292 TaskTraits(), ExecutionMode::PARALLEL); | 311 for (size_t i = 0; i < kNumThreadsInThreadPool; ++i) { |
| 293 for (size_t i = 0; i < kNumThreadsInThreadPool; ++i) | 312 factories.push_back( |
| 294 factory.PostTestTask(task_runner, false, &event); | 313 WrapUnique(new TaskFactory(thread_pool_.get(), GetParam()))); |
| 295 factory.WaitForAllTasksToRun(); | 314 factories.back()->PostTestTask(false, &event); |
| 315 factories.back()->WaitForAllTasksToRun(); | |
| 316 } | |
| 296 | 317 |
| 297 // Release tasks waiting on |event|. | 318 // Release tasks waiting on |event|. |
| 298 event.Signal(); | 319 event.Signal(); |
|
danakj
2016/04/15 21:14:34
Could we maybe verify that all the tasks actually
fdoray
2016/04/15 21:49:41
This is done by line 315.
danakj
2016/04/15 22:32:43
Ah, word ok. I was expecting to see kNumThreadsInT
| |
| 299 | 320 |
| 300 // Wait until all worker threads are idle to be sure that no task accesses | 321 // Wait until all worker threads are idle to be sure that no task accesses |
| 301 // |factory| after it is destroyed. | 322 // its TaskFactory after it is destroyed. |
| 302 thread_pool_->WaitForAllWorkerThreadsIdleForTesting(); | 323 thread_pool_->WaitForAllWorkerThreadsIdleForTesting(); |
| 303 } | 324 } |
| 304 | 325 |
| 326 INSTANTIATE_TEST_CASE_P(Parallel, | |
| 327 TaskSchedulerThreadPoolTest, | |
| 328 ::testing::Values(ExecutionMode::PARALLEL)); | |
| 329 INSTANTIATE_TEST_CASE_P(Sequenced, | |
| 330 TaskSchedulerThreadPoolTest, | |
| 331 ::testing::Values(ExecutionMode::SEQUENCED)); | |
| 332 | |
| 305 } // namespace | 333 } // namespace |
| 306 } // namespace internal | 334 } // namespace internal |
| 307 } // namespace base | 335 } // namespace base |
| OLD | NEW |