#include <math.h>
#include <string.h>
#include <BlockCache.h>
#include <List.h>
#include <TestSuiteAddon.h>
#include <ThreadedTestCaller.h>
#include <ThreadedTestCase.h>
#include <cppunit/TestFixture.h>
#include <cppunit/TestSuite.h>
#include <cppunit/extensions/HelperMacros.h>
class BlockCacheConcurrencyTest : public BThreadedTestCase {
private:
BBlockCache *theObjCache;
BBlockCache *theMallocCache;
int numBlocksInCache;
size_t sizeOfBlocksInCache;
size_t sizeOfNonCacheBlocks;
void *GetBlock(BBlockCache *theCache, size_t blockSize,
thread_id theThread, BList *cacheList, BList *nonCacheList);
void SaveBlock(BBlockCache *theCache, void *, size_t blockSize,
thread_id theThread, BList *cacheList, BList *nonCacheList);
void FreeBlock(void *, size_t blockSize, bool isMallocTest,
thread_id theThread, BList *cacheList,
BList *nonCacheList);
void TestBlockCache(BBlockCache *theCache, bool isMallocTest);
public:
static CppUnit::Test *suite(void);
void TestThreadObj(void);
void TestThreadMalloc(void);
virtual void setUp(void);
virtual void tearDown(void);
BlockCacheConcurrencyTest(std::string);
virtual ~BlockCacheConcurrencyTest();
};
BlockCacheConcurrencyTest::BlockCacheConcurrencyTest(std::string name)
:
BThreadedTestCase(name),
theObjCache(NULL),
theMallocCache(NULL),
numBlocksInCache(128),
sizeOfBlocksInCache(23),
sizeOfNonCacheBlocks(29)
{
}
BlockCacheConcurrencyTest::~BlockCacheConcurrencyTest()
{
}
void
BlockCacheConcurrencyTest::setUp()
{
theObjCache = new BBlockCache(numBlocksInCache, sizeOfBlocksInCache, B_OBJECT_CACHE);
theMallocCache = new BBlockCache(numBlocksInCache, sizeOfBlocksInCache, B_MALLOC_CACHE);
}
void
BlockCacheConcurrencyTest::tearDown()
{
delete theObjCache;
delete theMallocCache;
}
void*
BlockCacheConcurrencyTest::GetBlock(BBlockCache* theCache, size_t blockSize, thread_id theThread,
BList* cacheList, BList* nonCacheList)
{
void* thePtr = theCache->Get(blockSize);
CPPUNIT_ASSERT(!cacheList->HasItem(thePtr));
CPPUNIT_ASSERT(!nonCacheList->HasItem(thePtr));
if (blockSize == sizeOfBlocksInCache)
CPPUNIT_ASSERT(cacheList->AddItem(thePtr));
else
CPPUNIT_ASSERT(nonCacheList->AddItem(thePtr));
*((thread_id*)thePtr) = theThread;
return thePtr;
}
void
BlockCacheConcurrencyTest::SaveBlock(BBlockCache* theCache, void* thePtr, size_t blockSize,
thread_id theThread, BList* cacheList, BList* nonCacheList)
{
CPPUNIT_ASSERT(*((thread_id*)thePtr) == theThread);
if (blockSize == sizeOfBlocksInCache) {
CPPUNIT_ASSERT(cacheList->RemoveItem(thePtr));
CPPUNIT_ASSERT(!nonCacheList->HasItem(thePtr));
} else {
CPPUNIT_ASSERT(!cacheList->HasItem(thePtr));
CPPUNIT_ASSERT(nonCacheList->RemoveItem(thePtr));
}
theCache->Save(thePtr, blockSize);
}
void
BlockCacheConcurrencyTest::FreeBlock(void* thePtr, size_t blockSize, bool isMallocTest,
thread_id theThread, BList* cacheList, BList* nonCacheList)
{
CPPUNIT_ASSERT(*((thread_id*)thePtr) == theThread);
if (blockSize == sizeOfBlocksInCache) {
CPPUNIT_ASSERT(cacheList->RemoveItem(thePtr));
CPPUNIT_ASSERT(!nonCacheList->HasItem(thePtr));
} else {
CPPUNIT_ASSERT(!cacheList->HasItem(thePtr));
CPPUNIT_ASSERT(nonCacheList->RemoveItem(thePtr));
}
if (isMallocTest)
free(thePtr);
else
delete[] (uint8*)thePtr;
}
void
BlockCacheConcurrencyTest::TestBlockCache(BBlockCache* theCache, bool isMallocTest)
{
BList cacheList;
BList nonCacheList;
thread_id theThread = find_thread(NULL);
for (int j = 0; j < 8; j++) {
for (int i = 0; i < numBlocksInCache / 2; i++) {
GetBlock(theCache, sizeOfBlocksInCache, theThread, &cacheList, &nonCacheList);
GetBlock(theCache, sizeOfBlocksInCache, theThread, &cacheList, &nonCacheList);
GetBlock(theCache, sizeOfNonCacheBlocks, theThread, &cacheList, &nonCacheList);
GetBlock(theCache, sizeOfNonCacheBlocks, theThread, &cacheList, &nonCacheList);
SaveBlock(theCache, cacheList.ItemAt(cacheList.CountItems() / 2), sizeOfBlocksInCache,
theThread, &cacheList, &nonCacheList);
SaveBlock(theCache, nonCacheList.ItemAt(nonCacheList.CountItems() / 2),
sizeOfNonCacheBlocks, theThread, &cacheList, &nonCacheList);
GetBlock(theCache, sizeOfBlocksInCache, theThread, &cacheList, &nonCacheList);
GetBlock(theCache, sizeOfBlocksInCache, theThread, &cacheList, &nonCacheList);
GetBlock(theCache, sizeOfNonCacheBlocks, theThread, &cacheList, &nonCacheList);
GetBlock(theCache, sizeOfNonCacheBlocks, theThread, &cacheList, &nonCacheList);
FreeBlock(cacheList.ItemAt(cacheList.CountItems() / 2), sizeOfBlocksInCache,
isMallocTest, theThread, &cacheList, &nonCacheList);
FreeBlock(nonCacheList.ItemAt(nonCacheList.CountItems() / 2), sizeOfNonCacheBlocks,
isMallocTest, theThread, &cacheList, &nonCacheList);
}
bool performFree = false;
while (!cacheList.IsEmpty()) {
if (performFree) {
FreeBlock(cacheList.LastItem(), sizeOfBlocksInCache, isMallocTest, theThread,
&cacheList, &nonCacheList);
} else {
SaveBlock(theCache, cacheList.LastItem(), sizeOfBlocksInCache, theThread,
&cacheList, &nonCacheList);
}
performFree = !performFree;
}
while (!nonCacheList.IsEmpty()) {
if (performFree) {
FreeBlock(nonCacheList.LastItem(), sizeOfNonCacheBlocks, isMallocTest, theThread,
&cacheList, &nonCacheList);
} else {
SaveBlock(theCache, nonCacheList.LastItem(), sizeOfNonCacheBlocks, theThread,
&cacheList, &nonCacheList);
}
performFree = !performFree;
}
}
}
void
BlockCacheConcurrencyTest::TestThreadMalloc()
{
TestBlockCache(theMallocCache, true);
}
void
BlockCacheConcurrencyTest::TestThreadObj()
{
TestBlockCache(theObjCache, false);
}
CppUnit::Test*
BlockCacheConcurrencyTest::suite()
{
typedef BThreadedTestCaller<BlockCacheConcurrencyTest> BlockCacheConcurrencyTestCaller;
BlockCacheConcurrencyTest* theTest = new BlockCacheConcurrencyTest("");
BlockCacheConcurrencyTestCaller* threadedTest
= new BlockCacheConcurrencyTestCaller("BBlockCache::Concurrency Test", theTest);
threadedTest->addThread("A", &BlockCacheConcurrencyTest::TestThreadObj);
threadedTest->addThread("B", &BlockCacheConcurrencyTest::TestThreadObj);
threadedTest->addThread("C", &BlockCacheConcurrencyTest::TestThreadObj);
threadedTest->addThread("D", &BlockCacheConcurrencyTest::TestThreadMalloc);
threadedTest->addThread("E", &BlockCacheConcurrencyTest::TestThreadMalloc);
threadedTest->addThread("F", &BlockCacheConcurrencyTest::TestThreadMalloc);
return threadedTest;
}
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(BlockCacheConcurrencyTest, getTestSuiteName());