Check in per Jeremy Rand: Added BBlockCache unit tests.
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@4522 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -6,6 +6,7 @@ SEARCH_SOURCE += [ FDirName $(SUBDIR) bautolock ] ;
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) blocker ] ;
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) bmemoryio ] ;
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) bstring ] ;
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) bblockcache ] ;
|
||||
|
||||
CommonTestLib libsupporttest.so
|
||||
: SupportKitTestAddon.cpp
|
||||
@@ -66,6 +67,11 @@ CommonTestLib libsupporttest.so
|
||||
StringSearchTest.cpp
|
||||
StringReplaceTest.cpp
|
||||
|
||||
#BBlockCache
|
||||
BlockCacheTest.cpp
|
||||
BlockCacheExerciseTest.cpp
|
||||
BlockCacheConcurrencyTest.cpp
|
||||
|
||||
: <boot!home!config!lib>libopenbeos.so
|
||||
be stdc++.r4
|
||||
: be stdc++.r4
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "bmemoryio/MemoryIOTest.h"
|
||||
#include "bmemoryio/MallocIOTest.h"
|
||||
#include "bstring/StringTest.h"
|
||||
#include "bblockcache/BlockCacheTest.h"
|
||||
|
||||
BTestSuite* getTestSuite() {
|
||||
BTestSuite *suite = new BTestSuite("Support");
|
||||
@@ -19,6 +20,7 @@ BTestSuite* getTestSuite() {
|
||||
suite->addTest("BMemoryIO", MemoryIOTestSuite());
|
||||
suite->addTest("BMallocIO", MallocIOTestSuite());
|
||||
suite->addTest("BString", StringTestSuite());
|
||||
suite->addTest("BBlockCache", BlockCacheTestSuite());
|
||||
|
||||
return suite;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
$Id: BlockCacheConcurrencyTest.cpp,v 1.1 2003/09/07 11:53:03 bonefish Exp $
|
||||
|
||||
This file tests BBlockCache from multiple threads to ensure there are
|
||||
no concurrency problems.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "BlockCacheConcurrencyTest.h"
|
||||
#include "ThreadedTestCaller.h"
|
||||
#include <BlockCache.h>
|
||||
#include <List.h>
|
||||
|
||||
|
||||
/*
|
||||
* Method: BlockCacheConcurrencyTest::BlockCacheConcurrencyTest()
|
||||
* Descr: This method is the only constructor for the BlockCacheConcurrencyTest
|
||||
* class.
|
||||
*/
|
||||
|
||||
|
||||
BlockCacheConcurrencyTest::BlockCacheConcurrencyTest(std::string name) :
|
||||
BThreadedTestCase(name),
|
||||
theObjCache(NULL),
|
||||
theMallocCache(NULL),
|
||||
numBlocksInCache(128),
|
||||
sizeOfBlocksInCache(23),
|
||||
sizeOfNonCacheBlocks(29)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Method: BlockCacheConcurrencyTest::~BlockCacheConcurrencyTest()
|
||||
* Descr: This method is the destructor for the BlockCacheConcurrencyTest class.
|
||||
*/
|
||||
|
||||
|
||||
BlockCacheConcurrencyTest::~BlockCacheConcurrencyTest()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Method: BlockCacheConcurrencyTest::setUp()
|
||||
* Descr: This method creates a couple of BBlockCache instances to perform
|
||||
* tests on. One uses new/delete and the other uses malloc/free
|
||||
* on its blocks.
|
||||
*/
|
||||
|
||||
|
||||
void BlockCacheConcurrencyTest::setUp(void)
|
||||
{
|
||||
theObjCache = new BBlockCache(numBlocksInCache, sizeOfBlocksInCache,
|
||||
B_OBJECT_CACHE);
|
||||
theMallocCache = new BBlockCache(numBlocksInCache, sizeOfBlocksInCache,
|
||||
B_MALLOC_CACHE);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Method: BlockCacheConcurrencyTest::tearDown()
|
||||
* Descr: This method cleans up the BBlockCache instances which were tested.
|
||||
*/
|
||||
|
||||
|
||||
void BlockCacheConcurrencyTest::tearDown(void)
|
||||
{
|
||||
delete theObjCache;
|
||||
delete theMallocCache;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Method: BlockCacheConcurrencyTest::GetBlock()
|
||||
* Descr: This method returns a pointer from the BBlockCache, checking
|
||||
* the value before passing it to the caller.
|
||||
*/
|
||||
|
||||
|
||||
void *BlockCacheConcurrencyTest::GetBlock(BBlockCache *theCache,
|
||||
size_t blockSize,
|
||||
thread_id theThread,
|
||||
BList *cacheList,
|
||||
BList *nonCacheList)
|
||||
{
|
||||
void *thePtr = theCache->Get(blockSize);
|
||||
|
||||
// The new block should not already be used by this thread.
|
||||
assert(!cacheList->HasItem(thePtr));
|
||||
assert(!nonCacheList->HasItem(thePtr));
|
||||
|
||||
// Add the block to the list of blocks used by this thread.
|
||||
if (blockSize == sizeOfBlocksInCache) {
|
||||
assert(cacheList->AddItem(thePtr));
|
||||
} else {
|
||||
assert(nonCacheList->AddItem(thePtr));
|
||||
}
|
||||
|
||||
// Store the thread id at the start of the block for future
|
||||
// reference.
|
||||
*((thread_id *)thePtr) = theThread;
|
||||
return(thePtr);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Method: BlockCacheConcurrencyTest::SavedCacheBlock()
|
||||
* Descr: This method passes the pointer back to the BBlockCache
|
||||
* and checks the sanity of the lists.
|
||||
*/
|
||||
|
||||
|
||||
void BlockCacheConcurrencyTest::SaveBlock(BBlockCache *theCache,
|
||||
void *thePtr,
|
||||
size_t blockSize,
|
||||
thread_id theThread,
|
||||
BList *cacheList,
|
||||
BList *nonCacheList)
|
||||
{
|
||||
// The block being returned to the cache should still have
|
||||
// the thread id of this thread in it, or some other thread has
|
||||
// perhaps manipulated this block which would indicate a
|
||||
// concurrency problem.
|
||||
assert(*((thread_id *)thePtr) == theThread);
|
||||
|
||||
// Remove the item from the appropriate list and confirm it isn't
|
||||
// on the other list for some reason.
|
||||
if (blockSize == sizeOfBlocksInCache) {
|
||||
assert(cacheList->RemoveItem(thePtr));
|
||||
assert(!nonCacheList->HasItem(thePtr));
|
||||
} else {
|
||||
assert(!cacheList->HasItem(thePtr));
|
||||
assert(nonCacheList->RemoveItem(thePtr));
|
||||
}
|
||||
theCache->Save(thePtr, blockSize);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Method: BlockCacheConcurrencyTest::FreeBlock()
|
||||
* Descr: This method frees the block directly using delete[] or free(),
|
||||
* checking the sanity of the lists as it does the operation.
|
||||
*/
|
||||
|
||||
|
||||
void BlockCacheConcurrencyTest::FreeBlock(void *thePtr,
|
||||
size_t blockSize,
|
||||
bool isMallocTest,
|
||||
thread_id theThread,
|
||||
BList *cacheList,
|
||||
BList *nonCacheList)
|
||||
{
|
||||
// The block being returned to the cache should still have
|
||||
// the thread id of this thread in it, or some other thread has
|
||||
// perhaps manipulated this block which would indicate a
|
||||
// concurrency problem.
|
||||
assert(*((thread_id *)thePtr) == theThread);
|
||||
|
||||
// Remove the item from the appropriate list and confirm it isn't
|
||||
// on the other list for some reason.
|
||||
if (blockSize == sizeOfBlocksInCache) {
|
||||
assert(cacheList->RemoveItem(thePtr));
|
||||
assert(!nonCacheList->HasItem(thePtr));
|
||||
} else {
|
||||
assert(!cacheList->HasItem(thePtr));
|
||||
assert(nonCacheList->RemoveItem(thePtr));
|
||||
}
|
||||
if (isMallocTest) {
|
||||
free(thePtr);
|
||||
} else {
|
||||
delete[] thePtr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Method: BlockCacheConcurrencyTest::TestBlockCache()
|
||||
* Descr: This method performs the tests on BBlockCache. It is
|
||||
* called by 6 threads concurrently. Three of them are
|
||||
* operating on the B_OBJECT_CACHE instance of BBlockCache
|
||||
* and the other three are operating on the B_MALLOC_CACHE
|
||||
* instance.
|
||||
*
|
||||
* The goal of this method is to perform a series of get,
|
||||
* save and free operations on block from the cache using
|
||||
* "cache size" and "non-cache size" blocks. Also, at the
|
||||
* end of this method, all blocks unfreed by this method are
|
||||
* freed to avoid a memory leak.
|
||||
*/
|
||||
|
||||
|
||||
void BlockCacheConcurrencyTest::TestBlockCache(BBlockCache *theCache,
|
||||
bool isMallocTest)
|
||||
{
|
||||
BList cacheList;
|
||||
BList nonCacheList;
|
||||
thread_id theThread = find_thread(NULL);
|
||||
|
||||
// Do everything eight times to ensure the test runs long
|
||||
// enough to check for concurrency problems.
|
||||
for (int j = 0; j < 8; j++) {
|
||||
// Perform a series of gets, saves and frees
|
||||
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;
|
||||
// Free or save (every other block) for all "cache sized" blocks.
|
||||
while (!cacheList.IsEmpty()) {
|
||||
if (performFree) {
|
||||
FreeBlock(cacheList.LastItem(), sizeOfBlocksInCache, isMallocTest, theThread, &cacheList,
|
||||
&nonCacheList);
|
||||
} else {
|
||||
SaveBlock(theCache, cacheList.LastItem(), sizeOfBlocksInCache, theThread, &cacheList,
|
||||
&nonCacheList);
|
||||
}
|
||||
performFree = !performFree;
|
||||
}
|
||||
// Free or save (every other block) for all "non-cache sized" blocks.
|
||||
while (!nonCacheList.IsEmpty()) {
|
||||
if (performFree) {
|
||||
FreeBlock(nonCacheList.LastItem(), sizeOfNonCacheBlocks, isMallocTest, theThread, &cacheList,
|
||||
&nonCacheList);
|
||||
} else {
|
||||
SaveBlock(theCache, nonCacheList.LastItem(), sizeOfNonCacheBlocks, theThread, &cacheList,
|
||||
&nonCacheList);
|
||||
}
|
||||
performFree = !performFree;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Method: BlockCacheConcurrencyTest::TestThreadMalloc()
|
||||
* Descr: This method passes the BBlockCache instance to TestBlockCache()
|
||||
* where the instance will be tested.
|
||||
*/
|
||||
|
||||
|
||||
void BlockCacheConcurrencyTest::TestThreadMalloc(void)
|
||||
{
|
||||
TestBlockCache(theMallocCache, true);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Method: BlockCacheConcurrencyTest::TestThreadObj()
|
||||
* Descr: This method passes the BBlockCache instance to TestBlockCache()
|
||||
* where the instance will be tested.
|
||||
*/
|
||||
|
||||
|
||||
void BlockCacheConcurrencyTest::TestThreadObj(void)
|
||||
{
|
||||
TestBlockCache(theObjCache, false);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Method: BlockCacheConcurrencyTest::suite()
|
||||
* Descr: This static member function returns a test caller for performing
|
||||
* the "BlockCacheConcurrencyTest" test. The test caller
|
||||
* is created as a ThreadedTestCaller with six independent threads.
|
||||
*/
|
||||
|
||||
|
||||
CppUnit::Test *BlockCacheConcurrencyTest::suite(void)
|
||||
{
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
$Id: BlockCacheConcurrencyTest.h,v 1.1 2003/09/07 11:53:03 bonefish Exp $
|
||||
|
||||
This file defines a class for testing BBlockCache
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BlockCacheConcurrencyTest_H
|
||||
#define BlockCacheConcurrencyTest_H
|
||||
|
||||
|
||||
#include "ThreadedTestCase.h"
|
||||
#include <string>
|
||||
#include <OS.h>
|
||||
|
||||
|
||||
class BBlockCache;
|
||||
class BList;
|
||||
|
||||
|
||||
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 Test *suite(void);
|
||||
void TestThreadObj(void);
|
||||
void TestThreadMalloc(void);
|
||||
virtual void setUp(void);
|
||||
virtual void tearDown(void);
|
||||
BlockCacheConcurrencyTest(std::string);
|
||||
virtual ~BlockCacheConcurrencyTest();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,361 @@
|
||||
/*
|
||||
$Id: BlockCacheExerciseTest.cpp,v 1.1 2003/09/07 11:53:03 bonefish Exp $
|
||||
|
||||
This file tests basic functionality of BBlockCache.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "BlockCacheExerciseTest.h"
|
||||
#include "cppunit/TestCaller.h"
|
||||
#include <BlockCache.h>
|
||||
|
||||
|
||||
/*
|
||||
* Method: BlockCacheExerciseTest::BlockCacheExerciseTest()
|
||||
* Descr: This method is the only constructor for the BlockCacheExerciseTest
|
||||
* class.
|
||||
*/
|
||||
|
||||
|
||||
BlockCacheExerciseTest::BlockCacheExerciseTest(std::string name) :
|
||||
TestCase(name),
|
||||
theCache(NULL),
|
||||
numBlocksInCache(0),
|
||||
sizeOfBlocksInCache(0),
|
||||
sizeOfNonCacheBlocks(0),
|
||||
isMallocTest(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Method: BlockCacheExerciseTest::~BlockCacheExerciseTest()
|
||||
* Descr: This method is the destructor for the BlockCacheExerciseTest class.
|
||||
*/
|
||||
|
||||
|
||||
BlockCacheExerciseTest::~BlockCacheExerciseTest()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Method: BlockCacheExerciseTest::TestBlockCache()
|
||||
* Descr: This method performs the tests on a particular BBlockCache.
|
||||
* The goal of the method is to perform the following basic
|
||||
* sequence:
|
||||
* 1. Get (numBlocksInCache + 10) blocks of "cache size" from the
|
||||
* BBlockCache. By doing this, we can guarantee that the cache
|
||||
* has been exhausted and some elements are allocated to
|
||||
* satisfy the caller. Then, they are all returned to the
|
||||
* cache in most recent block to oldest block order. This
|
||||
* confirms that regardless whether the block was initially
|
||||
* part of the cache or created because the cache was empty,
|
||||
* once it is returned to the cache, it is just placed on the
|
||||
* cache. Imagine a cache of 4 blocks. Initally, the cache
|
||||
* has the following blocks:
|
||||
* A, B, C, D
|
||||
* If five blocks are gotten from the cache, the caller will get
|
||||
* A, B, C, D, E
|
||||
* However, E wasn't initially part of the cache. It was allocated
|
||||
* dynamically to satisfy the caller's request because the cache
|
||||
* was empty. Now, if they are returned in the order E, D, C, B, A
|
||||
* the cache will have the following blocks available in it:
|
||||
* B, C, D, E
|
||||
* When A is returned, the cache will find there is no more room
|
||||
* for more free blocks and it will be freed. This is the
|
||||
* behaviour which is confirmed initially.
|
||||
*
|
||||
* 2. After this is done, the cache is just "exercised". The following
|
||||
* is done "numBlocksInCache" times:
|
||||
* - 4 "cache sized" blocks are gotten from the cache
|
||||
* - 4 "non-cache sized" blocks are gotten from the cache
|
||||
* - 1 "cache sized" block is returned back to the cache
|
||||
* - 1 "non-cache sized" block is returned back to the cache
|
||||
* - 1 "cache sized" block is freed and not returned to the cache
|
||||
* - 1 "non-cache sized" block is freed and not returned to the
|
||||
* cache (but even if given to the BBlockCache, it would just
|
||||
* be freed anyhow)
|
||||
* What this means is that everytime through the loop, 2 "cache sized"
|
||||
* and 2 "non-cache sized" blocks are kept in memory. At the end,
|
||||
* 2 * numBlocksInCache items of size "cache size" and "non cache size"
|
||||
* will exist.
|
||||
*
|
||||
* Then, numBlocksInCache / 4 items are returned to the cache and
|
||||
* numBlocksInCache / 4 are freed. This ensures at the end of the
|
||||
* test that there are some available blocks in the cache.
|
||||
*
|
||||
* The sum total of these actions test the BBlockCache.
|
||||
*/
|
||||
|
||||
|
||||
void BlockCacheExerciseTest::TestBlockCache(void)
|
||||
{
|
||||
|
||||
// First get all items from the cache plus ten more
|
||||
for (int i = 0; i < numBlocksInCache + 10; i++) {
|
||||
GetBlock(sizeOfBlocksInCache);
|
||||
}
|
||||
|
||||
// Put them all back in reverse order to confirm 1 from above
|
||||
while (!usedList.IsEmpty()) {
|
||||
SaveBlock(usedList.LastItem(), sizeOfBlocksInCache);
|
||||
}
|
||||
|
||||
// Get a bunch of blocks and send some back to the cache
|
||||
// to confirm 2 from above.
|
||||
for (int i = 0; i < numBlocksInCache; i++) {
|
||||
GetBlock(sizeOfBlocksInCache);
|
||||
GetBlock(sizeOfBlocksInCache);
|
||||
GetBlock(sizeOfNonCacheBlocks);
|
||||
GetBlock(sizeOfNonCacheBlocks);
|
||||
|
||||
// We send one back from the middle of the lists so
|
||||
// the most recent block is not the one returned.
|
||||
SaveBlock(usedList.ItemAt(usedList.CountItems() / 2),
|
||||
sizeOfBlocksInCache);
|
||||
SaveBlock(nonCacheList.ItemAt(nonCacheList.CountItems() / 2),
|
||||
sizeOfNonCacheBlocks);
|
||||
|
||||
GetBlock(sizeOfBlocksInCache);
|
||||
GetBlock(sizeOfBlocksInCache);
|
||||
GetBlock(sizeOfNonCacheBlocks);
|
||||
GetBlock(sizeOfNonCacheBlocks);
|
||||
|
||||
// We free one from the middle of the lists so the
|
||||
// most recent block is not the one freed.
|
||||
FreeBlock(usedList.ItemAt(usedList.CountItems() / 2),
|
||||
sizeOfBlocksInCache);
|
||||
FreeBlock(nonCacheList.ItemAt(nonCacheList.CountItems() / 2),
|
||||
sizeOfNonCacheBlocks);
|
||||
}
|
||||
|
||||
// Now, send some blocks back to the cache and free some blocks
|
||||
// so the cache is not empty at the end of the test.
|
||||
for (int i = 0; i < numBlocksInCache / 4; i++) {
|
||||
// Return the blocks which are 2/3s of the way through the
|
||||
// lists.
|
||||
SaveBlock(usedList.ItemAt(usedList.CountItems() * 2 / 3),
|
||||
sizeOfBlocksInCache);
|
||||
SaveBlock(nonCacheList.ItemAt(nonCacheList.CountItems() * 2 / 3),
|
||||
sizeOfNonCacheBlocks);
|
||||
|
||||
// Free the blocks which are 1/3 of the way through the lists.
|
||||
FreeBlock(usedList.ItemAt(usedList.CountItems() / 3),
|
||||
sizeOfBlocksInCache);
|
||||
FreeBlock(nonCacheList.ItemAt(nonCacheList.CountItems() / 3),
|
||||
sizeOfNonCacheBlocks);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Method: BlockCacheExerciseTest::BuildLists()
|
||||
* Descr: This method gets all of the blocks from the cache in order to
|
||||
* track them for future tests. The assumption here is that the
|
||||
* blocks are not deallocated and reallocated in the implementation
|
||||
* of BBlockCache. Given the purpose is to provide a cheap way to
|
||||
* access allocated memory without resorting to malloc()'s or new's,
|
||||
* this should be a fair assumption.
|
||||
*/
|
||||
|
||||
|
||||
void BlockCacheExerciseTest::BuildLists(void)
|
||||
{
|
||||
freeList.MakeEmpty();
|
||||
usedList.MakeEmpty();
|
||||
nonCacheList.MakeEmpty();
|
||||
|
||||
for(int i = 0; i < numBlocksInCache; i++) {
|
||||
freeList.AddItem(theCache->Get(sizeOfBlocksInCache));
|
||||
}
|
||||
for(int i = 0; i < numBlocksInCache; i++) {
|
||||
theCache->Save(freeList.ItemAt(i), sizeOfBlocksInCache);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Method: BlockCacheExerciseTest::GetBlock()
|
||||
* Descr: This method returns a pointer from the BBlockCache, checking
|
||||
* the value before passing it to the caller.
|
||||
*/
|
||||
|
||||
|
||||
void *BlockCacheExerciseTest::GetBlock(size_t blockSize)
|
||||
{
|
||||
void *thePtr = theCache->Get(blockSize);
|
||||
|
||||
// This new pointer should not be one which we already
|
||||
// have from the BBlockCache which we haven't given back
|
||||
// yet.
|
||||
assert(!usedList.HasItem(thePtr));
|
||||
assert(!nonCacheList.HasItem(thePtr));
|
||||
|
||||
if (blockSize == sizeOfBlocksInCache) {
|
||||
// If this block was one which could have come from the
|
||||
// cache and there are free items on the cache, it
|
||||
// should be one of those free blocks.
|
||||
if (freeList.CountItems() > 0) {
|
||||
assert(freeList.RemoveItem(thePtr));
|
||||
}
|
||||
assert(usedList.AddItem(thePtr));
|
||||
} else {
|
||||
// A "non-cache sized" block should never come from the
|
||||
// free list.
|
||||
assert(!freeList.HasItem(thePtr));
|
||||
assert(nonCacheList.AddItem(thePtr));
|
||||
}
|
||||
return(thePtr);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Method: BlockCacheExerciseTest::SavedCacheBlock()
|
||||
* Descr: This method passes the pointer back to the BBlockCache
|
||||
* and checks the sanity of the lists.
|
||||
*/
|
||||
|
||||
|
||||
void BlockCacheExerciseTest::SaveBlock(void *thePtr, size_t blockSize)
|
||||
{
|
||||
// The memory block being returned to the cache should
|
||||
// not already be free.
|
||||
assert(!freeList.HasItem(thePtr));
|
||||
|
||||
if (blockSize == sizeOfBlocksInCache) {
|
||||
// If there is room on the free list, when this block
|
||||
// is returned to the cache, it will be put on the
|
||||
// free list. Therefore we will also track it as
|
||||
// a free block on the cache.
|
||||
if (freeList.CountItems() < numBlocksInCache) {
|
||||
assert(freeList.AddItem(thePtr));
|
||||
}
|
||||
|
||||
// This block should not be on the non-cache list but it
|
||||
// should be on the used list.
|
||||
assert(!nonCacheList.HasItem(thePtr));
|
||||
assert(usedList.RemoveItem(thePtr));
|
||||
} else {
|
||||
// This block should not be on the used list but it should
|
||||
// be on the non-cache list.
|
||||
assert(!usedList.HasItem(thePtr));
|
||||
assert(nonCacheList.RemoveItem(thePtr));
|
||||
}
|
||||
theCache->Save(thePtr, blockSize);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Method: BlockCacheExerciseTest::FreeBlock()
|
||||
* Descr: This method frees the block directly using delete[] or free(),
|
||||
* checking the sanity of the lists as it does the operation.
|
||||
*/
|
||||
|
||||
|
||||
void BlockCacheExerciseTest::FreeBlock(void *thePtr, size_t blockSize)
|
||||
{
|
||||
// The block being freed should not already have been
|
||||
// returned to the cache.
|
||||
assert(!freeList.HasItem(thePtr));
|
||||
|
||||
if (blockSize == sizeOfBlocksInCache) {
|
||||
// This block should not be on the non-cache list but it
|
||||
// should be on the used list.
|
||||
assert(!nonCacheList.HasItem(thePtr));
|
||||
assert(usedList.RemoveItem(thePtr));
|
||||
} else {
|
||||
// This block should not be on the used list but it should
|
||||
// be on the non-cache list.
|
||||
assert(!usedList.HasItem(thePtr));
|
||||
assert(nonCacheList.RemoveItem(thePtr));
|
||||
}
|
||||
if (isMallocTest) {
|
||||
free(thePtr);
|
||||
} else {
|
||||
delete[] thePtr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Method: BlockCacheExerciseTest::PerformTest()
|
||||
* Descr: This method performs the tests on a series of BBlockCache
|
||||
* instances. It performs the tests with a series of
|
||||
* block sizes and numbers of blocks. Also, it does the
|
||||
* test using a B_OBJECT_CACHE and B_MALLOC_CACHE type
|
||||
* cache. For each individual BBlockCache to be tested, it:
|
||||
* 1. Queries the cache to find out the blocks which are
|
||||
* on it.
|
||||
* 2. Performs the test.
|
||||
* 3. Frees all blocks left after the test to prevent
|
||||
* memory leaks.
|
||||
*/
|
||||
|
||||
|
||||
void BlockCacheExerciseTest::PerformTest(void)
|
||||
{
|
||||
for (numBlocksInCache = 8; numBlocksInCache < 513; numBlocksInCache *= 2) {
|
||||
for (sizeOfBlocksInCache = 13; sizeOfBlocksInCache < 9478; sizeOfBlocksInCache *= 3) {
|
||||
|
||||
// To test getting blocks which are not from the cache,
|
||||
// we will get blocks of 6 bytes less than the size of
|
||||
// the blocks on the cache.
|
||||
sizeOfNonCacheBlocks = sizeOfBlocksInCache - 6;
|
||||
|
||||
isMallocTest = false;
|
||||
theCache = new BBlockCache(numBlocksInCache, sizeOfBlocksInCache, B_OBJECT_CACHE);
|
||||
assert(theCache != NULL);
|
||||
|
||||
// Query the cache and determine the blocks in it.
|
||||
BuildLists();
|
||||
// Perform the test on this instance.
|
||||
TestBlockCache();
|
||||
delete theCache;
|
||||
// Clean up remaining memory.
|
||||
while (!usedList.IsEmpty()) {
|
||||
FreeBlock(usedList.LastItem(), sizeOfBlocksInCache);
|
||||
}
|
||||
while (!nonCacheList.IsEmpty()) {
|
||||
FreeBlock(nonCacheList.LastItem(), sizeOfNonCacheBlocks);
|
||||
}
|
||||
|
||||
isMallocTest = true;
|
||||
theCache = new BBlockCache(numBlocksInCache, sizeOfBlocksInCache, B_MALLOC_CACHE);
|
||||
assert(theCache != NULL);
|
||||
|
||||
// Query the cache and determine the blocks in it.
|
||||
BuildLists();
|
||||
// Perform the test on this instance.
|
||||
TestBlockCache();
|
||||
delete theCache;
|
||||
// Clean up remaining memory.
|
||||
while (!usedList.IsEmpty()) {
|
||||
FreeBlock(usedList.LastItem(), sizeOfBlocksInCache);
|
||||
}
|
||||
while (!nonCacheList.IsEmpty()) {
|
||||
FreeBlock(nonCacheList.LastItem(), sizeOfNonCacheBlocks);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Method: BlockCacheExerciseTest::suite()
|
||||
* Descr: This static member function returns a test caller for performing
|
||||
* the "BlockCacheExerciseTest" test.
|
||||
*/
|
||||
|
||||
|
||||
CppUnit::Test *BlockCacheExerciseTest::suite(void)
|
||||
{
|
||||
typedef CppUnit::TestCaller<BlockCacheExerciseTest>
|
||||
BlockCacheExerciseTestCaller;
|
||||
|
||||
return(new BlockCacheExerciseTestCaller("BBlockCache::Exercise Test", &BlockCacheExerciseTest::PerformTest));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
$Id: BlockCacheExerciseTest.h,v 1.1 2003/09/07 11:53:03 bonefish Exp $
|
||||
|
||||
This file defines a class for performing tests on the BBlockCache class.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BlockCacheExerciseTest_H
|
||||
#define BlockCacheExerciseTest_H
|
||||
|
||||
|
||||
#include "cppunit/TestCase.h"
|
||||
#include <List.h>
|
||||
|
||||
|
||||
class BBlockCache;
|
||||
|
||||
|
||||
class BlockCacheExerciseTest : public CppUnit::TestCase {
|
||||
|
||||
private:
|
||||
BBlockCache *theCache;
|
||||
int numBlocksInCache;
|
||||
size_t sizeOfBlocksInCache;
|
||||
size_t sizeOfNonCacheBlocks;
|
||||
|
||||
bool isMallocTest;
|
||||
|
||||
BList freeList;
|
||||
BList usedList;
|
||||
BList nonCacheList;
|
||||
|
||||
void BuildLists(void);
|
||||
void *GetBlock(size_t blockSize);
|
||||
void SaveBlock(void *, size_t blockSize);
|
||||
void FreeBlock(void *, size_t blockSize);
|
||||
void TestBlockCache(void);
|
||||
|
||||
protected:
|
||||
|
||||
public:
|
||||
static CppUnit::Test *suite(void);
|
||||
BlockCacheExerciseTest(std::string = "");
|
||||
virtual ~BlockCacheExerciseTest();
|
||||
virtual void PerformTest(void);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
$Id: BlockCacheTest.cpp,v 1.1 2003/09/07 11:53:03 bonefish Exp $
|
||||
*/
|
||||
|
||||
|
||||
#include "cppunit/Test.h"
|
||||
#include "cppunit/TestSuite.h"
|
||||
#include "BlockCacheExerciseTest.h"
|
||||
#include "BlockCacheConcurrencyTest.h"
|
||||
|
||||
|
||||
CppUnit::Test* BlockCacheTestSuite()
|
||||
{
|
||||
CppUnit::TestSuite *testSuite = new CppUnit::TestSuite();
|
||||
|
||||
testSuite->addTest(BlockCacheExerciseTest::suite());
|
||||
testSuite->addTest(BlockCacheConcurrencyTest::suite());
|
||||
|
||||
return testSuite;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef _blockcache_test_h_
|
||||
#define _blockcache_test_h_
|
||||
|
||||
class CppUnit::Test;
|
||||
|
||||
CppUnit::Test* BlockCacheTestSuite();
|
||||
|
||||
#endif // _blockcache_test_h_
|
||||
Reference in New Issue
Block a user