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