// $Id$ /************************************************************************** * This file is property of and copyright by the ALICE HLT Project * * ALICE Experiment at CERN, All rights reserved. * * * * Primary Authors: Matthias Richter <Matthias.Richter@ift.uib.no> * * 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 testAliRawReader.C @author Matthias Richter @date @brief Test macro/program for the AliRawReaderMemory */ #ifndef __CINT__ #include "TFile.h" #include "TDatime.h" #include "TRandom.h" #include "TArrayI.h" #include "TArrayC.h" #include "TSystem.h" #include "AliRawDataHeader.h" #include "AliRawReaderFile.h" #include "AliRawReaderMemory.h" #include "AliRawHLTManager.h" #include "AliDAQ.h" #include "AliHLTSystem.h" #include <ostream> #endif //__CINT__ #ifndef __CINT__ const int sizeofAliRawDataHeader=sizeof(AliRawDataHeader); #else // cint does not handle sizeof correctly const int sizeofAliRawDataHeader=32; #endif ///////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////// // // configuration of the test program // const char* tmpdir="/tmp/testAliRawReaderMemory"; bool gbVerbose=false; ///////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////// int GetRandom(int min, int max); int FillRandomDDL(TArrayC& target); int WriteDDL(TArrayC& ddl, int ddlid); int CheckRawReader(AliRawReader* pRawReader, TArrayC* ddls, int* ddlids, int nofDDLs); int CheckRawReaderMemory(TArrayC* ddlArray, int* ddlidArray, int nofDDLs); int CheckRawReaderHLT(AliRawReader* pParent, TArrayC* ddls, int* ddlids, int nofDDLs); int CheckDDL_ReadNext(AliRawReader* pRawReader, TArrayC& ddl, int ddlid); int CheckDDL_ReadNextData(AliRawReader* pRawReader, TArrayC& ddl, int ddlid); int CheckDDL_ReadNextChar(AliRawReader* pRawReader, TArrayC& ddl, int ddlid); int CheckDDL_ReadMixed(AliRawReader* pRawReader, TArrayC& ddl, int ddlid); int testAliRawReaderFile() { int iResult=0; // cleanup old raw folders TString command; command.Form("rm -r %s 2> /dev/null", tmpdir); gSystem->Exec(command); gSystem->mkdir(tmpdir); // variable number of DDLs int nofDDLs=0; do { nofDDLs=GetRandom(2,10); } while (nofDDLs<2); // allocate buffers TArrayC* ddlArray=new TArrayC[nofDDLs]; int* ddlidArray=new int[nofDDLs]; // create DDL ids and content int i=0; do { int detectorId=GetRandom(0,5); ddlidArray[i]=GetRandom(0,AliDAQ::NumberOfDdls(detectorId)-1)+AliDAQ::DdlIDOffset(detectorId); // check for duplicate id int j=0; for (; j<i; j++) if (ddlidArray[i]==ddlidArray[j]) break; if (j!=i) continue; // try once again FillRandomDDL(ddlArray[i]); if (gbVerbose) cout << "simulating data for ddl " << ddlidArray[i] << " size " << ddlArray[i].GetSize() << endl; WriteDDL(ddlArray[i], ddlidArray[i]); } while (++i<nofDDLs); if (gbVerbose) cout << "checking AliRawReaderFile ..." << endl; TString rawdir=tmpdir; if (!rawdir.EndsWith("/")) rawdir+="/"; AliRawReader* pRawReader=AliRawReader::Create(rawdir); if (!pRawReader) { cerr << "can not create RawReaderFile" << endl; return -1; } if (!pRawReader->NextEvent()) { cerr << "error: getting event from RawReaderFile failed" << endl; return -1; } if ((iResult=CheckRawReader(pRawReader, ddlArray, ddlidArray, nofDDLs))<0) { return iResult; } ///////////////////////////////////////////////////////////////////////////////////////// // check AliRawReaderMemory if ((iResult=CheckRawReaderMemory(ddlArray, ddlidArray, nofDDLs))<0) { return iResult; } ///////////////////////////////////////////////////////////////////////////////////////// // Matthias 2009-01-24 // disable check of RawReaderHLT for the moment due to problems with loeding libHLTrec // from AliRAWHLTManager // if ((iResult=CheckRawReaderHLT(pRawReader, ddlArray, ddlidArray, nofDDLs))<0) { // return iResult; // } delete pRawReader; gSystem->Exec(command); return 0; } Bool_t seedSet=kFALSE; /** * Get a random number in the given range. */ int GetRandom(int min, int max) { if (max-min<2) return min; static TRandom rand; if (!seedSet) { TDatime dt; rand.SetSeed(dt.Get()); seedSet=kTRUE; } return rand.Integer(max-min); } /** * Fill the array with random DDL data. * The function leaves space for the CDH, sets the size member of the * CDH either to the buffer size or 0xffffffff by a random decision. */ int FillRandomDDL(TArrayC& target) { int size=0; do size=GetRandom(100, 10000); while (size<100); target.Set(size); // decide randomly whether to set size of 0xffffffff if (GetRandom(0,40)%4) { *((Int_t*)target.GetArray())=size; } else { *((UInt_t*)target.GetArray())=0xffffffff; } for (int i=sizeofAliRawDataHeader; i<size; i++) { Int_t data=GetRandom(0,255); target.AddAt((UChar_t)data, i); } return size; } /** * Write the simulated DDL data to file * Creates the filename from the DDL naming convention using the * AliDAQ conventions. The file is written to folder tmpdir/raw0 * whereas tmpdir can be adjusted above. */ int WriteDDL(TArrayC& ddl, int ddlid) { Int_t dummy=0; TString filename; filename.Form("%s/raw0", tmpdir); gSystem->mkdir(filename); filename.Form("%s/%s_%d.ddl", filename.Data(), AliDAQ::DetectorNameFromDdlID(ddlid, dummy), ddlid); FILE* fp=fopen(filename.Data(), "w"); if (!fp) return -1; fwrite(ddl.GetArray(), 1, ddl.GetSize(), fp); fclose(fp); return 0; } /** * Check the AliRawReaderMemory * * Check consists of 3 steps: * - check with one ddl per cycle: SetMemory/SetEquipmentID method * - check with multiple buffers: AddBuffer method * - check with one ddl as constructor parameter and AddBuffer for the * subsequent ddls * * @return -1 if check failed */ int CheckRawReaderMemory(TArrayC* ddlArray, int* ddlidArray, int nofDDLs) { int iResult=0; int i=0; ///////////////////////////////////////////////////////////////////////////////////////// if (gbVerbose) cout << "checking AliRawReaderMemory ..." << endl; AliRawReaderMemory* pRawReaderMemory=new AliRawReaderMemory; for (i=0; i<nofDDLs; i++) { if (!pRawReaderMemory->SetMemory((UChar_t*)ddlArray[i].GetArray(), ddlArray[i].GetSize())) { cerr << "AliRawReaderMemory::SetMemory failed for block " << i << endl; return -1; } pRawReaderMemory->SetEquipmentID(ddlidArray[i]); if (i==0 && !pRawReaderMemory->NextEvent()) { cerr << "error: getting event from RawReaderMemory failed" << endl; return -1; } if ((iResult=CheckRawReader(pRawReaderMemory, ddlArray+i, ddlidArray+i, 1))<0) { return iResult; } } if (pRawReaderMemory->NextEvent()) { cerr << "error: RawReaderMemory::NextEvent returns true, while no more events should be there" << endl; return -1; } ///////////////////////////////////////////////////////////////////////////////////////// if (gbVerbose) cout << "checking AliRawReaderMemory with multiple buffers ..." << endl; pRawReaderMemory->RewindEvents(); pRawReaderMemory->ClearBuffers(); for (i=0; i<nofDDLs; i++) { if (!pRawReaderMemory->AddBuffer((UChar_t*)ddlArray[i].GetArray(), ddlArray[i].GetSize(), ddlidArray[i])) { cerr << "AliRawReaderMemory::AddBuffer failed for block " << i << endl; return -1; } } if (!pRawReaderMemory->NextEvent()) { cerr << "error: getting event from RawReaderMemory failed" << endl; return -1; } if ((iResult=CheckRawReader(pRawReaderMemory, ddlArray, ddlidArray, nofDDLs))<0) { return iResult; } if (pRawReaderMemory->NextEvent()) { cerr << "error: RawReaderMemory::NextEvent returns true, while no more events should be there" << endl; return -1; } delete pRawReaderMemory; pRawReaderMemory=NULL; ///////////////////////////////////////////////////////////////////////////////////////// if (gbVerbose) cout << "checking AliRawReaderMemory constructor ..." << endl; for (i=0; i<nofDDLs; i++) { if (!pRawReaderMemory) { pRawReaderMemory=new AliRawReaderMemory((UChar_t*)ddlArray[i].GetArray(), ddlArray[i].GetSize()); if (pRawReaderMemory) { pRawReaderMemory->SetEquipmentID(ddlidArray[i]); } else { cerr << "can not create AliRawReaderMemory with parameters" << endl; return -1; } }else if (!pRawReaderMemory->AddBuffer((UChar_t*)ddlArray[i].GetArray(), ddlArray[i].GetSize(), ddlidArray[i])) { cerr << "AliRawReaderMemory::AddBuffer failed for block " << i << endl; return -1; } } if (!pRawReaderMemory->NextEvent()) { cerr << "error: getting event from RawReaderMemory failed" << endl; return -1; } if ((iResult=CheckRawReader(pRawReaderMemory, ddlArray, ddlidArray, nofDDLs))<0) { return iResult; } if (pRawReaderMemory->NextEvent()) { cerr << "error: RawReaderMemory::NextEvent returns true, while no more events should be there" << endl; return -1; } delete pRawReaderMemory; pRawReaderMemory=NULL; return iResult; } /** * Check the AliRawReaderHLT * * Open the AliRawReaderHLT from the parent reader without any HLTOUT * options, i.e. all requests are just forwarded. * * @return -1 if check failed */ int CheckRawReaderHLT(AliRawReader* pParent, TArrayC* ddls, int* ddlids, int nofDDLs) { if (gbVerbose) cout << "checking AliRawReaderHLT ..." << endl; int iResult=0; pParent->RewindEvents(); pParent->Reset(); TString arg; // Int_t dummy=0; // for (i=0; i<nofDDLs; i++) { // if (!arg.Contains(AliDAQ::DetectorNameFromDdlID(ddlidArray[i], dummy))) { // arg+=" "; arg+=AliDAQ::DetectorNameFromDdlID(ddlidArray[i], dummy); // } // } AliRawReader* pRawReaderHLT=AliRawHLTManager::CreateRawReaderHLT(pParent, arg.Data()); if (!pRawReaderHLT) { cerr << "can not create HLT RawReader" << endl; return -1; } if (!pRawReaderHLT->NextEvent()) { cerr << "error: getting event from HLT RawReader failed" << endl; return -1; } if ((iResult=CheckRawReader(pRawReaderHLT, ddls, ddlids, nofDDLs))<0) { return iResult; } delete pRawReaderHLT; return iResult; } /** * Check a RawReader, compare with the corresponding simulated data. * The corresponding simulated data is searched from the array via the current * equipment id. The check consists of 4 steps: * - data comparison by ReadNext * - data comparison by ReadNextData * - data comparison by ReadNextChar * - data comparison by mixed reading: ReadNextInt/Short/Char/Data * * @return -1 if failed */ int CheckRawReader(AliRawReader* pRawReader, TArrayC* ddls, int* ddlids, int nofDDLs) { int iResult=0; int count=0; // 1st pass: check AliRawReader::ReadNext() while (pRawReader->ReadHeader()) { int id=pRawReader->GetEquipmentId(); int i=0; for (i=0; i<nofDDLs; i++) { if (ddlids[i]==id) break; } if (i==nofDDLs) { cerr << "error: can not find ddl id " << id << endl; return -1; } if ((iResult=CheckDDL_ReadNext(pRawReader, ddls[i], ddlids[i]))<0) return iResult; count++; } if (count<nofDDLs) { cerr << "less than the available blocks found from RawReader" << endl; return -1; } // 2nd pass: check AliRawReader::ReadNextData() count=0; pRawReader->Reset(); while (pRawReader->ReadHeader()) { int id=pRawReader->GetEquipmentId(); int i=0; for (i=0; i<nofDDLs; i++) { if (ddlids[i]==id) break; } if (i==nofDDLs) { cerr << "error: can not find ddl id " << id << endl; return -1; } if ((iResult=CheckDDL_ReadNextData(pRawReader, ddls[i], ddlids[i]))<0) return iResult; count++; } if (count<nofDDLs) { cerr << "less than the available blocks found from RawReader" << endl; return -1; } // 3rd pass: check AliRawReader::ReadNextData() count=0; pRawReader->Reset(); while (pRawReader->ReadHeader()) { int i=0; do { int id=pRawReader->GetEquipmentId(); for (i=0; i<nofDDLs; i++) { if (ddlids[i]==id) break; } if (i==nofDDLs) { cerr << "error: can not find ddl id " << id << endl; return -1; } count++; if ((iResult=CheckDDL_ReadNextChar(pRawReader, ddls[i], ddlids[i]))<0) return iResult; } // note: the ReadHeader is hidden in the ReadNextChar while (iResult!=ddlids[i]); } if (count<nofDDLs) { cerr << "less than the available blocks found from RawReader" << endl; return -1; } // 4th pass: check mixed AliRawReader::ReadNext*() count=0; pRawReader->Reset(); while (pRawReader->ReadHeader()) { int id=pRawReader->GetEquipmentId(); int i=0; for (i=0; i<nofDDLs; i++) { if (ddlids[i]==id) break; } if (i==nofDDLs) { cerr << "error: can not find ddl id " << id << endl; return -1; } if ((iResult=CheckDDL_ReadMixed(pRawReader, ddls[i], ddlids[i]))<0) return iResult; count++; } if (count<nofDDLs) { cerr << "less than the available blocks found from RawReader" << endl; return -1; } return iResult; } /** * Check RawReaders ReadNext function and compare data with simulated data * of the provided buffer. */ int CheckDDL_ReadNext(AliRawReader* pRawReader, TArrayC& ddl, int ddlid) { int dataSize=pRawReader->GetDataSize(); if (ddl.GetSize()!=dataSize+sizeofAliRawDataHeader) { cerr << "error: size mismatch in ddl " << ddlid << ": " << dataSize+sizeofAliRawDataHeader << " required " << ddl.GetSize() << endl; return -1; } TArrayC buffer(dataSize); UChar_t* pTgt=(UChar_t*)buffer.GetArray(); if (!pRawReader->ReadNext(pTgt, buffer.GetSize())) { cerr << "error: reading " << buffer.GetSize() << " byte(s) from ReadNext (ddl " << ddlid << ")" << endl; return -1; } if (ddlid!=pRawReader->GetEquipmentId()) { cerr << "error: ReadMixed ddl id missmatch after ReadNext: reqired id " << ddlid << " got " << pRawReader->GetEquipmentId() << endl; return -1; } TString sizeStr; if (*((UInt_t*)ddl.GetArray())==0xffffffff) { sizeStr=" (0xffffffff)"; } else { sizeStr.Form(" (%d)", ddl.GetSize()); } if (gbVerbose) cout << "verify ReadNext: ddl " << ddlid << sizeStr << endl; if (memcmp(ddl.GetArray()+sizeofAliRawDataHeader, buffer.GetArray(), buffer.GetSize())!=0) { cerr << "error: verification of ddl " << ddlid << ")" << endl; return -1; } return 0; } /** * Check RawReaders ReadNextData function and compare data with simulated data * of the provided buffer. */ int CheckDDL_ReadNextData(AliRawReader* pRawReader, TArrayC& ddl, int ddlid) { int dataSize=pRawReader->GetDataSize(); if (ddl.GetSize()!=dataSize+sizeofAliRawDataHeader) { cerr << "error: size mismatch in ddl " << ddlid << ": " << dataSize+sizeofAliRawDataHeader << " required " << ddl.GetSize() << endl; return -1; } UChar_t* pTgt=NULL; if (!pRawReader->ReadNextData(pTgt) || pTgt==NULL) { cerr << "error: reading " << dataSize << " byte(s) from ReadNextData (ddl " << ddlid << ")" << endl; return -1; } if (gbVerbose) cout << "verify ReadNextData: ddl " << ddlid << endl; if (memcmp(ddl.GetArray()+sizeofAliRawDataHeader, pTgt, dataSize)!=0) { cerr << "error: verification of ddl " << ddlid << endl; return -1; } return 0; } /** * Check RawReaders ReadNextChar function and compare data with simulated data * of the provided buffer. */ int CheckDDL_ReadNextChar(AliRawReader* pRawReader, TArrayC& ddl, int ddlid) { int iResult=ddlid; int dataSize=pRawReader->GetDataSize(); if (ddl.GetSize()!=dataSize+sizeofAliRawDataHeader) { cerr << "error: size mismatch in ddl " << ddlid << ": " << dataSize+sizeofAliRawDataHeader << " required " << ddl.GetSize() << endl; return -1; } if (gbVerbose) cout << "verify ReadNextChar: ddl " << ddlid << endl; static int offset=0; int i=sizeofAliRawDataHeader+offset; UChar_t data=0; Bool_t haveData=kFALSE; for (; (haveData=pRawReader->ReadNextChar(data)) && i<ddl.GetSize(); i++) { if (data!=(UChar_t)ddl.At(i)) { cerr << "error: at position " << i << " of ddl " << ddlid << ": read " << (UShort_t)data << " required " << (UShort_t)(UChar_t)ddl.At(i) << endl; return -1; } } if (i<ddl.GetSize()) { cerr << "error: reading data of ddl " << ddlid << ": " << i << " of " << ddl.GetSize() << endl; return -1; } if (pRawReader->GetEquipmentId()>=0 && ddlid!=pRawReader->GetEquipmentId()) { //cerr << "error: ddl id missmatch, expecting " << ddlid << " got " << pRawReader->GetEquipmentId() << endl; // thats not an error condition, RawReader just changes silently to the next DDL iResult=pRawReader->GetEquipmentId(); offset=1; } else { offset=0; } if (haveData && iResult==ddlid) { cerr << "error: size missmatch in ddl " << ddlid << ": still data available after " << ddl.GetSize() << " byte(s)"<< endl; return -1; } return iResult; } /** * Check RawReaders ReadNextInt/Short/Char/Data functions and compare data with * simulated data of the provided buffer. */ int CheckDDL_ReadMixed(AliRawReader* pRawReader, TArrayC& ddl, int ddlid) { int dataSize=pRawReader->GetDataSize(); if (ddl.GetSize()!=dataSize+sizeofAliRawDataHeader) { cerr << "error: size mismatch in ddl " << ddlid << ": " << dataSize+sizeofAliRawDataHeader << " required " << ddl.GetSize() << endl; return -1; } TArrayC readBytes(7); // we do not need to test if there is only one byte if (dataSize<=readBytes.GetSize()) return 0; UInt_t i=0; for (; i<(readBytes.GetSize()/sizeof(UInt_t))*sizeof(UInt_t); i+=sizeof(UInt_t)) { UInt_t data=0; if (!pRawReader->ReadNextInt(data)) { cerr << "error: reading 1 int from ReadNextInt position " << i << " (ddl " << ddlid << ")" << endl; return -1; } #ifndef R__BYTESWAP data = (((data & 0x000000ffU) << 24) | ((data & 0x0000ff00U) << 8) | ((data & 0x00ff0000U) >> 8) | ((data & 0xff000000U) >> 24)); #endif *(reinterpret_cast<UInt_t*>(readBytes.GetArray()+i))=data; } for (; i<(readBytes.GetSize()/sizeof(UShort_t))*sizeof(UShort_t); i+=sizeof(UShort_t)) { UShort_t data=0; if (!pRawReader->ReadNextShort(data)) { cerr << "error: reading 1 short from ReadNextShort position " << i << " (ddl " << ddlid << ")" << endl; return -1; } #ifndef R__BYTESWAP data = (((data & 0x00ffU) << 8) | ((data & 0xff00U) >> 8)) ; #endif *(reinterpret_cast<UShort_t*>(readBytes.GetArray()+i))=data; } for (; i<(UInt_t)readBytes.GetSize(); i++) { if (!pRawReader->ReadNextChar(*(reinterpret_cast<UChar_t*>(readBytes.GetArray()+i)))) { cerr << "error: reading 1 byte from ReadNextChar position " << i << " (ddl " << ddlid << ")" << endl; return -1; } } UChar_t* pTgt=NULL; // TODO: here we have a problem with the HLT Raw Reader, due to the // behavior of ReadNextData. It returns the pointer to either // - the remaining data within this block. Thogh, GetDataSize still // returns the full lenght // - if no more data available switch to next equipment // Currently, the RawReaderHLT switches immediately to the next // equipment, considered the GetDataSize behavior this is correct, but // different from the others // // Use ReadNext for the moment in order to get the test scheme working. //if (!pRawReader->ReadNextData(pTgt) || pTgt==NULL) { TArrayC buffer(dataSize-readBytes.GetSize()); pTgt=(UChar_t*)buffer.GetArray(); if (!pRawReader->ReadNext(pTgt, buffer.GetSize())) { cerr << "error: reading " << dataSize << " byte(s) from ReadNextData (ddl " << ddlid << ")" << endl; return -1; } if (ddlid!=pRawReader->GetEquipmentId()) { cerr << "error: ReadMixed ddl id missmatch after ReadNextData: reqired id " << ddlid << " got " << pRawReader->GetEquipmentId() << endl; return -1; } if (gbVerbose) cout << "verify ReadNextInt/Short/Char/Data: ddl " << ddlid << endl; if (memcmp((ddl.GetArray())+sizeofAliRawDataHeader, readBytes.GetArray(), readBytes.GetSize())!=0) { cerr << "error: verification of mixed ReadNextInt/Short/Char failed in ddl " << ddlid << endl; return -1; } if (memcmp((ddl.GetArray())+readBytes.GetSize()+sizeofAliRawDataHeader, pTgt, dataSize-readBytes.GetSize())!=0) { cerr << "error: verification of mixed ReadNext ddl " << ddlid << endl; return -1; } return 0; } int main(int /*argc*/, const char** /*argv*/) { int iResult=testAliRawReaderFile(); if (iResult<0) { cerr << "check failed, repeat in verbose mode ..." << endl; gbVerbose=true; iResult=testAliRawReaderFile(); } return iResult; }