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 <= 5000) { |
| 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 |