add CachedFactory, initial version of Guillaume Chatelet

git-svn-id: svn://svn.code.sf.net/p/loki-lib/code/trunk@719 7ec92016-0320-0410-acc4-a06ded1c099a
This commit is contained in:
syntheticpp 2006-10-16 09:31:45 +00:00
parent 530af30626
commit cf3ca512e6
7 changed files with 2467 additions and 0 deletions

View file

@ -0,0 +1,61 @@
[Project]
FileName=CachedFactory.dev
Name=Factory
UnitCount=2
Type=1
Ver=1
ObjFiles=
Includes=..\..\include
Libs=
PrivateResource=
ResourceIncludes=
MakeIncludes=
Compiler=
CppCompiler=-D DEBUG_@@_-D _DEBUG_@@_-Wall -pedantic_@@_
Linker=
IsCpp=1
Icon=
ExeOutput=
ObjectOutput=
OverrideOutput=0
OverrideOutputName=CachedFactoryTest.exe
HostApplication=
Folders=
CommandLine=
UseCustomMakefile=0
CustomMakefile=Makefile.loki
IncludeVersionInfo=0
SupportXPThemes=0
CompilerSet=0
CompilerSettings=0000000000000001000000
[VersionInfo]
Major=0
Minor=1
Release=1
Build=1
LanguageID=1033
CharsetID=1252
CompanyName=
FileVersion=
FileDescription=Developed using the Dev-C++ IDE
InternalName=
LegalCopyright=
LegalTrademarks=
OriginalFilename=
ProductName=
ProductVersion=
AutoIncBuildNr=0
[Unit1]
FileName=CachedFactoryTest.cpp
CompileCpp=1
Folder=CachedFactory
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=

View file

@ -0,0 +1,186 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8,00"
Name="Factory"
ProjectGUID="{925D5863-2F77-41B7-96F1-CC814762C40F}"
RootNamespace="CachedFactory"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="-wd4996"
Optimization="0"
AdditionalIncludeDirectories="..\..\include"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE _SECURE_SCL=1"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="4"
Detect64BitPortabilityProblems="false"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
GenerateDebugInformation="true"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
AdditionalIncludeDirectories="..\..\include"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
WarningLevel="4"
Detect64BitPortabilityProblems="false"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<File
RelativePath=".\CachedFactoryTest.cpp"
>
</File>
<File
RelativePath="..\..\include\loki\CachedFactory.h"
>
</File>
<File
RelativePath="..\..\include\loki\Key.h"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View file

@ -0,0 +1,414 @@
#define USE_SEQUENCE
#include <iostream>
#include <loki/Factory.h>
#ifdef LOKI_DISABLE_TYPELIST_MACROS
#define USE_WQUENCE
#endif
#ifdef USE_SEQUENCE
#include <loki/Sequence.h>
#endif
#include <loki/CachedFactory.h>
#include <windows.h>
using std::cout;
using std::cerr;
using std::endl;
using std::vector;
using namespace Loki;
class AbstractProduct{
public:
virtual ~AbstractProduct(){};
};
class Product : public AbstractProduct
{
public:
Product(){}
Product( int, int ){}
};
class CostlyProduct : public AbstractProduct
{
public:
CostlyProduct(){Sleep(100);}
CostlyProduct( int, int ){Sleep(100);}
};
class DebugProduct : public AbstractProduct
{
public:
DebugProduct()
{ cout << "Product Ctor()" << endl; }
DebugProduct( int, int )
{ cout << "Product Ctor(int, int)" << endl; }
~DebugProduct()
{ cout << "Product Dtor()" << endl; }
};
CostlyProduct* createCostlyProductNull()
{
return new CostlyProduct;
}
DebugProduct* createDebugProductNull()
{
return new DebugProduct;
}
Product* createProductNull()
{
return new Product;
}
Product* createProductInt(int a, int b)
{
return new Product(a,b);
}
const int nullID(0);
const int intID(1);
bool dispResult(const char* message, bool result)
{
cout << "## " << message << (result?" ...OK":" ...Failed !") << endl;
return result;
}
template<class CCache>
bool unitTestCacheOverhead(int loop){
std::clock_t start, elapsedNoCache, elapsedCache;
start = std::clock();
for(int i=0;i<loop;i++)
delete createProductNull();
elapsedNoCache = std::clock() - start;
cout << " " << elapsedNoCache << " ms" ;
CCache CC;
CC.Register(nullID, createProductNull);
start = std::clock();
for(int i=0;i<loop;i++){
AbstractProduct *pProduct(CC.CreateObject(nullID));
CC.ReleaseObject(pProduct);
}
elapsedCache = std::clock() - start;
cout << " " << elapsedCache << " ms";
cout << " | average overhead per fetch : " <<(((double)(elapsedCache-elapsedNoCache)) / CLOCKS_PER_SEC * 1000 / loop) << " ms" << endl;
return true;
}
void testCacheOverhead(){
const int loop(1000000);
cout << "Starting cache overhead test with " << loop << " loops" << endl;
typedef CachedFactory< AbstractProduct, int, NullType, SimplePointer, AmountLimitedCreation, EvictRandom > CRandomEvict;
typedef CachedFactory< AbstractProduct, int, NullType, SimplePointer, AmountLimitedCreation, EvictLRU > CLRUEvict;
typedef CachedFactory< AbstractProduct, int, NullType, SimplePointer, AmountLimitedCreation, EvictAging > CAgingEvict;
bool test1 = dispResult("Random policy", unitTestCacheOverhead< CRandomEvict >(loop));
bool test2 = dispResult("LRU policy", unitTestCacheOverhead< CLRUEvict >(loop));
bool test3 = dispResult("Aging policy", unitTestCacheOverhead< CAgingEvict >(loop));
}
void unitTestCachePerformance(int loop){
typedef CachedFactory< AbstractProduct, int > CCache;
std::clock_t start, elapsedNoCache, elapsedCache;
start = std::clock();
for(int i=0;i<loop;i++)
delete createCostlyProductNull();
elapsedNoCache = std::clock() - start;
CCache CC;
CC.Register(nullID, createCostlyProductNull);
start = std::clock();
for(int i=0;i<loop;i++){
AbstractProduct *pProduct(CC.CreateObject(nullID));
CC.ReleaseObject(pProduct);
}
elapsedCache = std::clock() - start;
cout << "No cache "<<elapsedNoCache<<" ms | Cache "<<elapsedCache<<" ms | Efficiency " << (double(elapsedNoCache)/elapsedCache)-1 << endl;
}
void testCachePerformance()
{
for(int i=1;i<=5;i++){
cout << " || => " << i << " iterations" << endl;
unitTestCachePerformance(i);
}
}
template< class Cache >
std::clock_t typicalUse( Cache &CC, unsigned objectKind, unsigned maxObjectCount, unsigned maxIteration)
{
assert(objectKind>0);
assert(maxIteration>0);
assert(maxObjectCount>0);
vector< AbstractProduct* > fetched;
fetched.reserve(maxObjectCount);
srand(0); // initialise the pseudo random operator
std::clock_t start, end;
try{
// Registering objects
for(int i=0;i<objectKind;i++)
CC.Register(i, createProductNull);
// Simulating real use
start = std::clock();
for(unsigned i=0;i<maxIteration;i++)
{
const size_t size(fetched.size());
if( size == maxObjectCount ){
CC.ReleaseObject(fetched.back());
fetched.pop_back();
} else if(size == 0){
fetched.push_back(CC.CreateObject(int(objectKind*rand()/(RAND_MAX + 1.0))));
} else if(rand()<RAND_MAX/2){
CC.ReleaseObject(fetched.back());
fetched.pop_back();
} else {
fetched.push_back(CC.CreateObject(int(objectKind*rand()/(RAND_MAX + 1.0))));
}
}
end = std::clock();
}catch(std::exception &e)
{
cout << "Error in executing typicalUse " << endl << e.what() << endl;
}
// Cleaning in use objects
for(std::vector<AbstractProduct*>::iterator itr = fetched.begin(); itr!=fetched.end(); itr++)
CC.ReleaseObject(*itr);
fetched.clear();
return end-start;
}
template< class Cache >
void displayTypicalUse(Cache &CC, unsigned objectKind, unsigned maxObjectCount, unsigned maxIteration)
{
CC.displayCacheType();
cout << "====> " << typicalUse<Cache>(CC, objectKind, maxObjectCount, maxIteration) << " ms" << endl;
}
void testTypicalUse()
{
const unsigned objectKind(10);
const unsigned maxObjectCount(300);
const unsigned maxIteration(1000000);
cout << "# " << objectKind << " objects registered in the Factory" << endl;
cout << "# Cache contains max " << maxObjectCount << " objects" << endl;
cout << "# Test performs "<< maxIteration <<" iterations" << endl;
{
typedef CachedFactory< AbstractProduct, int, NullType, SimplePointer, AlwaysCreate, EvictRandom, SimpleStatisticPolicy > CRandomEvict;
CRandomEvict cache;
displayTypicalUse<CRandomEvict>( cache, objectKind, maxObjectCount, maxIteration);
}
{
typedef CachedFactory< AbstractProduct, int, NullType, SimplePointer, AlwaysCreate, EvictLRU, SimpleStatisticPolicy > CLRUEvict;
CLRUEvict cache;
displayTypicalUse( cache, objectKind, maxObjectCount, maxIteration);
}
{
typedef CachedFactory< AbstractProduct, int, NullType, SimplePointer, AlwaysCreate, EvictAging, SimpleStatisticPolicy > CAgingEvict;
CAgingEvict cache;
displayTypicalUse( cache, objectKind, maxObjectCount, maxIteration);
}
}
template< class Cache >
bool testEvictionError()
{
bool testPassed = false;
Cache CC;
CC.Register(nullID, createProductNull);
CC.setMaxCreation(1);
AbstractProduct *pProduct1 = NULL, *pProduct2 = NULL;
try{
pProduct1 = CC.CreateObject(nullID); // should be OK
pProduct2 = CC.CreateObject(nullID); // should cast an exception
} catch(std::exception &e){
if(strcmp(e.what(), EvictionException().what())==0)
testPassed = true;
}
if(pProduct1!=NULL)
CC.ReleaseObject(pProduct1);
if(pProduct2!=NULL)
CC.ReleaseObject(pProduct2);
return testPassed;
}
bool testAllEvictionError()
{
typedef CachedFactory< AbstractProduct, int, NullType, SimplePointer, AmountLimitedCreation, EvictRandom > CRandomEvict;
typedef CachedFactory< AbstractProduct, int, NullType, SimplePointer, AmountLimitedCreation, EvictLRU > CLRUEvict;
typedef CachedFactory< AbstractProduct, int, NullType, SimplePointer, AmountLimitedCreation, EvictAging > CAgingEvict;
bool test1 = dispResult("Random policy", testEvictionError< CRandomEvict >());
bool test2 = dispResult("LRU policy", testEvictionError< CLRUEvict >());
bool test3 = dispResult("Aging policy", testEvictionError< CAgingEvict >());
return test1 && test2 && test3;
}
bool testAmountLimitedCreation()
{
typedef CachedFactory< AbstractProduct, int, NullType, SimplePointer, AmountLimitedCreation, EvictRandom, SimpleStatisticPolicy > CCache;
CCache CC;
CC.Register(nullID, createDebugProductNull);
CC.Register(intID, createDebugProductNull);
// CC.setMaxCreation(0); <== would break on assert, such a cache is useless
CC.setMaxCreation(1);
AbstractProduct *pProduct1 = NULL, *pProduct2 = NULL;
pProduct1 = CC.CreateObject(nullID); // should be OK
CC.ReleaseObject(pProduct1);
pProduct2 = CC.CreateObject(intID); // should call the evict method
if(pProduct1!=NULL)
CC.ReleaseObject(pProduct1);
if(pProduct2!=NULL)
CC.ReleaseObject(pProduct2);
return (CC.getDestroyed()==1);
}
bool testRateLimitedFetchPolicy(bool waitBetweenFetch)
{
typedef CachedFactory< AbstractProduct, int, NullType, SimplePointer, RateLimitedCreation > CCache;
CCache CC;
CC.Register(nullID, createProductNull);
CC.setRate(2/*max two fetchs*/,100/*within 100 ms*/);
bool exceptionOccured = false;
const int number(5);
const int sleepTime(60);
AbstractProduct *products[number];
for(int i=0;i<number;i++) products[i]=NULL; // initializing
try{
for(int i=0;i<number;i++){
products[i] = CC.CreateObject(nullID);
if(waitBetweenFetch && (i!=(number-1))){
Sleep(sleepTime);
}
}
} catch (std::exception &e){
exceptionOccured = true;
cout << "Exception occured" << endl << e.what() <<endl;
}
// Cleaning things by releasing
for(int i=0;i<number;i++)
if(products[i]!=NULL)
CC.ReleaseObject(products[i]);
return exceptionOccured;
}
bool fullTestRateLimitedFetchPolicy()
{
cout << " || => Setting rate limit to 2 fetch within 100 ms." << endl;
cout << " || => generating 5 objects " << endl;
bool test1 = dispResult("Fast creation", testRateLimitedFetchPolicy(false)==true);
cout << " || => generating 5 objects with 60ms between each Fetch" << endl;
bool test2 = dispResult("Slow creation", testRateLimitedFetchPolicy(true)==false);
return test1 && test2;
}
bool testRelease(){
typedef CachedFactory< AbstractProduct, int > CCache;
CCache CC;
CC.Register(nullID, createProductNull);
AbstractProduct *pProduct = NULL;
CC.ReleaseObject(pProduct);
cout << "Caching failed" << endl;
}
bool testCache()
{
typedef CachedFactory< AbstractProduct, int, Seq< int, int > > CCache2Parm;
CCache2Parm CC2;
CC2.Register(intID, createProductInt);
AbstractProduct * pProduct = CC2.CreateObject(intID,5,3);
AbstractProduct * pSave(pProduct);
CC2.ReleaseObject(pProduct);
pProduct = CC2.CreateObject(intID,5,3);
if(pSave != pProduct)
{
cout << "Caching failed" << endl;
return false;
}
else
{
CC2.ReleaseObject(pProduct);
return true;
}
}
void dispText(char* text)
{
cout << endl;
cout << "##========================================"<< endl;
cout << "## " << text << endl;
cout << "##========================================"<< endl;
}
void dispText(char* text, char* comment)
{
cout << endl;
cout << "##========================================"<< endl;
cout << "## " << text << endl;
cout << "## " << comment << endl;
cout << "##========================================"<< endl;
}
void separator()
{
cout << endl << endl;
}
void performanceTests()
{
dispText(" ==> Performance tests <==");
separator();
dispText("Test typical use", "tries different Cache strategies in a typical use configuration");
testTypicalUse();
separator();
dispText("Test efficiency","Comparison between generating costly objects (100ms) and using Cache");
testCachePerformance();
separator();
dispText("Test overhead","Intensive use of Cache to determine the cache time overhead");
testCacheOverhead();
separator();
}
void reliabilityTests()
{
dispText(" ==> Reliability tests <==");
separator();
dispText("Test caching", "Trying to Create, Release, Create and see if Cache gives the same object");
bool cacheResult= dispResult("caching result", testCache());
separator();
dispText("Test RateLimitedFetch policy",
"Trying to quickly create objects, then same scenario with pause in between");
bool rateLimitedResult= dispResult("RateLimitedFetch policy result",fullTestRateLimitedFetchPolicy());
separator();
dispText("Test AmountLimitedCreation policy","Trying to create 2 objects with a limit of 1 creation max, you should see a destroyed object (eviction)");
bool amountLimitedResult = dispResult("AmountLimitedCreation policy result", testAmountLimitedCreation());
separator();
dispText("Test eviction error", "An eviction should occur (Creation Policy), but all object are in use");
bool evictionTest = dispResult("eviction error test result", testAllEvictionError());
separator();
if(cacheResult&&rateLimitedResult&&amountLimitedResult&&evictionTest)
dispText("All tests passed successfully");
else
dispText("One or more test have failed");
}
int main(int argc, char **argv)
{
try{
performanceTests();
reliabilityTests();
}catch(std::exception &e){
cerr << e.what() << endl;
cerr << "Error while performing tests" << endl;
}
}
// TODO provide :
// +Efficiency tests
// +Overhead tests
// +Fiability tests

16
test/CachedFactory/Makefile Executable file
View file

@ -0,0 +1,16 @@
include ../Makefile.common
BIN := Factory$(BIN_SUFFIX)
SRC := Factory.cpp
OBJ := $(SRC:.cpp=.o)
.PHONY: all clean
all: $(BIN)
clean: cleandeps
$(RM) $(BIN)
$(RM) $(OBJ)
$(BIN): $(OBJ)
$(CXX) $(LDFLAGS) -o $@ $^ $(LDLIBS)
include ../../Makefile.deps

View file

@ -0,0 +1,7 @@
cl -c -Zm200 -O2 -DNDEBUG -MT -EHsc -GR -W4 -wd4710 -I"." -I"..\..\include" CachedFactoryTest.cpp.cpp
link /NOLOGO /SUBSYSTEM:CONSOLE /incremental:no /OUT:"main-msvc.exe" ..\..\lib\loki.lib CachedFactoryTest.cpp.obj
del *.obj