1*bfdb37ccSIngo Weinhold /* 2*bfdb37ccSIngo Weinhold $Id: BlockCacheConcurrencyTest.cpp,v 1.1 2003/09/07 11:53:03 bonefish Exp $ 3*bfdb37ccSIngo Weinhold 4*bfdb37ccSIngo Weinhold This file tests BBlockCache from multiple threads to ensure there are 5*bfdb37ccSIngo Weinhold no concurrency problems. 6*bfdb37ccSIngo Weinhold 7*bfdb37ccSIngo Weinhold */ 8*bfdb37ccSIngo Weinhold 9*bfdb37ccSIngo Weinhold 10*bfdb37ccSIngo Weinhold #include "BlockCacheConcurrencyTest.h" 11*bfdb37ccSIngo Weinhold #include "ThreadedTestCaller.h" 12*bfdb37ccSIngo Weinhold #include <BlockCache.h> 13*bfdb37ccSIngo Weinhold #include <List.h> 14*bfdb37ccSIngo Weinhold 15*bfdb37ccSIngo Weinhold 16*bfdb37ccSIngo Weinhold /* 17*bfdb37ccSIngo Weinhold * Method: BlockCacheConcurrencyTest::BlockCacheConcurrencyTest() 18*bfdb37ccSIngo Weinhold * Descr: This method is the only constructor for the BlockCacheConcurrencyTest 19*bfdb37ccSIngo Weinhold * class. 20*bfdb37ccSIngo Weinhold */ 21*bfdb37ccSIngo Weinhold 22*bfdb37ccSIngo Weinhold 23*bfdb37ccSIngo Weinhold BlockCacheConcurrencyTest::BlockCacheConcurrencyTest(std::string name) : 24*bfdb37ccSIngo Weinhold BThreadedTestCase(name), 25*bfdb37ccSIngo Weinhold theObjCache(NULL), 26*bfdb37ccSIngo Weinhold theMallocCache(NULL), 27*bfdb37ccSIngo Weinhold numBlocksInCache(128), 28*bfdb37ccSIngo Weinhold sizeOfBlocksInCache(23), 29*bfdb37ccSIngo Weinhold sizeOfNonCacheBlocks(29) 30*bfdb37ccSIngo Weinhold { 31*bfdb37ccSIngo Weinhold } 32*bfdb37ccSIngo Weinhold 33*bfdb37ccSIngo Weinhold 34*bfdb37ccSIngo Weinhold /* 35*bfdb37ccSIngo Weinhold * Method: BlockCacheConcurrencyTest::~BlockCacheConcurrencyTest() 36*bfdb37ccSIngo Weinhold * Descr: This method is the destructor for the BlockCacheConcurrencyTest class. 37*bfdb37ccSIngo Weinhold */ 38*bfdb37ccSIngo Weinhold 39*bfdb37ccSIngo Weinhold 40*bfdb37ccSIngo Weinhold BlockCacheConcurrencyTest::~BlockCacheConcurrencyTest() 41*bfdb37ccSIngo Weinhold { 42*bfdb37ccSIngo Weinhold } 43*bfdb37ccSIngo Weinhold 44*bfdb37ccSIngo Weinhold 45*bfdb37ccSIngo Weinhold /* 46*bfdb37ccSIngo Weinhold * Method: BlockCacheConcurrencyTest::setUp() 47*bfdb37ccSIngo Weinhold * Descr: This method creates a couple of BBlockCache instances to perform 48*bfdb37ccSIngo Weinhold * tests on. One uses new/delete and the other uses malloc/free 49*bfdb37ccSIngo Weinhold * on its blocks. 50*bfdb37ccSIngo Weinhold */ 51*bfdb37ccSIngo Weinhold 52*bfdb37ccSIngo Weinhold 53*bfdb37ccSIngo Weinhold void BlockCacheConcurrencyTest::setUp(void) 54*bfdb37ccSIngo Weinhold { 55*bfdb37ccSIngo Weinhold theObjCache = new BBlockCache(numBlocksInCache, sizeOfBlocksInCache, 56*bfdb37ccSIngo Weinhold B_OBJECT_CACHE); 57*bfdb37ccSIngo Weinhold theMallocCache = new BBlockCache(numBlocksInCache, sizeOfBlocksInCache, 58*bfdb37ccSIngo Weinhold B_MALLOC_CACHE); 59*bfdb37ccSIngo Weinhold } 60*bfdb37ccSIngo Weinhold 61*bfdb37ccSIngo Weinhold 62*bfdb37ccSIngo Weinhold /* 63*bfdb37ccSIngo Weinhold * Method: BlockCacheConcurrencyTest::tearDown() 64*bfdb37ccSIngo Weinhold * Descr: This method cleans up the BBlockCache instances which were tested. 65*bfdb37ccSIngo Weinhold */ 66*bfdb37ccSIngo Weinhold 67*bfdb37ccSIngo Weinhold 68*bfdb37ccSIngo Weinhold void BlockCacheConcurrencyTest::tearDown(void) 69*bfdb37ccSIngo Weinhold { 70*bfdb37ccSIngo Weinhold delete theObjCache; 71*bfdb37ccSIngo Weinhold delete theMallocCache; 72*bfdb37ccSIngo Weinhold } 73*bfdb37ccSIngo Weinhold 74*bfdb37ccSIngo Weinhold 75*bfdb37ccSIngo Weinhold /* 76*bfdb37ccSIngo Weinhold * Method: BlockCacheConcurrencyTest::GetBlock() 77*bfdb37ccSIngo Weinhold * Descr: This method returns a pointer from the BBlockCache, checking 78*bfdb37ccSIngo Weinhold * the value before passing it to the caller. 79*bfdb37ccSIngo Weinhold */ 80*bfdb37ccSIngo Weinhold 81*bfdb37ccSIngo Weinhold 82*bfdb37ccSIngo Weinhold void *BlockCacheConcurrencyTest::GetBlock(BBlockCache *theCache, 83*bfdb37ccSIngo Weinhold size_t blockSize, 84*bfdb37ccSIngo Weinhold thread_id theThread, 85*bfdb37ccSIngo Weinhold BList *cacheList, 86*bfdb37ccSIngo Weinhold BList *nonCacheList) 87*bfdb37ccSIngo Weinhold { 88*bfdb37ccSIngo Weinhold void *thePtr = theCache->Get(blockSize); 89*bfdb37ccSIngo Weinhold 90*bfdb37ccSIngo Weinhold // The new block should not already be used by this thread. 91*bfdb37ccSIngo Weinhold assert(!cacheList->HasItem(thePtr)); 92*bfdb37ccSIngo Weinhold assert(!nonCacheList->HasItem(thePtr)); 93*bfdb37ccSIngo Weinhold 94*bfdb37ccSIngo Weinhold // Add the block to the list of blocks used by this thread. 95*bfdb37ccSIngo Weinhold if (blockSize == sizeOfBlocksInCache) { 96*bfdb37ccSIngo Weinhold assert(cacheList->AddItem(thePtr)); 97*bfdb37ccSIngo Weinhold } else { 98*bfdb37ccSIngo Weinhold assert(nonCacheList->AddItem(thePtr)); 99*bfdb37ccSIngo Weinhold } 100*bfdb37ccSIngo Weinhold 101*bfdb37ccSIngo Weinhold // Store the thread id at the start of the block for future 102*bfdb37ccSIngo Weinhold // reference. 103*bfdb37ccSIngo Weinhold *((thread_id *)thePtr) = theThread; 104*bfdb37ccSIngo Weinhold return(thePtr); 105*bfdb37ccSIngo Weinhold } 106*bfdb37ccSIngo Weinhold 107*bfdb37ccSIngo Weinhold 108*bfdb37ccSIngo Weinhold /* 109*bfdb37ccSIngo Weinhold * Method: BlockCacheConcurrencyTest::SavedCacheBlock() 110*bfdb37ccSIngo Weinhold * Descr: This method passes the pointer back to the BBlockCache 111*bfdb37ccSIngo Weinhold * and checks the sanity of the lists. 112*bfdb37ccSIngo Weinhold */ 113*bfdb37ccSIngo Weinhold 114*bfdb37ccSIngo Weinhold 115*bfdb37ccSIngo Weinhold void BlockCacheConcurrencyTest::SaveBlock(BBlockCache *theCache, 116*bfdb37ccSIngo Weinhold void *thePtr, 117*bfdb37ccSIngo Weinhold size_t blockSize, 118*bfdb37ccSIngo Weinhold thread_id theThread, 119*bfdb37ccSIngo Weinhold BList *cacheList, 120*bfdb37ccSIngo Weinhold BList *nonCacheList) 121*bfdb37ccSIngo Weinhold { 122*bfdb37ccSIngo Weinhold // The block being returned to the cache should still have 123*bfdb37ccSIngo Weinhold // the thread id of this thread in it, or some other thread has 124*bfdb37ccSIngo Weinhold // perhaps manipulated this block which would indicate a 125*bfdb37ccSIngo Weinhold // concurrency problem. 126*bfdb37ccSIngo Weinhold assert(*((thread_id *)thePtr) == theThread); 127*bfdb37ccSIngo Weinhold 128*bfdb37ccSIngo Weinhold // Remove the item from the appropriate list and confirm it isn't 129*bfdb37ccSIngo Weinhold // on the other list for some reason. 130*bfdb37ccSIngo Weinhold if (blockSize == sizeOfBlocksInCache) { 131*bfdb37ccSIngo Weinhold assert(cacheList->RemoveItem(thePtr)); 132*bfdb37ccSIngo Weinhold assert(!nonCacheList->HasItem(thePtr)); 133*bfdb37ccSIngo Weinhold } else { 134*bfdb37ccSIngo Weinhold assert(!cacheList->HasItem(thePtr)); 135*bfdb37ccSIngo Weinhold assert(nonCacheList->RemoveItem(thePtr)); 136*bfdb37ccSIngo Weinhold } 137*bfdb37ccSIngo Weinhold theCache->Save(thePtr, blockSize); 138*bfdb37ccSIngo Weinhold } 139*bfdb37ccSIngo Weinhold 140*bfdb37ccSIngo Weinhold 141*bfdb37ccSIngo Weinhold /* 142*bfdb37ccSIngo Weinhold * Method: BlockCacheConcurrencyTest::FreeBlock() 143*bfdb37ccSIngo Weinhold * Descr: This method frees the block directly using delete[] or free(), 144*bfdb37ccSIngo Weinhold * checking the sanity of the lists as it does the operation. 145*bfdb37ccSIngo Weinhold */ 146*bfdb37ccSIngo Weinhold 147*bfdb37ccSIngo Weinhold 148*bfdb37ccSIngo Weinhold void BlockCacheConcurrencyTest::FreeBlock(void *thePtr, 149*bfdb37ccSIngo Weinhold size_t blockSize, 150*bfdb37ccSIngo Weinhold bool isMallocTest, 151*bfdb37ccSIngo Weinhold thread_id theThread, 152*bfdb37ccSIngo Weinhold BList *cacheList, 153*bfdb37ccSIngo Weinhold BList *nonCacheList) 154*bfdb37ccSIngo Weinhold { 155*bfdb37ccSIngo Weinhold // The block being returned to the cache should still have 156*bfdb37ccSIngo Weinhold // the thread id of this thread in it, or some other thread has 157*bfdb37ccSIngo Weinhold // perhaps manipulated this block which would indicate a 158*bfdb37ccSIngo Weinhold // concurrency problem. 159*bfdb37ccSIngo Weinhold assert(*((thread_id *)thePtr) == theThread); 160*bfdb37ccSIngo Weinhold 161*bfdb37ccSIngo Weinhold // Remove the item from the appropriate list and confirm it isn't 162*bfdb37ccSIngo Weinhold // on the other list for some reason. 163*bfdb37ccSIngo Weinhold if (blockSize == sizeOfBlocksInCache) { 164*bfdb37ccSIngo Weinhold assert(cacheList->RemoveItem(thePtr)); 165*bfdb37ccSIngo Weinhold assert(!nonCacheList->HasItem(thePtr)); 166*bfdb37ccSIngo Weinhold } else { 167*bfdb37ccSIngo Weinhold assert(!cacheList->HasItem(thePtr)); 168*bfdb37ccSIngo Weinhold assert(nonCacheList->RemoveItem(thePtr)); 169*bfdb37ccSIngo Weinhold } 170*bfdb37ccSIngo Weinhold if (isMallocTest) { 171*bfdb37ccSIngo Weinhold free(thePtr); 172*bfdb37ccSIngo Weinhold } else { 173*bfdb37ccSIngo Weinhold delete[] thePtr; 174*bfdb37ccSIngo Weinhold } 175*bfdb37ccSIngo Weinhold } 176*bfdb37ccSIngo Weinhold 177*bfdb37ccSIngo Weinhold 178*bfdb37ccSIngo Weinhold /* 179*bfdb37ccSIngo Weinhold * Method: BlockCacheConcurrencyTest::TestBlockCache() 180*bfdb37ccSIngo Weinhold * Descr: This method performs the tests on BBlockCache. It is 181*bfdb37ccSIngo Weinhold * called by 6 threads concurrently. Three of them are 182*bfdb37ccSIngo Weinhold * operating on the B_OBJECT_CACHE instance of BBlockCache 183*bfdb37ccSIngo Weinhold * and the other three are operating on the B_MALLOC_CACHE 184*bfdb37ccSIngo Weinhold * instance. 185*bfdb37ccSIngo Weinhold * 186*bfdb37ccSIngo Weinhold * The goal of this method is to perform a series of get, 187*bfdb37ccSIngo Weinhold * save and free operations on block from the cache using 188*bfdb37ccSIngo Weinhold * "cache size" and "non-cache size" blocks. Also, at the 189*bfdb37ccSIngo Weinhold * end of this method, all blocks unfreed by this method are 190*bfdb37ccSIngo Weinhold * freed to avoid a memory leak. 191*bfdb37ccSIngo Weinhold */ 192*bfdb37ccSIngo Weinhold 193*bfdb37ccSIngo Weinhold 194*bfdb37ccSIngo Weinhold void BlockCacheConcurrencyTest::TestBlockCache(BBlockCache *theCache, 195*bfdb37ccSIngo Weinhold bool isMallocTest) 196*bfdb37ccSIngo Weinhold { 197*bfdb37ccSIngo Weinhold BList cacheList; 198*bfdb37ccSIngo Weinhold BList nonCacheList; 199*bfdb37ccSIngo Weinhold thread_id theThread = find_thread(NULL); 200*bfdb37ccSIngo Weinhold 201*bfdb37ccSIngo Weinhold // Do everything eight times to ensure the test runs long 202*bfdb37ccSIngo Weinhold // enough to check for concurrency problems. 203*bfdb37ccSIngo Weinhold for (int j = 0; j < 8; j++) { 204*bfdb37ccSIngo Weinhold // Perform a series of gets, saves and frees 205*bfdb37ccSIngo Weinhold for (int i = 0; i < numBlocksInCache / 2; i++) { 206*bfdb37ccSIngo Weinhold GetBlock(theCache, sizeOfBlocksInCache, theThread, &cacheList, &nonCacheList); 207*bfdb37ccSIngo Weinhold GetBlock(theCache, sizeOfBlocksInCache, theThread, &cacheList, &nonCacheList); 208*bfdb37ccSIngo Weinhold GetBlock(theCache, sizeOfNonCacheBlocks, theThread, &cacheList, &nonCacheList); 209*bfdb37ccSIngo Weinhold GetBlock(theCache, sizeOfNonCacheBlocks, theThread, &cacheList, &nonCacheList); 210*bfdb37ccSIngo Weinhold 211*bfdb37ccSIngo Weinhold SaveBlock(theCache, cacheList.ItemAt(cacheList.CountItems() / 2), 212*bfdb37ccSIngo Weinhold sizeOfBlocksInCache, theThread, &cacheList, &nonCacheList); 213*bfdb37ccSIngo Weinhold SaveBlock(theCache, nonCacheList.ItemAt(nonCacheList.CountItems() / 2), 214*bfdb37ccSIngo Weinhold sizeOfNonCacheBlocks, theThread, &cacheList, &nonCacheList); 215*bfdb37ccSIngo Weinhold 216*bfdb37ccSIngo Weinhold GetBlock(theCache, sizeOfBlocksInCache, theThread, &cacheList, &nonCacheList); 217*bfdb37ccSIngo Weinhold GetBlock(theCache, sizeOfBlocksInCache, theThread, &cacheList, &nonCacheList); 218*bfdb37ccSIngo Weinhold GetBlock(theCache, sizeOfNonCacheBlocks, theThread, &cacheList, &nonCacheList); 219*bfdb37ccSIngo Weinhold GetBlock(theCache, sizeOfNonCacheBlocks, theThread, &cacheList, &nonCacheList); 220*bfdb37ccSIngo Weinhold 221*bfdb37ccSIngo Weinhold FreeBlock(cacheList.ItemAt(cacheList.CountItems() / 2), 222*bfdb37ccSIngo Weinhold sizeOfBlocksInCache, isMallocTest, theThread, &cacheList, &nonCacheList); 223*bfdb37ccSIngo Weinhold FreeBlock(nonCacheList.ItemAt(nonCacheList.CountItems() / 2), 224*bfdb37ccSIngo Weinhold sizeOfNonCacheBlocks, isMallocTest, theThread, &cacheList, &nonCacheList); 225*bfdb37ccSIngo Weinhold } 226*bfdb37ccSIngo Weinhold bool performFree = false; 227*bfdb37ccSIngo Weinhold // Free or save (every other block) for all "cache sized" blocks. 228*bfdb37ccSIngo Weinhold while (!cacheList.IsEmpty()) { 229*bfdb37ccSIngo Weinhold if (performFree) { 230*bfdb37ccSIngo Weinhold FreeBlock(cacheList.LastItem(), sizeOfBlocksInCache, isMallocTest, theThread, &cacheList, 231*bfdb37ccSIngo Weinhold &nonCacheList); 232*bfdb37ccSIngo Weinhold } else { 233*bfdb37ccSIngo Weinhold SaveBlock(theCache, cacheList.LastItem(), sizeOfBlocksInCache, theThread, &cacheList, 234*bfdb37ccSIngo Weinhold &nonCacheList); 235*bfdb37ccSIngo Weinhold } 236*bfdb37ccSIngo Weinhold performFree = !performFree; 237*bfdb37ccSIngo Weinhold } 238*bfdb37ccSIngo Weinhold // Free or save (every other block) for all "non-cache sized" blocks. 239*bfdb37ccSIngo Weinhold while (!nonCacheList.IsEmpty()) { 240*bfdb37ccSIngo Weinhold if (performFree) { 241*bfdb37ccSIngo Weinhold FreeBlock(nonCacheList.LastItem(), sizeOfNonCacheBlocks, isMallocTest, theThread, &cacheList, 242*bfdb37ccSIngo Weinhold &nonCacheList); 243*bfdb37ccSIngo Weinhold } else { 244*bfdb37ccSIngo Weinhold SaveBlock(theCache, nonCacheList.LastItem(), sizeOfNonCacheBlocks, theThread, &cacheList, 245*bfdb37ccSIngo Weinhold &nonCacheList); 246*bfdb37ccSIngo Weinhold } 247*bfdb37ccSIngo Weinhold performFree = !performFree; 248*bfdb37ccSIngo Weinhold } 249*bfdb37ccSIngo Weinhold } 250*bfdb37ccSIngo Weinhold } 251*bfdb37ccSIngo Weinhold 252*bfdb37ccSIngo Weinhold 253*bfdb37ccSIngo Weinhold /* 254*bfdb37ccSIngo Weinhold * Method: BlockCacheConcurrencyTest::TestThreadMalloc() 255*bfdb37ccSIngo Weinhold * Descr: This method passes the BBlockCache instance to TestBlockCache() 256*bfdb37ccSIngo Weinhold * where the instance will be tested. 257*bfdb37ccSIngo Weinhold */ 258*bfdb37ccSIngo Weinhold 259*bfdb37ccSIngo Weinhold 260*bfdb37ccSIngo Weinhold void BlockCacheConcurrencyTest::TestThreadMalloc(void) 261*bfdb37ccSIngo Weinhold { 262*bfdb37ccSIngo Weinhold TestBlockCache(theMallocCache, true); 263*bfdb37ccSIngo Weinhold } 264*bfdb37ccSIngo Weinhold 265*bfdb37ccSIngo Weinhold 266*bfdb37ccSIngo Weinhold /* 267*bfdb37ccSIngo Weinhold * Method: BlockCacheConcurrencyTest::TestThreadObj() 268*bfdb37ccSIngo Weinhold * Descr: This method passes the BBlockCache instance to TestBlockCache() 269*bfdb37ccSIngo Weinhold * where the instance will be tested. 270*bfdb37ccSIngo Weinhold */ 271*bfdb37ccSIngo Weinhold 272*bfdb37ccSIngo Weinhold 273*bfdb37ccSIngo Weinhold void BlockCacheConcurrencyTest::TestThreadObj(void) 274*bfdb37ccSIngo Weinhold { 275*bfdb37ccSIngo Weinhold TestBlockCache(theObjCache, false); 276*bfdb37ccSIngo Weinhold } 277*bfdb37ccSIngo Weinhold 278*bfdb37ccSIngo Weinhold 279*bfdb37ccSIngo Weinhold /* 280*bfdb37ccSIngo Weinhold * Method: BlockCacheConcurrencyTest::suite() 281*bfdb37ccSIngo Weinhold * Descr: This static member function returns a test caller for performing 282*bfdb37ccSIngo Weinhold * the "BlockCacheConcurrencyTest" test. The test caller 283*bfdb37ccSIngo Weinhold * is created as a ThreadedTestCaller with six independent threads. 284*bfdb37ccSIngo Weinhold */ 285*bfdb37ccSIngo Weinhold 286*bfdb37ccSIngo Weinhold 287*bfdb37ccSIngo Weinhold CppUnit::Test *BlockCacheConcurrencyTest::suite(void) 288*bfdb37ccSIngo Weinhold { 289*bfdb37ccSIngo Weinhold typedef BThreadedTestCaller <BlockCacheConcurrencyTest > 290*bfdb37ccSIngo Weinhold BlockCacheConcurrencyTestCaller; 291*bfdb37ccSIngo Weinhold 292*bfdb37ccSIngo Weinhold BlockCacheConcurrencyTest *theTest = new BlockCacheConcurrencyTest(""); 293*bfdb37ccSIngo Weinhold BlockCacheConcurrencyTestCaller *threadedTest = new BlockCacheConcurrencyTestCaller("BBlockCache::Concurrency Test", theTest); 294*bfdb37ccSIngo Weinhold threadedTest->addThread("A", &BlockCacheConcurrencyTest::TestThreadObj); 295*bfdb37ccSIngo Weinhold threadedTest->addThread("B", &BlockCacheConcurrencyTest::TestThreadObj); 296*bfdb37ccSIngo Weinhold threadedTest->addThread("C", &BlockCacheConcurrencyTest::TestThreadObj); 297*bfdb37ccSIngo Weinhold threadedTest->addThread("D", &BlockCacheConcurrencyTest::TestThreadMalloc); 298*bfdb37ccSIngo Weinhold threadedTest->addThread("E", &BlockCacheConcurrencyTest::TestThreadMalloc); 299*bfdb37ccSIngo Weinhold threadedTest->addThread("F", &BlockCacheConcurrencyTest::TestThreadMalloc); 300*bfdb37ccSIngo Weinhold return(threadedTest); 301*bfdb37ccSIngo Weinhold } 302