00001
00002
00003
00004
00005
00006 #include <stdio.h>
00007 #include <errno.h>
00008 #include <iomanip>
00009 #include <time.h>
00010 #ifndef WIN32
00011 #include <sys/time.h>
00012 #endif
00013 #include "rwlock_tester.h"
00014
00015 SyncOStream RWLockTester::stdSyncOStream(&std::cout);
00016
00017 static const unsigned long vthreads=kValidationThreadsNumber, vloops=kValidationLoopsNumber;
00018
00019 void RWLockLoopTest::mark_test_start()
00020 {
00021 #ifndef WIN32
00022 struct timeval tv;
00023 struct timezone tz;
00024 memset((void*)&tz, 0, sizeof(tz));
00025 gettimeofday(&tv, &tz);
00026 total_test_time = (MILLISECONDS)tv.tv_sec * 1000 + (MILLISECONDS)tv.tv_usec / 1000;
00027
00028 #else
00029 total_test_time = (MILLISECONDS)GetTickCount();
00030 #endif
00031 }
00032
00033 void RWLockLoopTest::mark_test_end()
00034 {
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047 #ifndef WIN32
00048 struct timeval tv;
00049 struct timezone tz;
00050 memset((void*)&tz, 0, sizeof(tz));
00051 gettimeofday(&tv, &tz);
00052 total_test_time = (MILLISECONDS)tv.tv_sec * 1000 + (MILLISECONDS)tv.tv_usec / 1000 - total_test_time;
00053 #else
00054 total_test_time = (MILLISECONDS)GetTickCount() - total_test_time;
00055 #endif
00056 }
00057
00058 volatile void RWLockLoopTest::run(int loops, int rwratio)
00059 {
00060 if(atomic_inc_return(&run_count) & 1)
00061 run_rw(loops, rwratio);
00062 else
00063 run_wr(loops, rwratio);
00064 }
00065
00066 volatile void RWLockLoopTest::run_rw(int loops, int rwratio)
00067 {
00068 MILLISECONDS rthread_time = read_test_loop(loops*rwratio);
00069 MILLISECONDS wthread_time = write_test_loop(loops);
00070
00071 cslock();
00072 read_thread_time += rthread_time;
00073 write_thread_time += wthread_time;
00074 total_read_thread_time += rthread_time;
00075 total_write_thread_time += wthread_time;
00076 csunlock();
00077 }
00078
00079 volatile void RWLockLoopTest::run_wr(int loops, int rwratio)
00080 {
00081 MILLISECONDS wthread_time = write_test_loop(loops*rwratio);
00082 MILLISECONDS rthread_time = read_test_loop(loops);
00083
00084 cslock();
00085 read_thread_time += rthread_time;
00086 write_thread_time += wthread_time;
00087 total_read_thread_time += rthread_time;
00088 total_write_thread_time += wthread_time;
00089 csunlock();
00090 }
00091
00092 volatile void RWLockLoopTest::run_r(int loops, int)
00093 {
00094 MILLISECONDS rthread_time = read_test_loop(loops);
00095
00096 cslock();
00097 read_thread_time += rthread_time;
00098 total_read_thread_time += rthread_time;
00099 csunlock();
00100 }
00101
00102 volatile void RWLockLoopTest::run_w(int loops, int)
00103 {
00104 MILLISECONDS wthread_time = write_test_loop(loops);
00105
00106 cslock();
00107 write_thread_time += wthread_time;
00108 total_write_thread_time += wthread_time;
00109 csunlock();
00110 }
00111
00112 void RWLockLoopTest::print_thread_times(void)
00113 {
00114 out.lock();
00115 out << "\tRead thread time="
00116 << (unsigned long)get_read_thread_time() << " milliseconds."
00117 << "\n\tWrite thread time="
00118 << (unsigned long)get_write_thread_time() << " milliseconds."
00119 << "\n\tTotal thread time="
00120 << (unsigned long)(get_write_thread_time() + get_read_thread_time()) << " milliseconds."
00121 << "\n\tTotal test time="
00122 << (unsigned long)get_total_test_time() << " milliseconds.\n\n";
00123 out.unlock();
00124 }
00125 void RWLockLoopTest::print_mixed_total(void)
00126 {
00127 out.lock();
00128 out << "\tTest thread time="
00129 << (unsigned long)get_read_thread_time() << " milliseconds."
00130 << "\n\tTotal test time="
00131 << (unsigned long)get_total_test_time() << " milliseconds.\n\n";
00132 out.unlock();
00133 }
00134
00135 void RWLockTester::validate(void)
00136 {
00137 SystemThread **thread_objs = new SystemThread * [vthreads];
00138 SystemThread **thread_objs2 = new SystemThread * [vthreads];
00139 int t;
00140
00141 for(std::vector<RWLockLoopTest *>::iterator i=lock_tests.begin(); i != lock_tests.end(); i++)
00142 {
00143 curr = *i;
00144
00145 out.lock();
00146 out << "Validating " << curr->name() << ":\n";
00147 out.unlock();
00148
00149 current_threads = 0;
00150
00151 signalStart();
00152
00153 curr->enter_write();
00154 for(t=0; t<vthreads; t++)
00155 {
00156 atomic_inc(¤t_threads);
00157 thread_objs[t] = new SystemThread(&thread_function_read, (void*)this);
00158 }
00159 while(current_read_threads != vthreads) SystemSleep(100);
00160 if(current_threads != vthreads)
00161 {
00162 out.lock();
00163 out << "Failed writer test, need to increase loops/threads number.\n";
00164 out.unlock();
00165
00166 exit(-1001);
00167 }
00168 curr->leave_write();
00169 thread_yield();
00170 for(t=0; t<vthreads; t++)
00171 {
00172 atomic_inc(¤t_threads);
00173 thread_objs2[t] = new SystemThread(&thread_function_read, (void*)this);
00174 }
00175 curr->enter_write();
00176 if(current_threads <= 0)
00177 {
00178 out << "Failed writer starvation test.\n";
00179 }
00180 else
00181 {
00182 out << "Writer starvation test passed - remaining readers: " <<
00183 current_threads << " out of " << vthreads*2 << ".\n";
00184 }
00185 curr->leave_write();
00186
00187 SystemSleep(100);
00188
00189 for(t=0; t<vthreads; t++)
00190 {
00191 delete thread_objs[t];
00192 delete thread_objs2[t];
00193 }
00194
00195 if(current_threads != 0)
00196 {
00197 out.lock();
00198 out << "Failed the framework test, current_threads= " << current_threads << "\n";
00199 out.unlock();
00200 exit(-1003);
00201 }
00202
00203 curr->enter_read();
00204 for(t=0; t<vthreads; t++)
00205 {
00206 atomic_inc(¤t_threads);
00207 thread_objs[t] = new SystemThread(&thread_function_write, (void*)this);
00208 }
00209 while(current_write_threads != vthreads) SystemSleep(100);
00210 if(current_threads != vthreads)
00211 {
00212 out.lock();
00213 out << "Failed reader test, need to increase loops/threads number.\n";
00214 out.unlock();
00215 }
00216 curr->leave_read();
00217 thread_yield();
00218 for(t=0; t<vthreads; t++)
00219 {
00220 atomic_inc(¤t_threads);
00221 thread_objs2[t] = new SystemThread(&thread_function_write, (void*)this);
00222 }
00223
00224 curr->enter_read();
00225 if(current_threads <= 0)
00226 {
00227 out << "Failed reader starvation test.\n";
00228 }
00229 else
00230 {
00231 out << "Reader starvation test passed - remaining writers: " <<
00232 current_threads << " out of " << vthreads*2 << ".\n";
00233 }
00234 curr->leave_read();
00235 SystemSleep(100);
00236 for(t=0; t<vthreads; t++)
00237 {
00238 delete thread_objs[t];
00239 delete thread_objs2[t];
00240 }
00241 if(current_threads != 0)
00242 {
00243 out.lock();
00244 out << "Failed the framework test 2, current_threads= " << current_threads << "\n";
00245 out.unlock();
00246 exit(-1013);
00247 }
00248 }
00249 delete [] thread_objs;
00250 delete [] thread_objs2;
00251 }
00252
00253 void RWLockTester::run_test(int threads_num, int loops, RWLockLoopTestRunFunction testf, int rwratio)
00254 {
00255 int t;
00256 SystemThread **thread_objs = new SystemThread * [threads_num];
00257 set_tests(threads_num, loops, rwratio, testf);
00258
00259 out.lock();
00260 out << "\n" << threads << " thread test.\n";
00261 out.unlock();
00262
00263 for(std::vector<RWLockLoopTest *>::iterator i=lock_tests.begin(); i != lock_tests.end(); i++)
00264 {
00265 curr = *i;
00266 out.lock();
00267 out << " " << curr->name() << ":\n";
00268 out.unlock();
00269 current_threads = 0;
00270
00271 clearStartFlag();
00272
00273 for(t=0; t<threads_num; t++)
00274 {
00275 atomic_inc(¤t_threads);
00276 thread_objs[t] = new SystemThread(&thread_function, (void*)this);
00277 thread_yield();
00278 }
00279
00280 while(current_threads > current_active_threads) thread_yield();
00281
00282 SystemSleep(2000);
00283
00284 curr->clear_thread_times();
00285 curr->mark_test_start();
00286
00287 signalStart();
00288
00289 while(current_threads > 0) thread_yield();
00290
00291 curr->mark_test_end();
00292
00293 for(t=0; t<threads_num; t++)
00294 {
00295 thread_objs[t]->join();
00296 delete thread_objs[t];
00297 thread_objs[t] = NULL;
00298 thread_yield();
00299 }
00300
00301 if(testfptr == &RWLockLoopTest::run_mixed)
00302 curr->print_mixed_total();
00303 else
00304 curr->print_thread_times();
00305 }
00306 delete [] thread_objs;
00307 }
00308
00309 void * RWLockTester::thread_function_read(void *ptr)
00310 {
00311 RWLockTester *thisPtr = (RWLockTester *)ptr;
00312 atomic_inc(&thisPtr->current_active_threads);
00313 atomic_inc(&thisPtr->current_read_threads);
00314
00315 thisPtr->waitForStart();
00316
00317 thisPtr->curr->read_test_loop(vloops);
00318
00319 atomic_dec(&thisPtr->current_read_threads);
00320 atomic_dec(&thisPtr->current_active_threads);
00321 atomic_dec(&thisPtr->current_threads);
00322 return NULL;
00323 }
00324
00325 void * RWLockTester::thread_function_write(void *ptr)
00326 {
00327 RWLockTester *thisPtr = (RWLockTester *)ptr;
00328 atomic_inc(&thisPtr->current_active_threads);
00329 atomic_inc(&thisPtr->current_write_threads);
00330
00331 thisPtr->waitForStart();
00332
00333 thisPtr->curr->write_test_loop(vloops);
00334
00335 atomic_dec(&thisPtr->current_write_threads);
00336 atomic_dec(&thisPtr->current_active_threads);
00337 atomic_dec(&thisPtr->current_threads);
00338 return NULL;
00339 }
00340
00341 void * RWLockTester::thread_function(void *ptr)
00342 {
00343 RWLockTester *thisPtr = (RWLockTester *)ptr;
00344 atomic_inc(&thisPtr->current_active_threads);
00345
00346 thisPtr->waitForStart();
00347
00348 (thisPtr->curr->*thisPtr->testfptr)(thisPtr->repeat, thisPtr->rw_ratio);
00349
00350 atomic_dec(&thisPtr->current_active_threads);
00351
00352 atomic_dec(&thisPtr->current_threads);
00353 return NULL;
00354 }
00355
00356 void RWLockTester::clear_summary(void)
00357 {
00358 for(std::vector<RWLockLoopTest *>::iterator i=lock_tests.begin(); i != lock_tests.end(); i++)
00359 (*i)->clear_total_thread_time();
00360 }
00361
00362 void RWLockTester::print_summary(void)
00363 {
00364 for(std::vector<RWLockLoopTest *>::iterator i=lock_tests.begin(); i != lock_tests.end(); i++)
00365 {
00366 RWLockLoopTest *ct = *i;
00367 out << "\nTest Summary for " << ct->name()
00368 << ":\n\tTotal read thread time="
00369 << (unsigned long)ct->get_total_read_thread_time()
00370 << "\n\tTotal write thread time="
00371 << (unsigned long)ct->get_total_write_thread_time()
00372 << "\n\tTotal R/W thread time="
00373 << (unsigned long)(ct->get_total_read_thread_time() + ct->get_total_write_thread_time()) << "\n";
00374 }
00375 }
00376
00377 void GraphData::init(const RWLockTester &tester, const int *th_counts, size_t thread_count_len)
00378 {
00379 threads.clear();
00380 threads.insert(threads.begin(),th_counts, th_counts+thread_count_len);
00381 for(std::vector<RWLockLoopTest *>::const_iterator i=tester.begin(); i!=tester.end(); i++)
00382 {
00383 size_t last = lock_info.size();
00384 lock_info.resize(last+1);
00385 lock_info[last].clear();
00386 lock_info[last].name = (*i)->name();
00387 lock_info[last].resize(thread_count_len);
00388 }
00389 }
00390
00391 int GraphData::add_results(const RWLockTester &tester, size_t thread_count_num)
00392 {
00393 for(size_t indx=0; indx<tester.size(); indx++)
00394 {
00395 lock_info[indx].read[thread_count_num] = tester[indx]->get_read_thread_time();
00396 lock_info[indx].write[thread_count_num] = tester[indx]->get_write_thread_time();
00397 lock_info[indx].total[thread_count_num] = tester[indx]->get_total_test_time();
00398 }
00399 return 0;
00400 }
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496