// $Id$ /************************************************************************** * This file is property of and copyright by the ALICE HLT Project * * ALICE Experiment at CERN, All rights reserved. * * * * Primary Authors: Matthias Richter * * for The ALICE HLT Project. * * * * Permission to use, copy, modify and distribute this software and its * * documentation strictly for non-commercial purposes is hereby granted * * without fee, provided that the above copyright notice appears in all * * copies and that both the copyright notice and this permission notice * * appear in the supporting documentation. The authors make no claims * * about the suitability of this software for any purpose. It is * * provided "as is" without express or implied warranty. * **************************************************************************/ /** @file testAliHLTDataBuffer.C @author Matthias Richter @date @brief Test program for the AliHLTDataBuffer class */ #ifndef __CINT__ #include "TDatime.h" #include "TRandom.h" #include "AliHLTDataTypes.h" #include "algorithm" #include "TObjArray.h" #include "TObjString.h" #include "TString.h" #include "AliHLTDAQ.h" #include #include #include #include #include "AliHLTDataBuffer.h" #endif using namespace std; int gVerbosity=0; const int gPagesize=1024*1024; template int testLoop(vector& descriptions, int nofLevels, int nofCycles); int GetRandom(int min, int max); class AliHLTRandomBuffer { public: AliHLTRandomBuffer(): fpBuffer(NULL), fBufferSize(0), fInstances() {} AliHLTRandomBuffer(AliHLTUInt32_t size): fpBuffer(NULL), fBufferSize(0), fInstances() {Init(size);} AliHLTRandomBuffer(const AliHLTRandomBuffer&): fpBuffer(NULL), fBufferSize(0), fInstances() {} AliHLTRandomBuffer& operator=(const AliHLTRandomBuffer& src) {if (&src!=this) {fpBuffer=NULL; fBufferSize=0;} return *this;} ~AliHLTRandomBuffer() {} int Init(AliHLTUInt32_t size) { if (fpBuffer) return -EINPROGRESS; fpBuffer=new AliHLTUInt8_t[size]; if (!fpBuffer) return -ENOMEM; fBufferSize=size; int words=size/sizeof(AliHLTUInt32_t); AliHLTUInt32_t* pTgt=reinterpret_cast(fpBuffer); for (int i=0; ifBufferSize) return -ENOSPC; AliHLTRandomBufferInstance instance; instance.fId=fInstances.size()>0?fInstances.back().fId+1:0; instance.fOffset=GetRandom(0, fBufferSize-size); instance.fSize=size; fInstances.push_back(instance); return instance.fId; } int ReleaseInstance(int id) { for (vector::iterator instance=fInstances.begin(); instance!=fInstances.end(); instance++) { if (instance->fId==id) { fInstances.erase(instance); return 0; } } return -ENOENT; } const AliHLTUInt8_t* GetBuffer(int id) { for (vector::iterator instance=fInstances.begin(); instance!=fInstances.end(); instance++) { if (instance->fId==id) { return fpBuffer+instance->fOffset; } } return NULL; } bool CompareBuffer(const AliHLTUInt8_t* buffer, AliHLTUInt32_t size, int id) { if (!buffer) return false; for (vector::iterator instance=fInstances.begin(); instance!=fInstances.end(); instance++) { if (instance->fId==id) { if (instance->fSize!=size) { cout << "CompareBuffer ("<< instance->fId << "): size missmatch: " << size << ", expected " << instance->fSize << endl; return false; } return memcmp(buffer, fpBuffer+instance->fOffset, size)==0; } } return false; } void Print(const char* /*option*/) { cout << "AliHLTRandomBufferInstance " << this << ": buffer " << (void*)fpBuffer << " size " << fBufferSize << endl; if (!fpBuffer) return; int words=fBufferSize/sizeof(AliHLTUInt32_t); int lines=words/4; AliHLTUInt32_t* pTgt=reinterpret_cast(fpBuffer); for (int line=0; line fInstances; }; AliHLTRandomBuffer gData(2*gPagesize); /** * @class AliHLTTestRawPage * Helper class for testing cycles of memory allocation, buffer modification, and * cleanup with the AliHLTRawPage within the function testLoop. */ class AliHLTTestRawPage { public: AliHLTTestRawPage() : fBuffer(NULL) {} AliHLTTestRawPage(const AliHLTTestRawPage& src) : fBuffer(src.fBuffer) {} AliHLTTestRawPage& operator=(const AliHLTTestRawPage& src) { fBuffer=src.fBuffer; return *this; } ~AliHLTTestRawPage() {} bool IsAllocated() {return fBuffer!=NULL;} bool Alloc(AliHLTUInt32_t size, int verbosity) { fBuffer=AliHLTDataBuffer::AliHLTRawPage::GlobalAlloc(size); if (!fBuffer) return false; if (verbosity>1) { printf("allocated raw buffer %p from page %p\n", fBuffer, AliHLTDataBuffer::AliHLTRawPage::FindPage(fBuffer)); fBuffer->Print("min"); } return true; } AliHLTUInt8_t* GetPointer() {return fBuffer?fBuffer->GetPointer():NULL;} bool SetSize(AliHLTUInt32_t size, int verbosity) { AliHLTDataBuffer::AliHLTRawPage* rawpage=AliHLTDataBuffer::AliHLTRawPage::FindPage(fBuffer); if (rawpage) { if (rawpage->SetSize(fBuffer, size)==0) { if (verbosity>1) { cout << "setting size for raw buffer " << fBuffer << " of page " << rawpage << endl; fBuffer->Print("min"); } return true; } else { cerr << "failed to set size for raw buffer " << fBuffer << endl; } } else { cerr << "can not find raw page for buffer " << fBuffer << endl; } return false; } bool Free(int verbosity) { AliHLTDataBuffer::AliHLTRawPage* rawpage=AliHLTDataBuffer::AliHLTRawPage::FindPage(fBuffer); if (rawpage) { if (rawpage->Free(fBuffer)==0) { if (verbosity>1) cout << "released raw buffer " << fBuffer << " from page " << rawpage << endl; fBuffer=NULL; return true; } else { cerr << "failed to release raw buffer " << fBuffer << endl; } } else { cerr << "can not find raw page for buffer " << fBuffer << endl; } return false; } AliHLTUInt32_t GetTotalSize() {return fBuffer?fBuffer->GetTotalSize():0;} bool GlobalClean(int verbosity) { int nofPages=0; for (AliHLTDataBuffer::AliHLTRawPage* rawpage=AliHLTDataBuffer::AliHLTRawPage::NextPage(NULL); rawpage!=NULL; rawpage=AliHLTDataBuffer::AliHLTRawPage::NextPage(rawpage)) { nofPages++; } if (verbosity>=1) { cout << "total number of pages: " << nofPages << endl; } AliHLTDataBuffer::AliHLTRawPage::GlobalClean(); return true; } void Print(const char* options) { if (strcmp(options, "pages")==0 || strcmp(options, "global")==0) { AliHLTDataBuffer::AliHLTRawPage::NextPage(NULL)->Print("global"); return; } } private: AliHLTDataBuffer::AliHLTRawBuffer* fBuffer; }; struct testRawPageDescription { testRawPageDescription() : fLevel(0), fBufferSize(0), fDataId(-1), fTest() {}; int fLevel; AliHLTUInt32_t fBufferSize; int fDataId; AliHLTTestRawPage fTest; }; class AliHLTDataBufferWrapper : public AliHLTDataBuffer { public: int ResetDataBuffer() { return AliHLTDataBuffer::ResetDataBuffer(); } }; /** * @class AliHLTTestDataBuffer * Helper class for testing cycles of memory allocation, buffer modification, and * cleanup with the AliHLTDataBuffer within the function testLoop. */ class AliHLTTestDataBuffer { public: AliHLTTestDataBuffer() : fInstance(NULL), fBuffer(NULL), fSize(0) {} AliHLTTestDataBuffer(const AliHLTTestDataBuffer&) : fInstance(NULL), fBuffer(NULL), fSize(0) {} ; AliHLTTestDataBuffer& operator=(const AliHLTTestDataBuffer&) { fInstance=NULL; fBuffer=NULL; fSize=0; return *this; } bool IsAllocated() {return fBuffer!=NULL;} bool Alloc(AliHLTUInt32_t size, int verbosity) { if (!fInstance) { fInstance=new AliHLTDataBufferWrapper; if (!fInstance) return false; fInstance->SetGlobalLoggingLevel(verbosity>1?kHLTLogAll:(AliHLTComponentLogSeverity)0x7c); } fBuffer=fInstance->GetTargetBuffer(size); if (!fBuffer) return false; fSize=size; if (verbosity>1) { cout << "allocated data buffer" << this << endl; } return true; } AliHLTUInt8_t* GetPointer() {return fBuffer;} bool SetSize(AliHLTUInt32_t size, int verbosity) { if (!fInstance) return false; AliHLTComponentBlockData bd; AliHLTComponent::FillBlockData(bd); bd.fSize=size; bd.fOffset=0; fInstance->SetSegments(fBuffer, &bd, 1); if (verbosity>1) { cout << "setting size for data buffer " << this << ": allocated size " << fSize << " -> " << size << endl; } fSize=size; return true; } bool Free(int verbosity) { if (!fInstance) return false; fSize=0; if (fInstance->ResetDataBuffer()==0) { if (verbosity>1) cout << "released data buffer " << this << endl; fBuffer=NULL; return true; } else { cerr << "failed to release raw buffer " << fBuffer << endl; } return false; } AliHLTUInt32_t GetTotalSize() {return fSize;} bool GlobalClean(int verbosity) { if (!fInstance) return false; if (verbosity>=1) { fInstance->PrintStatistics(); } delete fInstance; AliHLTDataBuffer::AliHLTRawPage::GlobalClean(); return true; } void Print(const char* options) { if (strcmp(options, "pages")==0 || strcmp(options, "global")==0) { fInstance->PrintStatistics(); AliHLTDataBuffer::AliHLTRawPage::NextPage(NULL)->Print("global"); return; } } private: AliHLTDataBufferWrapper* fInstance; AliHLTUInt8_t* fBuffer; AliHLTUInt32_t fSize; }; struct testDataBufferDescription { testDataBufferDescription() : fLevel(0), fBufferSize(0), fDataId(-1), fTest() {}; int fLevel; AliHLTUInt32_t fBufferSize; int fDataId; AliHLTTestDataBuffer fTest; }; template int CopyDescription(vector& target, vector& source) { target.clear(); for (unsigned i=0; i int fillTestSample(int levels, int processes, vector& descriptions) { int availableProcesses=processes; for (int level=0; level int allocateBuffers(vector& descriptions, int level=-1) { for (unsigned i=0; i=0 && descriptions[i].fLevel=0 && descriptions[i].fLevel>level) break; if (descriptions[i].fTest.IsAllocated()) { cerr << "warning: buffer already allocated" << endl; continue; } if (descriptions[i].fTest.Alloc(GetRandom(descriptions[i].fBufferSize/2, descriptions[i].fBufferSize), gVerbosity)) { } if (!descriptions[i].fTest.IsAllocated()) { cerr << "failed to allocate buffer for process " << i << endl; return -EFAULT; } } return 0; } template int setBufferSizes(vector& descriptions, int level=-1) { // set buffer size for all processes of the specified level // buffer size is chosen randomly between 0 and the allocated size vector positions; for (unsigned i=0; i=0 && descriptions[i].fLevel=0 && descriptions[i].fLevel>level) break; positions.push_back(i); } random_shuffle(positions.begin(), positions.end()); for (vector::iterator position=positions.begin(); position!=positions.end(); position++) { AliHLTUInt32_t datasize=GetRandom(0, descriptions[*position].fTest.GetTotalSize()); descriptions[*position].fDataId=gData.CreateInstance(datasize); const AliHLTUInt8_t* pSrc=gData.GetBuffer(descriptions[*position].fDataId); if (!pSrc) { cout << "error creating data instance" << endl; return -1; } AliHLTUInt8_t* pTgt=descriptions[*position].fTest.GetPointer(); if (!pTgt) { cout << "error target buffer" << endl; return -1; } memcpy(pTgt, pSrc, datasize); if (descriptions[*position].fTest.SetSize(datasize, gVerbosity)) { if (gVerbosity>1) cout << " process " << *position << " level " << descriptions[*position].fLevel << endl; } else { cout << "failed allocation for process " << *position << " level " << descriptions[*position].fLevel << endl; return -1; } } return 0; } template int releaseBuffers(vector& descriptions, int level=-1) { // find the processes to be releases according to the specified level // shuffle the processes and then release in this random order vector positions; for (unsigned i=0; i=0 && descriptions[i].fLevel=0 && descriptions[i].fLevel>level) break; positions.push_back(i); } random_shuffle(positions.begin(), positions.end()); for (vector::iterator position=positions.begin(); position!=positions.end(); position++) { if (!gData.CompareBuffer(descriptions[*position].fTest.GetPointer(), descriptions[*position].fTest.GetTotalSize(), descriptions[*position].fDataId)) { cout << "data comparison failed for process " << *position << " level " << descriptions[*position].fLevel << endl; return -1; } gData.ReleaseInstance(descriptions[*position].fDataId); if (descriptions[*position].fTest.Free(gVerbosity)) { if (gVerbosity>1) cout << " process " << *position << " level " << descriptions[*position].fLevel << endl; } else { cout << "failed deallocation for process " << *position << " level " << descriptions[*position].fLevel << endl; return -1; } } return 0; } template int testLoop(vector& descriptions, int nofLevels, int nofCycles) { // test the buffer allocation and deallocation from the AliHLTRawPage // // build a hierarchy of processes like in a real chain, in the first // implementation it is only a linear tree // the number of levels and processes are randomly chosen from a certain range // processes are distributed among the levels such that there is a decreasing // number of processes but at least one process // // The test cycle consists of the following steps // - loop over all levels // - allocation of a maximum buffer for every process of the current level // - set the buffer size to be used for every process of the current level // - release buffers of the previous level // - check all created raw pages and throw error, if // - not all buffers released // - not all memory released // - still fragmented // int iResult=0; AliHLTDataBuffer::AliHLTRawPage* rawpage=NULL; for (int cycle=0; cycle=0; cycle++) { for (int level=0; level<=nofLevels; level++) { // allocate buffers if (level1) { cout << "finished allocation - level " << level << " "; descriptions[0].fTest.Print("pages"); } if (level1) { cout << "finished size modification - level " << level << " "; descriptions[0].fTest.Print("pages"); } if (level>0) { if ((iResult=releaseBuffers(descriptions, level-1))<0) { cerr << "failed to release buffers" << endl; return iResult; } } } if (gVerbosity>1) { cout << "status of released pages: " << endl << " "; descriptions[0].fTest.Print("pages"); } for (rawpage=AliHLTDataBuffer::AliHLTRawPage::NextPage(NULL); rawpage!=NULL; rawpage=AliHLTDataBuffer::AliHLTRawPage::NextPage(rawpage)) { if (rawpage->IsUsed()) { cerr << "page " << rawpage << " has used buffers" << endl; iResult=-EFAULT; } else if (rawpage->Size()!=rawpage->Capacity()) { cerr << "page " << rawpage << " not completely released" << endl; iResult=-EFAULT; } else if (rawpage->IsFragmented()) { cerr << "page " << rawpage << " is still fragmented" << endl; iResult=-EFAULT; } } AliHLTDataBuffer::SetGlobalEventCount(cycle); } if (iResult<0) { descriptions[0].fTest.Print("pages"); } descriptions[0].fTest.GlobalClean(gVerbosity); return iResult; } /** * Get a random number in the given range. */ int GetRandom(int min, int max) { if (max-min<2) return min; static TRandom rand; static bool seedSet=false; if (!seedSet) { TDatime dt; rand.SetSeed(dt.Get()); seedSet=true; } return min+rand.Integer(max-min); } int testAliHLTDataBuffer() { int iResult=0; const int iMaxLevels=10; int nofLevels=GetRandom(3,iMaxLevels); int nofProcesses=GetRandom(nofLevels,2*iMaxLevels); int nofCycles=GetRandom(100,1000); vector descriptions; if ((iResult=fillTestSample(nofLevels, nofProcesses, descriptions))<0) { cerr << "failed to fill test sample" << endl; return iResult; } // adjust to the level of the last entry nofLevels=descriptions[descriptions.size()-1].fLevel; if (gVerbosity>0) { cout << " Test setup: " << nofLevels << " levels/ " << nofProcesses << " processes/ " << nofCycles << " cycle(s)" << endl; cout << " Pagesize: " << gPagesize << endl; for (unsigned i=0; i0) { cout << "checking memory allocation using AliHLTRawPage directly ..." << endl; } vector rawpagedesc; CopyDescription(rawpagedesc, descriptions); if ((iResult=testLoop(rawpagedesc, nofLevels, nofCycles))<0) return iResult; return 0; } ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// // // main functions int main(int /*argc*/, const char** /*argv*/) { int iResult=0; const int nofCycles=10; for (int cycle=0; cycle=0; cycle++) { iResult=testAliHLTDataBuffer(); if (((cycle+1)*100/nofCycles)%10==0) { cout << (cycle+1)*100/nofCycles << "% complete" << endl; } } return iResult; }