00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "fennel/common/CommonPreamble.h"
00025 #include "fennel/test/PagingTestBase.h"
00026 #include "fennel/common/FileSystem.h"
00027 #include "fennel/device/RandomAccessFileDevice.h"
00028 #include "fennel/synch/Thread.h"
00029 #include "fennel/cache/CachePage.h"
00030 #include "fennel/cache/CacheImpl.h"
00031 #include "fennel/cache/RandomVictimPolicy.h"
00032 #include <boost/test/test_tools.hpp>
00033
00034
00035 #include <functional>
00036
00037 using namespace fennel;
00038
00039 static boost::thread_specific_ptr<std::subtractive_rng> g_pRNG;
00040
00041 void PagingTestBase::threadInit()
00042 {
00043 ThreadedTestBase::threadInit();
00044 g_pRNG.reset(new std::subtractive_rng());
00045 }
00046
00047 void PagingTestBase::threadTerminate()
00048 {
00049 g_pRNG.reset();
00050 ThreadedTestBase::threadTerminate();
00051 }
00052
00053 uint PagingTestBase::generateRandomNumber(uint iMax)
00054 {
00055 return (*g_pRNG)(iMax);
00056 }
00057
00058 void PagingTestBase::fillPage(CachePage &page,uint x)
00059 {
00060 uint *p = reinterpret_cast<uint *>(page.getWritableData());
00061 assert(cbPageUsable);
00062 uint n = cbPageUsable / sizeof(uint);
00063 for (uint i = 0; i < n; i++) {
00064 p[i] = x + i;
00065 }
00066 uint r = generateRandomNumber(n);
00067 p[r] = 0;
00068 }
00069
00070 void PagingTestBase::verifyPage(CachePage &page,uint x)
00071 {
00072 uint const *p = reinterpret_cast<uint const *>(page.getReadableData());
00073 assert(cbPageUsable);
00074 uint n = cbPageUsable / sizeof(uint);
00075 uint nZeros = 0;
00076 for (uint i = 0; i < n; i++) {
00077 if (p[i] != x + i) {
00078 assert(!p[i]);
00079 nZeros++;
00080 }
00081 }
00082 assert(nZeros < 2);
00083 }
00084
00085 bool PagingTestBase::testOp(OpType opType,uint iPage,bool bNice)
00086 {
00087 CachePage *pPage = lockPage(opType,iPage);
00088 LockMode lockMode = getLockMode(opType);
00089 if (!pPage) {
00090
00091 assert(lockMode >= LOCKMODE_S_NOWAIT);
00092 return false;
00093 }
00094 CachePage &page = *pPage;
00095 if (lockMode == LOCKMODE_S
00096 || lockMode == LOCKMODE_S_NOWAIT)
00097 {
00098 verifyPage(page,iPage);
00099 } else {
00100 fillPage(page,iPage);
00101 }
00102 switch (lockMode) {
00103 case LOCKMODE_X_NOWAIT:
00104 lockMode = LOCKMODE_X;
00105 break;
00106 case LOCKMODE_S_NOWAIT:
00107 lockMode = LOCKMODE_S;
00108 break;
00109 default:
00110 break;
00111 }
00112 if (bNice) {
00113 getCache().nicePage(page);
00114 }
00115 unlockPage(page,lockMode);
00116 return true;
00117 }
00118
00119 char const *PagingTestBase::getOpName(OpType opType)
00120 {
00121 switch (opType) {
00122 case OP_ALLOCATE:
00123 return "allocate";
00124 case OP_READ_SEQ:
00125 return "sequential read";
00126 case OP_WRITE_SEQ:
00127 return "sequential write";
00128 case OP_READ_RAND:
00129 return "random read";
00130 case OP_WRITE_RAND:
00131 return "random write";
00132 case OP_READ_NOWAIT:
00133 return "read no-wait";
00134 case OP_WRITE_NOWAIT:
00135 return "write no-wait";
00136 case OP_WRITE_SKIP:
00137 return "write every n pages";
00138 default:
00139 permAssert(false);
00140 }
00141 }
00142
00143 LockMode PagingTestBase::getLockMode(OpType opType)
00144 {
00145 switch (opType) {
00146 case OP_ALLOCATE:
00147 return LOCKMODE_X;
00148 case OP_READ_SEQ:
00149 return LOCKMODE_S;
00150 case OP_WRITE_SEQ:
00151 return LOCKMODE_X;
00152 case OP_READ_RAND:
00153 return LOCKMODE_S;
00154 case OP_WRITE_RAND:
00155 return LOCKMODE_X;
00156 case OP_READ_NOWAIT:
00157 return LOCKMODE_S_NOWAIT;
00158 case OP_WRITE_NOWAIT:
00159 return LOCKMODE_X_NOWAIT;
00160 case OP_WRITE_SKIP:
00161 return LOCKMODE_X;
00162 default:
00163 permAssert(false);
00164 }
00165 }
00166
00167 void PagingTestBase::testSequentialOp(OpType opType)
00168 {
00169 uint n = 0;
00170 for (uint i = 0; i < nDiskPages; i++) {
00171 if (testOp(opType,i,true)) {
00172 n++;
00173 }
00174 }
00175 StrictMutexGuard mutexGuard(logMutex);
00176 BOOST_MESSAGE(
00177 "completed " << n << " " << getOpName(opType) << " ops");
00178 }
00179
00180 void PagingTestBase::testRandomOp(OpType opType)
00181 {
00182 uint n = 0;
00183 for (uint i = 0; i < nRandomOps; i++) {
00184 uint iPage = generateRandomNumber(nDiskPages);
00185 bool bNice = (generateRandomNumber(nRandomOps) == 0);
00186 if (testOp(opType,iPage,bNice)) {
00187 n++;
00188 }
00189 }
00190 StrictMutexGuard mutexGuard(logMutex);
00191 BOOST_MESSAGE(
00192 "completed " << n << " " << getOpName(opType) << " ops");
00193
00194 }
00195
00196 void PagingTestBase::testSkipOp(OpType opType, uint n)
00197 {
00198 uint numOps = 0;
00199 for (uint i = 0; i < nDiskPages; i += n) {
00200 if (testOp(opType,i,true)) {
00201 numOps++;
00202 }
00203 }
00204 StrictMutexGuard mutexGuard(logMutex);
00205 BOOST_MESSAGE(
00206 "completed " << numOps << " " << getOpName(opType) << " ops");
00207 }
00208
00209 void PagingTestBase::testScratch()
00210 {
00211 for (uint i = 0; i < nRandomOps; i++) {
00212 CachePage &page = getCache().lockScratchPage();
00213 fillPage(page,generateRandomNumber(10000));
00214 getCache().unlockPage(page,LOCKMODE_X);
00215 }
00216 StrictMutexGuard mutexGuard(logMutex);
00217 BOOST_MESSAGE("completed " << nRandomOps << " random scratch ops");
00218 }
00219
00220 void PagingTestBase::testPrefetch()
00221 {
00222
00223 uint n = 3;
00224 for (uint i = 0; i < n; i++) {
00225 uint iPage = generateRandomNumber(nDiskPages);
00226 prefetchPage(iPage);
00227 }
00228
00229 snooze(1);
00230 StrictMutexGuard mutexGuard(logMutex);
00231 BOOST_MESSAGE("completed " << n << " random prefetch ops");
00232 }
00233
00234 void PagingTestBase::testPrefetchBatch()
00235 {
00236
00237 uint n = 2;
00238 uint nPagesPerBatch = 4;
00239 for (uint i = 0; i < n; i++) {
00240 uint iPage = generateRandomNumber(nDiskPages - nPagesPerBatch);
00241 prefetchBatch(iPage,nPagesPerBatch);
00242 }
00243
00244 snooze(1);
00245 StrictMutexGuard mutexGuard(logMutex);
00246 BOOST_MESSAGE("completed " << n << " random prefetch batch ops");
00247 }
00248
00249 void PagingTestBase::testAllocateAll()
00250 {
00251 testSequentialOp(OP_ALLOCATE);
00252 }
00253
00254 void PagingTestBase::testSequentialRead()
00255 {
00256 testSequentialOp(OP_READ_SEQ);
00257 }
00258
00259 void PagingTestBase::testSequentialWrite()
00260 {
00261 testSequentialOp(OP_WRITE_SEQ);
00262 }
00263
00264 void PagingTestBase::testRandomRead()
00265 {
00266 testRandomOp(OP_READ_RAND);
00267 }
00268
00269 void PagingTestBase::testRandomWrite()
00270 {
00271 testRandomOp(OP_WRITE_RAND);
00272 }
00273
00274 void PagingTestBase::testSkipWrite(uint n)
00275 {
00276 testSkipOp(OP_WRITE_SKIP, n);
00277 }
00278
00279 void PagingTestBase::testAllocate()
00280 {
00281 permAssert(false);
00282 }
00283
00284 void PagingTestBase::testDeallocate()
00285 {
00286 permAssert(false);
00287 }
00288
00289 void PagingTestBase::testCheckpoint()
00290 {
00291 DeviceIdPagePredicate pagePredicate(dataDeviceId);
00292 getCache().checkpointPages(pagePredicate,CHECKPOINT_FLUSH_ALL);
00293 }
00294
00295 void PagingTestBase::testCheckpointGuarded()
00296 {
00297 snooze(nSecondsBetweenCheckpoints);
00298 StrictMutexGuard logGuard(logMutex);
00299 BOOST_MESSAGE("checkpoint started");
00300 logGuard.unlock();
00301 SXMutexExclusiveGuard checkpointExclusiveGuard(checkpointMutex);
00302 testCheckpoint();
00303 checkpointExclusiveGuard.unlock();
00304 logGuard.lock();
00305 BOOST_MESSAGE("checkpoint completed");
00306 }
00307
00308 void PagingTestBase::testCacheResize()
00309 {
00310 snooze(nSeconds / 3);
00311 getCache().setAllocatedPageCount(nMemPages / 2);
00312 StrictMutexGuard mutexGuard(logMutex);
00313 BOOST_MESSAGE("shrank cache");
00314 mutexGuard.unlock();
00315 snooze(nSeconds / 3);
00316 getCache().setAllocatedPageCount(nMemPages - 1);
00317 mutexGuard.lock();
00318 BOOST_MESSAGE("expanded cache");
00319 mutexGuard.unlock();
00320 }
00321
00322 PagingTestBase::PagingTestBase()
00323 {
00324 nRandomOps = configMap.getIntParam("randomOps",5000);
00325 nSecondsBetweenCheckpoints = configMap.getIntParam("checkpointInterval",20);
00326 bTestResize = configMap.getIntParam("resizeCache",1);
00327 checkpointMutex.setSchedulingPolicy(SXMutex::SCHEDULE_FAVOR_EXCLUSIVE);
00328
00329 threadCounts.resize(OP_MAX,-1);
00330
00331 threadCounts[OP_READ_SEQ] = configMap.getIntParam(
00332 "readSeqThreads",-1);
00333 threadCounts[OP_WRITE_SEQ] = configMap.getIntParam(
00334 "writeSeqThreads",-1);
00335 threadCounts[OP_READ_RAND] = configMap.getIntParam(
00336 "readRandThreads",-1);
00337 threadCounts[OP_WRITE_RAND] = configMap.getIntParam(
00338 "writeRandThreads",-1);
00339 threadCounts[OP_READ_NOWAIT] = configMap.getIntParam(
00340 "readNoWaitThreads",-1);
00341 threadCounts[OP_WRITE_NOWAIT] = configMap.getIntParam(
00342 "writeNoWaitThreads",-1);
00343 threadCounts[OP_WRITE_SKIP] = configMap.getIntParam(
00344 "writeSkipThreads",-1);
00345 threadCounts[OP_SCRATCH] = configMap.getIntParam(
00346 "scratchThreads",-1);
00347 threadCounts[OP_PREFETCH] = configMap.getIntParam(
00348 "prefetchThreads",-1);
00349 threadCounts[OP_PREFETCH_BATCH] = configMap.getIntParam(
00350 "prefetchBatchThreads",-1);
00351 threadCounts[OP_ALLOCATE] = configMap.getIntParam(
00352 "allocateThreads",-1);
00353 threadCounts[OP_DEALLOCATE] = configMap.getIntParam(
00354 "deallocateThreads",-1);
00355
00356 if (nSecondsBetweenCheckpoints < nSeconds) {
00357 threadCounts[OP_CHECKPOINT] = 1;
00358 } else {
00359 threadCounts[OP_CHECKPOINT] = 0;
00360 }
00361
00362 if (bTestResize) {
00363 threadCounts[OP_RESIZE_CACHE] = 1;
00364 } else {
00365 threadCounts[OP_RESIZE_CACHE] = 0;
00366 }
00367
00368 cbPageUsable = 0;
00369
00370 threadInit();
00371 }
00372
00373 PagingTestBase::~PagingTestBase()
00374 {
00375 threadTerminate();
00376 }
00377
00378 bool PagingTestBase::testThreadedOp(int iOp)
00379 {
00380 SXMutexSharedGuard checkpointSharedGuard(checkpointMutex,false);
00381 assert(iOp < OP_MAX);
00382 OpType op = static_cast<OpType>(iOp);
00383 switch (op) {
00384 case PagingTestBase::OP_WRITE_SEQ:
00385 checkpointSharedGuard.lock();
00386
00387 case PagingTestBase::OP_READ_SEQ:
00388 testSequentialOp(op);
00389 break;
00390 case PagingTestBase::OP_WRITE_RAND:
00391 case PagingTestBase::OP_WRITE_NOWAIT:
00392 checkpointSharedGuard.lock();
00393
00394 case PagingTestBase::OP_READ_RAND:
00395 case PagingTestBase::OP_READ_NOWAIT:
00396 testRandomOp(op);
00397 break;
00398 case PagingTestBase::OP_WRITE_SKIP:
00399 checkpointSharedGuard.lock();
00400 testSkipOp(op, 5);
00401 break;
00402 case PagingTestBase::OP_SCRATCH:
00403 testScratch();
00404 break;
00405 case PagingTestBase::OP_PREFETCH:
00406 testPrefetch();
00407 break;
00408 case PagingTestBase::OP_PREFETCH_BATCH:
00409 testPrefetchBatch();
00410 break;
00411 case PagingTestBase::OP_ALLOCATE:
00412 checkpointSharedGuard.lock();
00413 testAllocate();
00414 break;
00415 case PagingTestBase::OP_DEALLOCATE:
00416 checkpointSharedGuard.lock();
00417 testDeallocate();
00418 break;
00419 case PagingTestBase::OP_CHECKPOINT:
00420 testCheckpointGuarded();
00421 break;
00422 case PagingTestBase::OP_RESIZE_CACHE:
00423 testCacheResize();
00424 return false;
00425 default:
00426 permAssert(false);
00427 }
00428 return true;
00429 }
00430
00431 void PagingTestBase::testMultipleThreads()
00432 {
00433 openStorage(DeviceMode::createNew);
00434 testAllocateAll();
00435 runThreadedTestCase();
00436 }
00437
00438