Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(878)

Side by Side Diff: base/condition_variable_unittest.cc

Issue 19729: Reduce flakiness of condition var unit test (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 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 <time.h> 7 #include <time.h>
8 #include <algorithm> 8 #include <algorithm>
9 #include <vector> 9 #include <vector>
10 10
11 #include "base/condition_variable.h" 11 #include "base/condition_variable.h"
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/platform_thread.h" 13 #include "base/platform_thread.h"
14 #include "base/scoped_ptr.h" 14 #include "base/scoped_ptr.h"
15 #include "base/spin_wait.h" 15 #include "base/spin_wait.h"
16 #include "base/thread_collision_warner.h" 16 #include "base/thread_collision_warner.h"
17 #include "base/time.h"
17 #include "testing/gtest/include/gtest/gtest.h" 18 #include "testing/gtest/include/gtest/gtest.h"
18 #include "testing/platform_test.h" 19 #include "testing/platform_test.h"
19 20
20 using base::TimeDelta; 21 using base::TimeDelta;
21 using base::TimeTicks; 22 using base::TimeTicks;
22 23
23 namespace { 24 namespace {
24 //------------------------------------------------------------------------------ 25 //------------------------------------------------------------------------------
25 // Define our test class, with several common variables. 26 // Define our test class, with several common variables.
26 //------------------------------------------------------------------------------ 27 //------------------------------------------------------------------------------
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
91 92
92 //---------------------------------------------------------------------------- 93 //----------------------------------------------------------------------------
93 // The rest of the methods are for use by the controlling master thread (the 94 // The rest of the methods are for use by the controlling master thread (the
94 // test case code). 95 // test case code).
95 void ResetHistory(); 96 void ResetHistory();
96 int GetMinCompletionsByWorkerThread() const; 97 int GetMinCompletionsByWorkerThread() const;
97 int GetMaxCompletionsByWorkerThread() const; 98 int GetMaxCompletionsByWorkerThread() const;
98 int GetNumThreadsTakingAssignments() const; 99 int GetNumThreadsTakingAssignments() const;
99 int GetNumThreadsCompletingTasks() const; 100 int GetNumThreadsCompletingTasks() const;
100 int GetNumberOfCompletedTasks() const; 101 int GetNumberOfCompletedTasks() const;
102 TimeDelta GetWorkTime() const;
101 103
102 void SetWorkTime(TimeDelta delay); 104 void SetWorkTime(TimeDelta delay);
103 void SetTaskCount(int count); 105 void SetTaskCount(int count);
104 void SetAllowHelp(bool allow); 106 void SetAllowHelp(bool allow);
105 107
106 // Caller must acquire lock before calling. 108 // Caller must acquire lock before calling.
107 void SetShutdown(); 109 void SetShutdown();
108 110
109 // Compares the |shutdown_task_count_| to the |thread_count| and returns true 111 // Compares the |shutdown_task_count_| to the |thread_count| and returns true
110 // if they are equal. This check will acquire the |lock_| so the caller 112 // if they are equal. This check will acquire the |lock_| so the caller
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
173 175
174 cv.TimedWait(WAIT_TIME + FUDGE_TIME); 176 cv.TimedWait(WAIT_TIME + FUDGE_TIME);
175 TimeDelta duration = TimeTicks::Now() - start; 177 TimeDelta duration = TimeTicks::Now() - start;
176 // We can't use EXPECT_GE here as the TimeDelta class does not support the 178 // We can't use EXPECT_GE here as the TimeDelta class does not support the
177 // required stream conversion. 179 // required stream conversion.
178 EXPECT_TRUE(duration >= WAIT_TIME); 180 EXPECT_TRUE(duration >= WAIT_TIME);
179 181
180 lock.Release(); 182 lock.Release();
181 } 183 }
182 184
183 // This test is flaky due to excessive timing sensitivity. 185 // Test serial task servicing, as well as two parallel task servicing methods.
184 // http://code.google.com/p/chromium/issues/detail?id=3599 186 TEST_F(ConditionVariableTest, MultiThreadConsumerTest) {
185 // TODO(jar): A recent change to the WorkQueue fixed flakyness for the test
186 // LargeFastTaskTest. Specifically, the test was accessing the member variable
187 // WorkQueue::shutdown_task_count_ without a lock held. The MultiThreadConsumer
188 // test now ran successfully for 500 times on RalphL's machine. RalphL did not
189 // want to blindly re-enable this test if you know of other issues with it, but
190 // it appears that the flakyness is gone, but I'll leave that to you to verify.
191 TEST_F(ConditionVariableTest, DISABLED_MultiThreadConsumerTest) {
192 const int kThreadCount = 10; 187 const int kThreadCount = 10;
193 WorkQueue queue(kThreadCount); // Start the threads. 188 WorkQueue queue(kThreadCount); // Start the threads.
194 189
195 Lock private_lock; // Used locally for master to wait. 190 const int kTaskCount = 10; // Number of tasks in each mini-test here.
196 AutoLock private_held_lock(private_lock); 191
197 ConditionVariable private_cv(&private_lock); 192 base::Time start_time; // Used to time task processing.
198 193
199 { 194 {
200 AutoLock auto_lock(*queue.lock()); 195 AutoLock auto_lock(*queue.lock());
201 while (!queue.EveryIdWasAllocated()) 196 while (!queue.EveryIdWasAllocated())
202 queue.all_threads_have_ids()->Wait(); 197 queue.all_threads_have_ids()->Wait();
203 } 198 }
204 199
205 // Wait a bit more to allow threads to reach their wait state. 200 // Wait a bit more to allow threads to reach their wait state.
206 private_cv.TimedWait(kTenMs); 201 // If threads aren't in a wait state, they may start to gobble up tasks in
202 // parallel, short-circuiting (breaking) this test.
203 PlatformThread::Sleep(100);
207 204
208 { 205 {
209 // Since we have no tasks, all threads should be waiting by now. 206 // Since we have no tasks yet, all threads should be waiting by now.
210 AutoLock auto_lock(*queue.lock()); 207 AutoLock auto_lock(*queue.lock());
211 EXPECT_EQ(0, queue.GetNumThreadsTakingAssignments()); 208 EXPECT_EQ(0, queue.GetNumThreadsTakingAssignments());
212 EXPECT_EQ(0, queue.GetNumThreadsCompletingTasks()); 209 EXPECT_EQ(0, queue.GetNumThreadsCompletingTasks());
213 EXPECT_EQ(0, queue.task_count()); 210 EXPECT_EQ(0, queue.task_count());
214 EXPECT_EQ(0, queue.GetMaxCompletionsByWorkerThread()); 211 EXPECT_EQ(0, queue.GetMaxCompletionsByWorkerThread());
215 EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread()); 212 EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread());
216 EXPECT_EQ(0, queue.GetNumberOfCompletedTasks()); 213 EXPECT_EQ(0, queue.GetNumberOfCompletedTasks());
217 214
218 // Set up to make one worker do 3 30ms tasks. 215 // Set up to make one worker do 30ms tasks sequentially.
219 queue.ResetHistory(); 216 queue.ResetHistory();
220 queue.SetTaskCount(3); 217 queue.SetTaskCount(kTaskCount);
221 queue.SetWorkTime(kThirtyMs); 218 queue.SetWorkTime(kThirtyMs);
222 queue.SetAllowHelp(false); 219 queue.SetAllowHelp(false);
220
221 start_time = base::Time::Now();
223 } 222 }
223
224 queue.work_is_available()->Signal(); // Start up one thread. 224 queue.work_is_available()->Signal(); // Start up one thread.
225 // Wait to allow solo worker insufficient time to get done. 225
226 private_cv.TimedWait(kFortyFiveMs); // Should take about 90 ms.
227 226
228 { 227 {
229 // Check that all work HASN'T completed yet. 228 // Wait until all 10 work tasks have at least been assigned.
230 AutoLock auto_lock(*queue.lock()); 229 AutoLock auto_lock(*queue.lock());
230 while(queue.task_count())
231 queue.no_more_tasks()->Wait();
232 // The last of the tasks *might* still be running, but... all but one should
233 // be done by now, since tasks are being done serially.
234 EXPECT_LT(queue.GetWorkTime().InMilliseconds() * (kTaskCount - 1),
235 (base::Time::Now() - start_time).InMilliseconds());
236
231 EXPECT_EQ(1, queue.GetNumThreadsTakingAssignments()); 237 EXPECT_EQ(1, queue.GetNumThreadsTakingAssignments());
232 EXPECT_EQ(1, queue.GetNumThreadsCompletingTasks()); 238 EXPECT_EQ(1, queue.GetNumThreadsCompletingTasks());
233 EXPECT_GT(2, queue.task_count()); // 2 should have started. 239 EXPECT_LE(kTaskCount - 1, queue.GetMaxCompletionsByWorkerThread());
234 EXPECT_GT(3, queue.GetMaxCompletionsByWorkerThread());
235 EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread()); 240 EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread());
236 EXPECT_EQ(1, queue.GetNumberOfCompletedTasks()); 241 EXPECT_LE(kTaskCount - 1, queue.GetNumberOfCompletedTasks());
237 } 242 }
238 // Wait to allow solo workers to get done. 243
239 private_cv.TimedWait(kSixtyMs); // Should take about 45ms more. 244 // Wait to be sure all tasks are done.
245 while (1) {
246 {
247 AutoLock auto_lock(*queue.lock());
248 if (kTaskCount == queue.GetNumberOfCompletedTasks())
249 break;
250 }
251 PlatformThread::Sleep(30); // Wait a little.
252 }
240 253
241 { 254 {
242 // Check that all work was done by one thread id. 255 // Check that all work was done by one thread id.
243 AutoLock auto_lock(*queue.lock()); 256 AutoLock auto_lock(*queue.lock());
244 EXPECT_EQ(1, queue.GetNumThreadsTakingAssignments()); 257 EXPECT_EQ(1, queue.GetNumThreadsTakingAssignments());
245 EXPECT_EQ(1, queue.GetNumThreadsCompletingTasks()); 258 EXPECT_EQ(1, queue.GetNumThreadsCompletingTasks());
246 EXPECT_EQ(0, queue.task_count()); 259 EXPECT_EQ(0, queue.task_count());
247 EXPECT_EQ(3, queue.GetMaxCompletionsByWorkerThread()); 260 EXPECT_EQ(kTaskCount, queue.GetMaxCompletionsByWorkerThread());
248 EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread()); 261 EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread());
249 EXPECT_EQ(3, queue.GetNumberOfCompletedTasks()); 262 EXPECT_EQ(kTaskCount, queue.GetNumberOfCompletedTasks());
250 263
251 // Set up to make each task include getting help from another worker. 264 // Set up to make each task include getting help from another worker, so
265 // so that the work gets done in paralell.
252 queue.ResetHistory(); 266 queue.ResetHistory();
253 queue.SetTaskCount(3); 267 queue.SetTaskCount(kTaskCount);
254 queue.SetWorkTime(kThirtyMs); 268 queue.SetWorkTime(kThirtyMs);
255 queue.SetAllowHelp(true); 269 queue.SetAllowHelp(true);
270
271 start_time = base::Time::Now();
256 } 272 }
273
257 queue.work_is_available()->Signal(); // But each worker can signal another. 274 queue.work_is_available()->Signal(); // But each worker can signal another.
258 // Wait to allow the 3 workers to get done. 275 // Wait to allow the all workers to get done.
259 private_cv.TimedWait(kFortyFiveMs); // Should take about 30 ms. 276 while (1) {
277 {
278 AutoLock auto_lock(*queue.lock());
279 if (kTaskCount == queue.GetNumberOfCompletedTasks())
280 break;
281 }
282 PlatformThread::Sleep(30); // Wait a little.
283 }
260 284
261 { 285 {
286 // Wait until all work tasks have at least been assigned.
262 AutoLock auto_lock(*queue.lock()); 287 AutoLock auto_lock(*queue.lock());
263 EXPECT_EQ(3, queue.GetNumThreadsTakingAssignments()); 288 while(queue.task_count())
264 EXPECT_EQ(3, queue.GetNumThreadsCompletingTasks()); 289 queue.no_more_tasks()->Wait();
265 EXPECT_EQ(0, queue.task_count()); 290 // Since they can all run almost in parallel, there is no guarantee that all
266 EXPECT_EQ(1, queue.GetMaxCompletionsByWorkerThread()); 291 // tasks are finished, but we should have gotten here faster than it would
267 EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread()); 292 // take to run all tasks serially.
268 EXPECT_EQ(3, queue.GetNumberOfCompletedTasks()); 293 EXPECT_GT(queue.GetWorkTime().InMilliseconds() * (kTaskCount - 1),
294 (base::Time::Now() - start_time).InMilliseconds());
295
296 // To avoid racy assumptions, we'll just assert that at least 2 threads
297 // did work.
298 EXPECT_LE(2, queue.GetNumThreadsTakingAssignments());
299 EXPECT_EQ(kTaskCount, queue.GetNumberOfCompletedTasks());
269 300
270 // Try to ask all workers to help, and only a few will do the work. 301 // Try to ask all workers to help, and only a few will do the work.
271 queue.ResetHistory(); 302 queue.ResetHistory();
272 queue.SetTaskCount(3); 303 queue.SetTaskCount(3);
273 queue.SetWorkTime(kThirtyMs); 304 queue.SetWorkTime(kThirtyMs);
274 queue.SetAllowHelp(false); 305 queue.SetAllowHelp(false);
275 } 306 }
276 queue.work_is_available()->Broadcast(); // Make them all try. 307 queue.work_is_available()->Broadcast(); // Make them all try.
277 // Wait to allow the 3 workers to get done. 308 // Wait to allow the 3 workers to get done.
278 private_cv.TimedWait(kFortyFiveMs); 309 PlatformThread::Sleep(45);
279 310
280 { 311 {
281 AutoLock auto_lock(*queue.lock()); 312 AutoLock auto_lock(*queue.lock());
282 EXPECT_EQ(3, queue.GetNumThreadsTakingAssignments()); 313 EXPECT_EQ(3, queue.GetNumThreadsTakingAssignments());
283 EXPECT_EQ(3, queue.GetNumThreadsCompletingTasks()); 314 EXPECT_EQ(3, queue.GetNumThreadsCompletingTasks());
284 EXPECT_EQ(0, queue.task_count()); 315 EXPECT_EQ(0, queue.task_count());
285 EXPECT_EQ(1, queue.GetMaxCompletionsByWorkerThread()); 316 EXPECT_EQ(1, queue.GetMaxCompletionsByWorkerThread());
286 EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread()); 317 EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread());
287 EXPECT_EQ(3, queue.GetNumberOfCompletedTasks()); 318 EXPECT_EQ(3, queue.GetNumberOfCompletedTasks());
288 319
289 // Set up to make each task get help from another worker. 320 // Set up to make each task get help from another worker.
290 queue.ResetHistory(); 321 queue.ResetHistory();
291 queue.SetTaskCount(3); 322 queue.SetTaskCount(3);
292 queue.SetWorkTime(kThirtyMs); 323 queue.SetWorkTime(kThirtyMs);
293 queue.SetAllowHelp(true); // Allow (unnecessary) help requests. 324 queue.SetAllowHelp(true); // Allow (unnecessary) help requests.
294 } 325 }
295 queue.work_is_available()->Broadcast(); // We already signal all threads. 326 queue.work_is_available()->Broadcast(); // We already signal all threads.
296 // Wait to allow the 3 workers to get done. 327 // Wait to allow the 3 workers to get done.
297 private_cv.TimedWait(kOneHundredMs); 328 PlatformThread::Sleep(100);
298 329
299 { 330 {
300 AutoLock auto_lock(*queue.lock()); 331 AutoLock auto_lock(*queue.lock());
301 EXPECT_EQ(3, queue.GetNumThreadsTakingAssignments()); 332 EXPECT_EQ(3, queue.GetNumThreadsTakingAssignments());
302 EXPECT_EQ(3, queue.GetNumThreadsCompletingTasks()); 333 EXPECT_EQ(3, queue.GetNumThreadsCompletingTasks());
303 EXPECT_EQ(0, queue.task_count()); 334 EXPECT_EQ(0, queue.task_count());
304 EXPECT_EQ(1, queue.GetMaxCompletionsByWorkerThread()); 335 EXPECT_EQ(1, queue.GetMaxCompletionsByWorkerThread());
305 EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread()); 336 EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread());
306 EXPECT_EQ(3, queue.GetNumberOfCompletedTasks()); 337 EXPECT_EQ(3, queue.GetNumberOfCompletedTasks());
307 338
308 // Set up to make each task get help from another worker. 339 // Set up to make each task get help from another worker.
309 queue.ResetHistory(); 340 queue.ResetHistory();
310 queue.SetTaskCount(20); 341 queue.SetTaskCount(20);
311 queue.SetWorkTime(kThirtyMs); 342 queue.SetWorkTime(kThirtyMs);
312 queue.SetAllowHelp(true); 343 queue.SetAllowHelp(true);
313 } 344 }
314 queue.work_is_available()->Signal(); // But each worker can signal another. 345 queue.work_is_available()->Signal(); // But each worker can signal another.
315 // Wait to allow the 10 workers to get done. 346 // Wait to allow the 10 workers to get done.
316 private_cv.TimedWait(kOneHundredMs); // Should take about 60 ms. 347 PlatformThread::Sleep(100); // Should take about 60 ms.
317 348
318 { 349 {
319 AutoLock auto_lock(*queue.lock()); 350 AutoLock auto_lock(*queue.lock());
320 EXPECT_EQ(10, queue.GetNumThreadsTakingAssignments()); 351 EXPECT_EQ(10, queue.GetNumThreadsTakingAssignments());
321 EXPECT_EQ(10, queue.GetNumThreadsCompletingTasks()); 352 EXPECT_EQ(10, queue.GetNumThreadsCompletingTasks());
322 EXPECT_EQ(0, queue.task_count()); 353 EXPECT_EQ(0, queue.task_count());
323 EXPECT_EQ(2, queue.GetMaxCompletionsByWorkerThread()); 354 EXPECT_EQ(2, queue.GetMaxCompletionsByWorkerThread());
324 EXPECT_EQ(2, queue.GetMinCompletionsByWorkerThread()); 355 EXPECT_EQ(2, queue.GetMinCompletionsByWorkerThread());
325 EXPECT_EQ(20, queue.GetNumberOfCompletedTasks()); 356 EXPECT_EQ(20, queue.GetNumberOfCompletedTasks());
326 357
327 // Same as last test, but with Broadcast(). 358 // Same as last test, but with Broadcast().
328 queue.ResetHistory(); 359 queue.ResetHistory();
329 queue.SetTaskCount(20); // 2 tasks per process. 360 queue.SetTaskCount(20); // 2 tasks per process.
330 queue.SetWorkTime(kThirtyMs); 361 queue.SetWorkTime(kThirtyMs);
331 queue.SetAllowHelp(true); 362 queue.SetAllowHelp(true);
332 } 363 }
333 queue.work_is_available()->Broadcast(); 364 queue.work_is_available()->Broadcast();
334 // Wait to allow the 10 workers to get done. 365 // Wait to allow the 10 workers to get done.
335 private_cv.TimedWait(kOneHundredMs); // Should take about 60 ms. 366 PlatformThread::Sleep(100); // Should take about 60 ms.
336 367
337 { 368 {
338 AutoLock auto_lock(*queue.lock()); 369 AutoLock auto_lock(*queue.lock());
339 EXPECT_EQ(10, queue.GetNumThreadsTakingAssignments()); 370 EXPECT_EQ(10, queue.GetNumThreadsTakingAssignments());
340 EXPECT_EQ(10, queue.GetNumThreadsCompletingTasks()); 371 EXPECT_EQ(10, queue.GetNumThreadsCompletingTasks());
341 EXPECT_EQ(0, queue.task_count()); 372 EXPECT_EQ(0, queue.task_count());
342 EXPECT_EQ(2, queue.GetMaxCompletionsByWorkerThread()); 373 EXPECT_EQ(2, queue.GetMaxCompletionsByWorkerThread());
343 EXPECT_EQ(2, queue.GetMinCompletionsByWorkerThread()); 374 EXPECT_EQ(2, queue.GetMinCompletionsByWorkerThread());
344 EXPECT_EQ(20, queue.GetNumberOfCompletedTasks()); 375 EXPECT_EQ(20, queue.GetNumberOfCompletedTasks());
345 376
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after
609 return count; 640 return count;
610 } 641 }
611 642
612 int WorkQueue::GetNumberOfCompletedTasks() const { 643 int WorkQueue::GetNumberOfCompletedTasks() const {
613 int total = 0; 644 int total = 0;
614 for (int i = 0; i < thread_count_; ++i) 645 for (int i = 0; i < thread_count_; ++i)
615 total += completion_history_[i]; 646 total += completion_history_[i];
616 return total; 647 return total;
617 } 648 }
618 649
650 TimeDelta WorkQueue::GetWorkTime() const {
651 return worker_delay_;
652 }
653
619 void WorkQueue::SetWorkTime(TimeDelta delay) { 654 void WorkQueue::SetWorkTime(TimeDelta delay) {
620 worker_delay_ = delay; 655 worker_delay_ = delay;
621 } 656 }
622 657
623 void WorkQueue::SetTaskCount(int count) { 658 void WorkQueue::SetTaskCount(int count) {
624 task_count_ = count; 659 task_count_ = count;
625 } 660 }
626 661
627 void WorkQueue::SetAllowHelp(bool allow) { 662 void WorkQueue::SetAllowHelp(bool allow) {
628 allow_help_requests_ = allow; 663 allow_help_requests_ = allow;
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
693 728
694 { 729 {
695 AutoLock auto_lock(lock_); 730 AutoLock auto_lock(lock_);
696 // Send notification that we completed our "work." 731 // Send notification that we completed our "work."
697 WorkIsCompleted(thread_id); 732 WorkIsCompleted(thread_id);
698 } 733 }
699 } 734 }
700 } 735 }
701 736
702 } // namespace 737 } // namespace
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698