2 This file tests BBlockCache from multiple threads to ensure there are
3 no concurrency problems.
7 #include "BlockCacheConcurrencyTest.h"
11 #include <BlockCache.h>
14 #include "ThreadedTestCaller.h"
18 * Method: BlockCacheConcurrencyTest::BlockCacheConcurrencyTest()
19 * Descr: This method is the only constructor for the BlockCacheConcurrencyTest
22 BlockCacheConcurrencyTest::BlockCacheConcurrencyTest(std::string name
)
24 BThreadedTestCase(name
),
27 numBlocksInCache(128),
28 sizeOfBlocksInCache(23),
29 sizeOfNonCacheBlocks(29)
35 * Method: BlockCacheConcurrencyTest::~BlockCacheConcurrencyTest()
36 * Descr: This method is the destructor for the BlockCacheConcurrencyTest class.
38 BlockCacheConcurrencyTest::~BlockCacheConcurrencyTest()
44 * Method: BlockCacheConcurrencyTest::setUp()
45 * Descr: This method creates a couple of BBlockCache instances to perform
46 * tests on. One uses new/delete and the other uses malloc/free
50 BlockCacheConcurrencyTest::setUp()
52 theObjCache
= new BBlockCache(numBlocksInCache
, sizeOfBlocksInCache
,
54 theMallocCache
= new BBlockCache(numBlocksInCache
, sizeOfBlocksInCache
,
60 * Method: BlockCacheConcurrencyTest::tearDown()
61 * Descr: This method cleans up the BBlockCache instances which were tested.
64 BlockCacheConcurrencyTest::tearDown()
67 delete theMallocCache
;
72 * Method: BlockCacheConcurrencyTest::GetBlock()
73 * Descr: This method returns a pointer from the BBlockCache, checking
74 * the value before passing it to the caller.
77 BlockCacheConcurrencyTest::GetBlock(BBlockCache
*theCache
, size_t blockSize
,
78 thread_id theThread
, BList
*cacheList
, BList
*nonCacheList
)
80 void *thePtr
= theCache
->Get(blockSize
);
82 // The new block should not already be used by this thread.
83 CPPUNIT_ASSERT(!cacheList
->HasItem(thePtr
));
84 CPPUNIT_ASSERT(!nonCacheList
->HasItem(thePtr
));
86 // Add the block to the list of blocks used by this thread.
87 if (blockSize
== sizeOfBlocksInCache
) {
88 CPPUNIT_ASSERT(cacheList
->AddItem(thePtr
));
90 CPPUNIT_ASSERT(nonCacheList
->AddItem(thePtr
));
93 // Store the thread id at the start of the block for future
95 *((thread_id
*)thePtr
) = theThread
;
101 * Method: BlockCacheConcurrencyTest::SavedCacheBlock()
102 * Descr: This method passes the pointer back to the BBlockCache
103 * and checks the sanity of the lists.
106 BlockCacheConcurrencyTest::SaveBlock(BBlockCache
*theCache
, void *thePtr
,
107 size_t blockSize
, thread_id theThread
, BList
*cacheList
,
110 // The block being returned to the cache should still have
111 // the thread id of this thread in it, or some other thread has
112 // perhaps manipulated this block which would indicate a
113 // concurrency problem.
114 CPPUNIT_ASSERT(*((thread_id
*)thePtr
) == theThread
);
116 // Remove the item from the appropriate list and confirm it isn't
117 // on the other list for some reason.
118 if (blockSize
== sizeOfBlocksInCache
) {
119 CPPUNIT_ASSERT(cacheList
->RemoveItem(thePtr
));
120 CPPUNIT_ASSERT(!nonCacheList
->HasItem(thePtr
));
122 CPPUNIT_ASSERT(!cacheList
->HasItem(thePtr
));
123 CPPUNIT_ASSERT(nonCacheList
->RemoveItem(thePtr
));
125 theCache
->Save(thePtr
, blockSize
);
130 * Method: BlockCacheConcurrencyTest::FreeBlock()
131 * Descr: This method frees the block directly using delete[] or free(),
132 * checking the sanity of the lists as it does the operation.
135 BlockCacheConcurrencyTest::FreeBlock(void *thePtr
, size_t blockSize
,
136 bool isMallocTest
, thread_id theThread
, BList
*cacheList
,
139 // The block being returned to the cache should still have
140 // the thread id of this thread in it, or some other thread has
141 // perhaps manipulated this block which would indicate a
142 // concurrency problem.
143 CPPUNIT_ASSERT(*((thread_id
*)thePtr
) == theThread
);
145 // Remove the item from the appropriate list and confirm it isn't
146 // on the other list for some reason.
147 if (blockSize
== sizeOfBlocksInCache
) {
148 CPPUNIT_ASSERT(cacheList
->RemoveItem(thePtr
));
149 CPPUNIT_ASSERT(!nonCacheList
->HasItem(thePtr
));
151 CPPUNIT_ASSERT(!cacheList
->HasItem(thePtr
));
152 CPPUNIT_ASSERT(nonCacheList
->RemoveItem(thePtr
));
157 delete[] (uint8
*)thePtr
;
163 * Method: BlockCacheConcurrencyTest::TestBlockCache()
164 * Descr: This method performs the tests on BBlockCache. It is
165 * called by 6 threads concurrently. Three of them are
166 * operating on the B_OBJECT_CACHE instance of BBlockCache
167 * and the other three are operating on the B_MALLOC_CACHE
170 * The goal of this method is to perform a series of get,
171 * save and free operations on block from the cache using
172 * "cache size" and "non-cache size" blocks. Also, at the
173 * end of this method, all blocks unfreed by this method are
174 * freed to avoid a memory leak.
177 BlockCacheConcurrencyTest::TestBlockCache(BBlockCache
*theCache
,
182 thread_id theThread
= find_thread(NULL
);
184 // Do everything eight times to ensure the test runs long
185 // enough to check for concurrency problems.
186 for (int j
= 0; j
< 8; j
++) {
187 // Perform a series of gets, saves and frees
188 for (int i
= 0; i
< numBlocksInCache
/ 2; i
++) {
189 GetBlock(theCache
, sizeOfBlocksInCache
, theThread
, &cacheList
, &nonCacheList
);
190 GetBlock(theCache
, sizeOfBlocksInCache
, theThread
, &cacheList
, &nonCacheList
);
191 GetBlock(theCache
, sizeOfNonCacheBlocks
, theThread
, &cacheList
, &nonCacheList
);
192 GetBlock(theCache
, sizeOfNonCacheBlocks
, theThread
, &cacheList
, &nonCacheList
);
194 SaveBlock(theCache
, cacheList
.ItemAt(cacheList
.CountItems() / 2),
195 sizeOfBlocksInCache
, theThread
, &cacheList
, &nonCacheList
);
196 SaveBlock(theCache
, nonCacheList
.ItemAt(nonCacheList
.CountItems() / 2),
197 sizeOfNonCacheBlocks
, theThread
, &cacheList
, &nonCacheList
);
199 GetBlock(theCache
, sizeOfBlocksInCache
, theThread
, &cacheList
, &nonCacheList
);
200 GetBlock(theCache
, sizeOfBlocksInCache
, theThread
, &cacheList
, &nonCacheList
);
201 GetBlock(theCache
, sizeOfNonCacheBlocks
, theThread
, &cacheList
, &nonCacheList
);
202 GetBlock(theCache
, sizeOfNonCacheBlocks
, theThread
, &cacheList
, &nonCacheList
);
204 FreeBlock(cacheList
.ItemAt(cacheList
.CountItems() / 2),
205 sizeOfBlocksInCache
, isMallocTest
, theThread
, &cacheList
, &nonCacheList
);
206 FreeBlock(nonCacheList
.ItemAt(nonCacheList
.CountItems() / 2),
207 sizeOfNonCacheBlocks
, isMallocTest
, theThread
, &cacheList
, &nonCacheList
);
209 bool performFree
= false;
210 // Free or save (every other block) for all "cache sized" blocks.
211 while (!cacheList
.IsEmpty()) {
213 FreeBlock(cacheList
.LastItem(), sizeOfBlocksInCache
, isMallocTest
, theThread
, &cacheList
,
216 SaveBlock(theCache
, cacheList
.LastItem(), sizeOfBlocksInCache
, theThread
, &cacheList
,
219 performFree
= !performFree
;
221 // Free or save (every other block) for all "non-cache sized" blocks.
222 while (!nonCacheList
.IsEmpty()) {
224 FreeBlock(nonCacheList
.LastItem(), sizeOfNonCacheBlocks
, isMallocTest
, theThread
, &cacheList
,
227 SaveBlock(theCache
, nonCacheList
.LastItem(), sizeOfNonCacheBlocks
, theThread
, &cacheList
,
230 performFree
= !performFree
;
237 * Method: BlockCacheConcurrencyTest::TestThreadMalloc()
238 * Descr: This method passes the BBlockCache instance to TestBlockCache()
239 * where the instance will be tested.
242 BlockCacheConcurrencyTest::TestThreadMalloc()
244 TestBlockCache(theMallocCache
, true);
249 * Method: BlockCacheConcurrencyTest::TestThreadObj()
250 * Descr: This method passes the BBlockCache instance to TestBlockCache()
251 * where the instance will be tested.
254 BlockCacheConcurrencyTest::TestThreadObj()
256 TestBlockCache(theObjCache
, false);
261 * Method: BlockCacheConcurrencyTest::suite()
262 * Descr: This static member function returns a test caller for performing
263 * the "BlockCacheConcurrencyTest" test. The test caller
264 * is created as a ThreadedTestCaller with six independent threads.
266 CppUnit::Test
*BlockCacheConcurrencyTest::suite()
268 typedef BThreadedTestCaller
<BlockCacheConcurrencyTest
>
269 BlockCacheConcurrencyTestCaller
;
271 BlockCacheConcurrencyTest
*theTest
= new BlockCacheConcurrencyTest("");
272 BlockCacheConcurrencyTestCaller
*threadedTest
= new BlockCacheConcurrencyTestCaller("BBlockCache::Concurrency Test", theTest
);
273 threadedTest
->addThread("A", &BlockCacheConcurrencyTest::TestThreadObj
);
274 threadedTest
->addThread("B", &BlockCacheConcurrencyTest::TestThreadObj
);
275 threadedTest
->addThread("C", &BlockCacheConcurrencyTest::TestThreadObj
);
276 threadedTest
->addThread("D", &BlockCacheConcurrencyTest::TestThreadMalloc
);
277 threadedTest
->addThread("E", &BlockCacheConcurrencyTest::TestThreadMalloc
);
278 threadedTest
->addThread("F", &BlockCacheConcurrencyTest::TestThreadMalloc
);
279 return(threadedTest
);