| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 // Multi-threaded tests of ConditionVariable class. | 5 // Multi-threaded tests of ConditionVariable class. |
| 6 | 6 |
| 7 #include "base/synchronization/condition_variable.h" | 7 #include "base/synchronization/condition_variable.h" |
| 8 | 8 |
| 9 #include <time.h> | 9 #include <time.h> |
| 10 | 10 |
| (...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 247 | 247 |
| 248 | 248 |
| 249 // Suddenly got flaky on Win, see http://crbug.com/10607 (starting at | 249 // Suddenly got flaky on Win, see http://crbug.com/10607 (starting at |
| 250 // comment #15). | 250 // comment #15). |
| 251 #if defined(OS_WIN) | 251 #if defined(OS_WIN) |
| 252 #define MAYBE_MultiThreadConsumerTest DISABLED_MultiThreadConsumerTest | 252 #define MAYBE_MultiThreadConsumerTest DISABLED_MultiThreadConsumerTest |
| 253 #else | 253 #else |
| 254 #define MAYBE_MultiThreadConsumerTest MultiThreadConsumerTest | 254 #define MAYBE_MultiThreadConsumerTest MultiThreadConsumerTest |
| 255 #endif | 255 #endif |
| 256 // Test serial task servicing, as well as two parallel task servicing methods. | 256 // Test serial task servicing, as well as two parallel task servicing methods. |
| 257 TEST_F(ConditionVariableTest, MAYBE_MultiThreadConsumerTest) { | 257 TEST_F(ConditionVariableTest, MultiThreadConsumerTest) { |
| 258 const int kThreadCount = 10; | 258 int current_test = 0; |
| 259 WorkQueue queue(kThreadCount); // Start the threads. | 259 while (++current_test <= 100) { |
| 260 const int kThreadCount = 10; |
| 261 WorkQueue queue(kThreadCount); // Start the threads. |
| 260 | 262 |
| 261 const int kTaskCount = 10; // Number of tasks in each mini-test here. | 263 const int kTaskCount = 10; // Number of tasks in each mini-test here. |
| 262 | 264 |
| 263 Time start_time; // Used to time task processing. | 265 Time start_time; // Used to time task processing. |
| 264 | 266 |
| 265 { | 267 { |
| 266 base::AutoLock auto_lock(*queue.lock()); | 268 base::AutoLock auto_lock(*queue.lock()); |
| 267 while (!queue.EveryIdWasAllocated()) | 269 while (!queue.EveryIdWasAllocated()) |
| 268 queue.all_threads_have_ids()->Wait(); | 270 queue.all_threads_have_ids()->Wait(); |
| 271 } |
| 272 |
| 273 // If threads aren't in a wait state, they may start to gobble up tasks in |
| 274 // parallel, short-circuiting (breaking) this test. |
| 275 queue.SpinUntilAllThreadsAreWaiting(); |
| 276 |
| 277 { |
| 278 // Since we have no tasks yet, all threads should be waiting by now. |
| 279 base::AutoLock auto_lock(*queue.lock()); |
| 280 EXPECT_EQ(0, queue.GetNumThreadsTakingAssignments()); |
| 281 EXPECT_EQ(0, queue.GetNumThreadsCompletingTasks()); |
| 282 EXPECT_EQ(0, queue.task_count()); |
| 283 EXPECT_EQ(0, queue.GetMaxCompletionsByWorkerThread()); |
| 284 EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread()); |
| 285 EXPECT_EQ(0, queue.GetNumberOfCompletedTasks()); |
| 286 |
| 287 // Set up to make each task include getting help from another worker, so |
| 288 // so that the work gets done in paralell. |
| 289 queue.ResetHistory(); |
| 290 queue.SetTaskCount(kTaskCount); |
| 291 queue.SetWorkTime(kThirtyMs); |
| 292 queue.SetAllowHelp(true); |
| 293 |
| 294 start_time = Time::Now(); |
| 295 } |
| 296 |
| 297 queue.work_is_available()->Signal(); // But each worker can signal another. |
| 298 // Wait till we at least start to handle tasks (and we're not all waiting). |
| 299 queue.SpinUntilTaskCountLessThan(kTaskCount); |
| 300 // Wait to allow the all workers to get done. |
| 301 queue.SpinUntilAllThreadsAreWaiting(); |
| 302 |
| 303 { |
| 304 // Wait until all work tasks have at least been assigned. |
| 305 base::AutoLock auto_lock(*queue.lock()); |
| 306 while (queue.task_count()) |
| 307 queue.no_more_tasks()->Wait(); |
| 308 |
| 309 // To avoid racy assumptions, we'll just assert that at least 2 threads |
| 310 // did work. We know that the first worker should have gone to sleep, and |
| 311 // hence a second worker should have gotten an assignment. |
| 312 EXPECT_LE(2, queue.GetNumThreadsTakingAssignments()); |
| 313 EXPECT_EQ(kTaskCount, queue.GetNumberOfCompletedTasks()); |
| 314 |
| 315 // Try to ask all workers to help, and only a few will do the work. |
| 316 queue.ResetHistory(); |
| 317 queue.SetTaskCount(3); |
| 318 queue.SetWorkTime(kThirtyMs); |
| 319 queue.SetAllowHelp(false); |
| 320 } |
| 321 queue.work_is_available()->Broadcast(); // Make them all try. |
| 322 // Wait till we at least start to handle tasks (and we're not all waiting). |
| 323 queue.SpinUntilTaskCountLessThan(3); |
| 324 // Wait to allow the 3 workers to get done. |
| 325 queue.SpinUntilAllThreadsAreWaiting(); |
| 326 |
| 327 { |
| 328 base::AutoLock auto_lock(*queue.lock()); |
| 329 EXPECT_EQ(3, queue.GetNumThreadsTakingAssignments()); |
| 330 EXPECT_EQ(3, queue.GetNumThreadsCompletingTasks()); |
| 331 EXPECT_EQ(0, queue.task_count()); |
| 332 EXPECT_EQ(1, queue.GetMaxCompletionsByWorkerThread()); |
| 333 EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread()); |
| 334 EXPECT_EQ(3, queue.GetNumberOfCompletedTasks()); |
| 335 |
| 336 // Set up to make each task get help from another worker. |
| 337 queue.ResetHistory(); |
| 338 queue.SetTaskCount(3); |
| 339 queue.SetWorkTime(kThirtyMs); |
| 340 queue.SetAllowHelp(true); // Allow (unnecessary) help requests. |
| 341 } |
| 342 queue.work_is_available()->Broadcast(); // Signal all threads. |
| 343 // Wait till we at least start to handle tasks (and we're not all waiting). |
| 344 queue.SpinUntilTaskCountLessThan(3); |
| 345 // Wait to allow the 3 workers to get done. |
| 346 queue.SpinUntilAllThreadsAreWaiting(); |
| 347 |
| 348 { |
| 349 base::AutoLock auto_lock(*queue.lock()); |
| 350 EXPECT_EQ(3, queue.GetNumThreadsTakingAssignments()); |
| 351 EXPECT_EQ(3, queue.GetNumThreadsCompletingTasks()); |
| 352 EXPECT_EQ(0, queue.task_count()); |
| 353 EXPECT_EQ(1, queue.GetMaxCompletionsByWorkerThread()); |
| 354 EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread()); |
| 355 EXPECT_EQ(3, queue.GetNumberOfCompletedTasks()); |
| 356 |
| 357 // Set up to make each task get help from another worker. |
| 358 queue.ResetHistory(); |
| 359 queue.SetTaskCount(20); // 2 tasks per thread. |
| 360 queue.SetWorkTime(kThirtyMs); |
| 361 queue.SetAllowHelp(true); |
| 362 } |
| 363 queue.work_is_available()->Signal(); // But each worker can signal another. |
| 364 // Wait till we at least start to handle tasks (and we're not all waiting). |
| 365 queue.SpinUntilTaskCountLessThan(20); |
| 366 // Wait to allow the 10 workers to get done. |
| 367 queue.SpinUntilAllThreadsAreWaiting(); // Should take about 60 ms. |
| 368 |
| 369 { |
| 370 base::AutoLock auto_lock(*queue.lock()); |
| 371 EXPECT_EQ(10, queue.GetNumThreadsTakingAssignments()); |
| 372 EXPECT_EQ(10, queue.GetNumThreadsCompletingTasks()); |
| 373 EXPECT_EQ(0, queue.task_count()); |
| 374 EXPECT_EQ(20, queue.GetNumberOfCompletedTasks()); |
| 375 |
| 376 // Same as last test, but with Broadcast(). |
| 377 queue.ResetHistory(); |
| 378 queue.SetTaskCount(20); // 2 tasks per thread. |
| 379 queue.SetWorkTime(kThirtyMs); |
| 380 queue.SetAllowHelp(true); |
| 381 } |
| 382 queue.work_is_available()->Broadcast(); |
| 383 // Wait till we at least start to handle tasks (and we're not all waiting). |
| 384 queue.SpinUntilTaskCountLessThan(20); |
| 385 // Wait to allow the 10 workers to get done. |
| 386 queue.SpinUntilAllThreadsAreWaiting(); // Should take about 60 ms. |
| 387 |
| 388 { |
| 389 base::AutoLock auto_lock(*queue.lock()); |
| 390 EXPECT_EQ(10, queue.GetNumThreadsTakingAssignments()); |
| 391 EXPECT_EQ(10, queue.GetNumThreadsCompletingTasks()); |
| 392 EXPECT_EQ(0, queue.task_count()); |
| 393 EXPECT_EQ(20, queue.GetNumberOfCompletedTasks()); |
| 394 |
| 395 queue.SetShutdown(); |
| 396 } |
| 397 queue.work_is_available()->Broadcast(); // Force check for shutdown. |
| 398 |
| 399 SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE( |
| 400 TimeDelta::FromMinutes(1), queue.ThreadSafeCheckShutdown(kThreadCount)); |
| 269 } | 401 } |
| 270 | |
| 271 // If threads aren't in a wait state, they may start to gobble up tasks in | |
| 272 // parallel, short-circuiting (breaking) this test. | |
| 273 queue.SpinUntilAllThreadsAreWaiting(); | |
| 274 | |
| 275 { | |
| 276 // Since we have no tasks yet, all threads should be waiting by now. | |
| 277 base::AutoLock auto_lock(*queue.lock()); | |
| 278 EXPECT_EQ(0, queue.GetNumThreadsTakingAssignments()); | |
| 279 EXPECT_EQ(0, queue.GetNumThreadsCompletingTasks()); | |
| 280 EXPECT_EQ(0, queue.task_count()); | |
| 281 EXPECT_EQ(0, queue.GetMaxCompletionsByWorkerThread()); | |
| 282 EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread()); | |
| 283 EXPECT_EQ(0, queue.GetNumberOfCompletedTasks()); | |
| 284 | |
| 285 // Set up to make each task include getting help from another worker, so | |
| 286 // so that the work gets done in paralell. | |
| 287 queue.ResetHistory(); | |
| 288 queue.SetTaskCount(kTaskCount); | |
| 289 queue.SetWorkTime(kThirtyMs); | |
| 290 queue.SetAllowHelp(true); | |
| 291 | |
| 292 start_time = Time::Now(); | |
| 293 } | |
| 294 | |
| 295 queue.work_is_available()->Signal(); // But each worker can signal another. | |
| 296 // Wait till we at least start to handle tasks (and we're not all waiting). | |
| 297 queue.SpinUntilTaskCountLessThan(kTaskCount); | |
| 298 // Wait to allow the all workers to get done. | |
| 299 queue.SpinUntilAllThreadsAreWaiting(); | |
| 300 | |
| 301 { | |
| 302 // Wait until all work tasks have at least been assigned. | |
| 303 base::AutoLock auto_lock(*queue.lock()); | |
| 304 while (queue.task_count()) | |
| 305 queue.no_more_tasks()->Wait(); | |
| 306 | |
| 307 // To avoid racy assumptions, we'll just assert that at least 2 threads | |
| 308 // did work. We know that the first worker should have gone to sleep, and | |
| 309 // hence a second worker should have gotten an assignment. | |
| 310 EXPECT_LE(2, queue.GetNumThreadsTakingAssignments()); | |
| 311 EXPECT_EQ(kTaskCount, queue.GetNumberOfCompletedTasks()); | |
| 312 | |
| 313 // Try to ask all workers to help, and only a few will do the work. | |
| 314 queue.ResetHistory(); | |
| 315 queue.SetTaskCount(3); | |
| 316 queue.SetWorkTime(kThirtyMs); | |
| 317 queue.SetAllowHelp(false); | |
| 318 } | |
| 319 queue.work_is_available()->Broadcast(); // Make them all try. | |
| 320 // Wait till we at least start to handle tasks (and we're not all waiting). | |
| 321 queue.SpinUntilTaskCountLessThan(3); | |
| 322 // Wait to allow the 3 workers to get done. | |
| 323 queue.SpinUntilAllThreadsAreWaiting(); | |
| 324 | |
| 325 { | |
| 326 base::AutoLock auto_lock(*queue.lock()); | |
| 327 EXPECT_EQ(3, queue.GetNumThreadsTakingAssignments()); | |
| 328 EXPECT_EQ(3, queue.GetNumThreadsCompletingTasks()); | |
| 329 EXPECT_EQ(0, queue.task_count()); | |
| 330 EXPECT_EQ(1, queue.GetMaxCompletionsByWorkerThread()); | |
| 331 EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread()); | |
| 332 EXPECT_EQ(3, queue.GetNumberOfCompletedTasks()); | |
| 333 | |
| 334 // Set up to make each task get help from another worker. | |
| 335 queue.ResetHistory(); | |
| 336 queue.SetTaskCount(3); | |
| 337 queue.SetWorkTime(kThirtyMs); | |
| 338 queue.SetAllowHelp(true); // Allow (unnecessary) help requests. | |
| 339 } | |
| 340 queue.work_is_available()->Broadcast(); // Signal all threads. | |
| 341 // Wait till we at least start to handle tasks (and we're not all waiting). | |
| 342 queue.SpinUntilTaskCountLessThan(3); | |
| 343 // Wait to allow the 3 workers to get done. | |
| 344 queue.SpinUntilAllThreadsAreWaiting(); | |
| 345 | |
| 346 { | |
| 347 base::AutoLock auto_lock(*queue.lock()); | |
| 348 EXPECT_EQ(3, queue.GetNumThreadsTakingAssignments()); | |
| 349 EXPECT_EQ(3, queue.GetNumThreadsCompletingTasks()); | |
| 350 EXPECT_EQ(0, queue.task_count()); | |
| 351 EXPECT_EQ(1, queue.GetMaxCompletionsByWorkerThread()); | |
| 352 EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread()); | |
| 353 EXPECT_EQ(3, queue.GetNumberOfCompletedTasks()); | |
| 354 | |
| 355 // Set up to make each task get help from another worker. | |
| 356 queue.ResetHistory(); | |
| 357 queue.SetTaskCount(20); // 2 tasks per thread. | |
| 358 queue.SetWorkTime(kThirtyMs); | |
| 359 queue.SetAllowHelp(true); | |
| 360 } | |
| 361 queue.work_is_available()->Signal(); // But each worker can signal another. | |
| 362 // Wait till we at least start to handle tasks (and we're not all waiting). | |
| 363 queue.SpinUntilTaskCountLessThan(20); | |
| 364 // Wait to allow the 10 workers to get done. | |
| 365 queue.SpinUntilAllThreadsAreWaiting(); // Should take about 60 ms. | |
| 366 | |
| 367 { | |
| 368 base::AutoLock auto_lock(*queue.lock()); | |
| 369 EXPECT_EQ(10, queue.GetNumThreadsTakingAssignments()); | |
| 370 EXPECT_EQ(10, queue.GetNumThreadsCompletingTasks()); | |
| 371 EXPECT_EQ(0, queue.task_count()); | |
| 372 EXPECT_EQ(20, queue.GetNumberOfCompletedTasks()); | |
| 373 | |
| 374 // Same as last test, but with Broadcast(). | |
| 375 queue.ResetHistory(); | |
| 376 queue.SetTaskCount(20); // 2 tasks per thread. | |
| 377 queue.SetWorkTime(kThirtyMs); | |
| 378 queue.SetAllowHelp(true); | |
| 379 } | |
| 380 queue.work_is_available()->Broadcast(); | |
| 381 // Wait till we at least start to handle tasks (and we're not all waiting). | |
| 382 queue.SpinUntilTaskCountLessThan(20); | |
| 383 // Wait to allow the 10 workers to get done. | |
| 384 queue.SpinUntilAllThreadsAreWaiting(); // Should take about 60 ms. | |
| 385 | |
| 386 { | |
| 387 base::AutoLock auto_lock(*queue.lock()); | |
| 388 EXPECT_EQ(10, queue.GetNumThreadsTakingAssignments()); | |
| 389 EXPECT_EQ(10, queue.GetNumThreadsCompletingTasks()); | |
| 390 EXPECT_EQ(0, queue.task_count()); | |
| 391 EXPECT_EQ(20, queue.GetNumberOfCompletedTasks()); | |
| 392 | |
| 393 queue.SetShutdown(); | |
| 394 } | |
| 395 queue.work_is_available()->Broadcast(); // Force check for shutdown. | |
| 396 | |
| 397 SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(1), | |
| 398 queue.ThreadSafeCheckShutdown(kThreadCount)); | |
| 399 } | 402 } |
| 400 | 403 |
| 401 TEST_F(ConditionVariableTest, LargeFastTaskTest) { | 404 TEST_F(ConditionVariableTest, LargeFastTaskTest) { |
| 402 const int kThreadCount = 200; | 405 const int kThreadCount = 200; |
| 403 WorkQueue queue(kThreadCount); // Start the threads. | 406 WorkQueue queue(kThreadCount); // Start the threads. |
| 404 | 407 |
| 405 Lock private_lock; // Used locally for master to wait. | 408 Lock private_lock; // Used locally for master to wait. |
| 406 base::AutoLock private_held_lock(private_lock); | 409 base::AutoLock private_held_lock(private_lock); |
| 407 ConditionVariable private_cv(&private_lock); | 410 ConditionVariable private_cv(&private_lock); |
| 408 | 411 |
| (...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 759 base::AutoLock auto_lock(lock_); | 762 base::AutoLock auto_lock(lock_); |
| 760 // Send notification that we completed our "work." | 763 // Send notification that we completed our "work." |
| 761 WorkIsCompleted(thread_id); | 764 WorkIsCompleted(thread_id); |
| 762 } | 765 } |
| 763 } | 766 } |
| 764 } | 767 } |
| 765 | 768 |
| 766 } // namespace | 769 } // namespace |
| 767 | 770 |
| 768 } // namespace base | 771 } // namespace base |
| OLD | NEW |