*/
#include "AliHLTCompStatCollector.h"
+#include "TFile.h"
#include "TStopwatch.h"
#include "TH1F.h"
#include "TH2F.h"
#include "TH2C.h"
#include "TTree.h"
+#include "TFolder.h"
+#include "TNamed.h"
#include "TString.h"
+#include <cassert>
+
+#define HLTSTAT_FOLDER_NAME "HLTstat"
+#define HLTSTAT_FOLDER_DESC "ALICE HLT component statistics"
+#define HLTSTAT_ENTRY_PARENT_FOLDER_NAME "parents"
+#define HLTSTAT_ENTRY_PARENT_FOLDER_DESC "parent components"
+#define HLTSTAT_ENTRY_PROPS_FOLDER_NAME "props"
+#define HLTSTAT_ENTRY_PROPS_FOLDER_DESC "component properties"
+#define HLTSTAT_ENTRY_PROPS_IDOBJ_NAME "id"
+#define HLTSTAT_ENTRY_PROPS_IDOBJ_DESC "numerical id calculated from chain id"
/** ROOT macro for the implementation of ROOT specific class methods */
ClassImp(AliHLTCompStatCollector)
:
AliHLTProcessor(),
fpTimer(NULL),
+ fpFolder(NULL),
fpStatTree(NULL),
fCycleTime(0),
fNofSets(0),
fpCTimeArray(NULL),
fpInputBlockCountArray(NULL),
fpTotalInputSizeArray(NULL),
+ fpNormalizedInputSizeArray(NULL),
fpOutputBlockCountArray(NULL),
fpTotalOutputSizeArray(NULL)
+ , fpInputOutputRatioArray(NULL)
+ , fpNormalizedInputOutputRatioArray(NULL)
+ , fpComponentCycleTimeArray(NULL)
+ , fpEventTypeArray(NULL)
+ , fpEventCountArray(NULL)
+ , fSizeEstimator(1000)
+ , fMode(kPublishObjects)
+ , fFileName()
+ , fFile(NULL)
+ , fLastTime(time(NULL))
+ , fPeriod(0)
+ , fEventModulo(0)
{
// see header file for class documentation
// or
void AliHLTCompStatCollector::GetOutputDataSize( unsigned long& constBase, double& inputMultiplier )
{
// see header file for class documentation
- constBase=1000;
+ constBase=fSizeEstimator;
inputMultiplier=100.0;
}
argument=argv[i];
if (argument.IsNull()) continue;
- // -array-size
- if (argument.CompareTo("-array-size")==0) {
+ // -file
+ if (argument.CompareTo("-file")==0) {
+ if ((bMissingParam=(++i>=argc))) break;
+ fFileName=argv[i];
+ fMode|=kSaveObjects;
+
+ // -modulo
+ } else if (argument.CompareTo("-modulo")==0) {
+ if ((bMissingParam=(++i>=argc))) break;
+ TString param=argv[i];
+ if (param.IsDigit()) {
+ fEventModulo=param.Atoi();
+ } else {
+ HLTError("expecting number as parameter for option %s", argument.Data());
+ iResult=-EINVAL;
+ }
+
+ // -period
+ } else if (argument.CompareTo("-period")==0) {
if ((bMissingParam=(++i>=argc))) break;
- TString param=argv[argc];
+ TString param=argv[i];
+ if (param.IsDigit()) {
+ fPeriod=param.Atoi();
+ } else {
+ HLTError("expecting number as parameter for option %s", argument.Data());
+ iResult=-EINVAL;
+ }
+
+ // -publish
+ } else if (argument.CompareTo("-publish")==0) {
+ if ((bMissingParam=(++i>=argc))) break;
+ TString param=argv[i];
+ if (param.IsDigit()) {
+ if (param.Atoi()==1) fMode|=kPublishObjects;
+ else if (param.Atoi()==0) fMode&=~kPublishObjects;
+ else {
+ HLTError("expecting 0 or 1 as parameter for option %s", argument.Data());
+ iResult=-EINVAL;
+ }
+ } else {
+ HLTError("expecting number as parameter for option %s", argument.Data());
+ iResult=-EINVAL;
+ }
+
+ // -arraysize
+ } else if (argument.CompareTo("-arraysize")==0) {
+ if ((bMissingParam=(++i>=argc))) break;
+ TString param=argv[i];
if (param.IsDigit()) {
fArraySize=param.Atoi();
} else {
- HLTError("expecting number as parameter for option '-array-size'");
+ HLTError("expecting number as parameter for option %s", argument.Data());
iResult=-EINVAL;
}
} else {
+ HLTError("unknown argument %s", argument.Data());
iResult=-EINVAL;
}
}
fpCTimeArray=new UInt_t[fArraySize];
fpInputBlockCountArray=new UInt_t[fArraySize];
fpTotalInputSizeArray=new UInt_t[fArraySize];
+ fpNormalizedInputSizeArray=new UInt_t[fArraySize];
fpOutputBlockCountArray=new UInt_t[fArraySize];
fpTotalOutputSizeArray=new UInt_t[fArraySize];
+ fpInputOutputRatioArray=new UInt_t[fArraySize];
+ fpNormalizedInputOutputRatioArray=new UInt_t[fArraySize];
+ fpComponentCycleTimeArray=new UInt_t[fArraySize];
+ fpEventTypeArray=new UInt_t[fArraySize];
+ fpEventCountArray=new UInt_t[fArraySize];
fpStatTree=new TTree("CompStat", "HLT component statistics");
if (fpStatTree) {
fpStatTree->Branch("CTime", fpCTimeArray, "CTime[nofSets]/i");
fpStatTree->Branch("InputBlockCount", fpInputBlockCountArray, "InputBlockCount[nofSets]/i");
fpStatTree->Branch("TotalInputSize", fpTotalInputSizeArray, "TotalInputSize[nofSets]/i");
+ fpStatTree->Branch("NormalizedInputSize", fpNormalizedInputSizeArray, "NormalizedInputSize[nofSets]/i");
fpStatTree->Branch("OutputBlockCount", fpOutputBlockCountArray, "OutputBlockCount[nofSets]/i");
fpStatTree->Branch("TotalOutputSize", fpTotalOutputSizeArray, "TotalOutputSize[nofSets]/i");
+ fpStatTree->Branch("InputOutputRatio", fpInputOutputRatioArray, "InputOutputRatio[nofSets]/i");
+ fpStatTree->Branch("NormalizedInputOutputRatio", fpNormalizedInputOutputRatioArray, "NormalizedInputOutputRatio[nofSets]/i");
+ fpStatTree->Branch("ComponentCycleTime",fpComponentCycleTimeArray, "ComponentCycleTime[nofSets]/i");
+ fpStatTree->Branch("EventType",fpEventTypeArray, "EventType[nofSets]/i");
+ fpStatTree->Branch("EventCount",fpEventCountArray, "EventCount[nofSets]/i");
}
}
+
+ if (!fFileName.empty()) {
+ fFile=new TFile(fFileName.c_str(), "RECREATE");
+ }
return iResult;
}
// see header file for class documentation
ClearAll();
+ if (fFile) {
+ fFile->Close();
+ delete fFile;
+ fFile=NULL;
+ }
return 0;
}
// see header file for class documentation
int iResult=0;
+ AliHLTUInt32_t eventType=gkAliEventTypeUnknown;
+ IsDataEvent(&eventType);
+
ResetFillingVariables();
if (fpTimer) {
fCycleTime=fpTimer->RealTime()*1000000;
}
+ bool bEmbeddedTree=false;
+ bool bFolderCreated=false;
+ if ((bFolderCreated=(fpFolder==NULL))) {
+ fpFolder=new TFolder(HLTSTAT_FOLDER_NAME, HLTSTAT_FOLDER_DESC);
+ if (bEmbeddedTree) fpFolder->Add(fpStatTree);
+ }
+ if (!fpFolder) return -ENOMEM;
+ vector<TFolder*> newFolders;
+
+ for (const AliHLTComponentBlockData* pBlock=GetFirstInputBlock(kAliHLTDataTypeComponentTable);
+ pBlock && iResult>=0;
+ pBlock=GetNextInputBlock()) {
+ string chainId, compId, compArgs;
+ vector<AliHLTUInt32_t> parents;
+ iResult=ExtractComponentTableEntry((const AliHLTUInt8_t*)pBlock->fPtr, pBlock->fSize,
+ chainId, compId, compArgs,
+ parents);
+ if (iResult>0) {
+ HLTDebug("%s(%s) 0x%08x", chainId.c_str(), compId.c_str(), pBlock->fSpecification);
+ TObject* pObj=NULL;
+ TFolder* pEntry=NULL;
+ if ((pObj=fpFolder->FindObjectAny(chainId.c_str()))!=NULL &&
+ (pEntry=dynamic_cast<TFolder*>(pObj))!=NULL ) {
+
+ } else if (pObj) {
+ HLTError("entry %s exists in folder, but is not a sub-folder", chainId.c_str());
+ } else if (chainId.size()>0) {
+ pEntry=new TFolder(chainId.c_str(), chainId.c_str());
+ if (pEntry) {
+ pEntry->SetOwner();
+ TFolder* pProps=pEntry->AddFolder(HLTSTAT_ENTRY_PROPS_FOLDER_NAME, HLTSTAT_ENTRY_PROPS_FOLDER_DESC);
+ if (pProps) {
+ pProps->Add(new TObjString(compId.c_str()));
+ if (!compArgs.empty())
+ pProps->Add(new TObjString(compArgs.c_str()));
+ TNamed* pCRC=new TNamed(HLTSTAT_ENTRY_PROPS_IDOBJ_NAME, HLTSTAT_ENTRY_PROPS_IDOBJ_DESC);
+ if (pCRC) {
+ pCRC->SetUniqueID(pBlock->fSpecification);
+ pProps->Add(pCRC);
+ }
+ }
+ TFolder* pParents=pEntry->AddFolder(HLTSTAT_ENTRY_PARENT_FOLDER_NAME, HLTSTAT_ENTRY_PARENT_FOLDER_DESC);
+ if (pParents) {
+ for (vector<AliHLTUInt32_t>::iterator parent=parents.begin();
+ parent!=parents.end(); parent++) {
+ TString name; name.Form("0x%08x", *parent);
+ pParents->Add(new TObjString(name));
+ }
+ }
+ if (parents.size()==0) {
+ newFolders.push_back(pEntry);
+ } else {
+ vector<TFolder*>::iterator iter=newFolders.begin();
+ vector<AliHLTUInt32_t>::iterator parent=parents.begin();
+ while (iter!=newFolders.end() && parent!=parents.end()) {
+ TObject* idobj=(*iter)->FindObjectAny(HLTSTAT_ENTRY_PROPS_IDOBJ_NAME);
+ AliHLTUInt32_t crcid=0;
+ if (idobj) crcid=idobj->GetUniqueID();
+ HLTDebug("check: %s 0x%08x", (*iter)->GetName(), crcid);
+ if (idobj && crcid==*parent) break;
+ if ((++parent!=parents.end())) continue;
+ parent=parents.begin();
+ iter++;
+ }
+ newFolders.insert(iter,pEntry);
+ }
+ }
+ } else {
+ HLTError("missing chain id for table entry 0x%08x (%p %d), skipping ...", pBlock->fSpecification, pBlock->fPtr, pBlock->fSize);
+ }
+ } else if (iResult!=0) {
+ HLTError("extraction of table entry 0x%08x (%p %d) failed with %d", pBlock->fSpecification, pBlock->fPtr, pBlock->fSize, iResult);
+ }
+ iResult=0;
+ }
+
+ if (newFolders.size()>0) {
+ vector<TFolder*> revert;
+ vector<TFolder*>::iterator iter=newFolders.begin();
+ while (iter!=newFolders.end()) {
+ revert.insert(revert.begin(), *iter);
+ HLTDebug("%s", (*iter)->GetName());
+ iter++;
+ }
+ newFolders.empty();
+ newFolders.assign(revert.begin(), revert.end());
+
+ vector<TFolder*>::iterator publisher=newFolders.begin();
+ while (publisher!=newFolders.end()) {
+ bool bRemove=false;
+ HLTDebug("checking %s for parents", (*publisher)->GetName());
+ TFolder* propsFolder=dynamic_cast<TFolder*>((*publisher)->FindObject(HLTSTAT_ENTRY_PROPS_FOLDER_NAME));
+ assert(propsFolder);
+ TObject* idobj=NULL;
+ if (propsFolder) idobj=propsFolder->FindObject(HLTSTAT_ENTRY_PROPS_IDOBJ_NAME);
+ assert(idobj);
+ AliHLTUInt32_t crcid=idobj->GetUniqueID();
+ TString idstr; idstr.Form("0x%08x", crcid);
+ if (idobj) {
+ for (vector<TFolder*>::iterator consumer=publisher+1;
+ consumer!=newFolders.end(); consumer++) {
+ HLTDebug(" checking %s", (*consumer)->GetName());
+ TFolder* parentFolder=dynamic_cast<TFolder*>((*consumer)->FindObject(HLTSTAT_ENTRY_PARENT_FOLDER_NAME));
+ assert(parentFolder);
+ if (parentFolder) {
+ TIter entries(parentFolder->GetListOfFolders());
+ while (TObject* entry=entries.Next())
+ if (entry) {
+ Bool_t foo; foo=kTRUE;// only to avoid warning in non-debug compile
+ HLTDebug(" searching %s in %s: %s", idstr.Data(), (*consumer)->GetName(), entry->GetName());
+ }
+ TObject* parent=parentFolder->FindObjectAny(idstr);
+ if (parent) {
+ parentFolder->Add(*publisher);
+ parentFolder->Remove(parent);
+ bRemove=true;
+ }
+ }
+ }
+ }
+ if (bRemove) publisher=newFolders.erase(publisher);
+ else publisher++;
+ }
+
+ for (publisher=newFolders.begin();
+ publisher!=newFolders.end(); publisher++) {
+ RemoveRecurrence(*publisher);
+ fpFolder->Add(*publisher);
+ }
+ }
+
int blockNo=0;
for (const AliHLTComponentBlockData* pBlock=GetFirstInputBlock(kAliHLTDataTypeComponentStatistics);
pBlock && iResult>=0;
pBlock=GetNextInputBlock(), blockNo++) {
unsigned int current=fPosition;
- iResult=FillVariablesSorted(pBlock->fPtr, pBlock->fSize);
+ iResult=FillVariablesSorted(pBlock->fPtr, pBlock->fSize, eventType);
for (; current<fPosition; current++) {
fpSpecArray[current]=pBlock->fSpecification;
fpBlockNoArray[current]=blockNo;
}
+ // indicate availability of component statistic block
+ iResult=1;
}
- if (iResult>=0) {
+ int totalOutputSize=0;
+ if (iResult>0 && eventType) {
fNofSets=fPosition;
fpStatTree->Fill();
- iResult=PushBack(fpStatTree, kAliHLTDataTypeTTree);
+
+ // init the timer for the next cycle
+ if (!fpTimer) fpTimer=new TStopwatch;
+ if (fpTimer) {
+ fpTimer->Reset();
+ fpTimer->Start();
+ }
}
- // init the timer for the next cycle
- if (!fpTimer) fpTimer=new TStopwatch;
- if (fpTimer) {
- fpTimer->Reset();
- fpTimer->Start();
+ if (eventType==gkAliEventTypeEndOfRun ||
+ (iResult>=0 && CheckPeriod())) {
+
+ // publish objects to component output
+ if ((fMode&kPublishObjects)!=0) {
+ if (!bEmbeddedTree) {
+ iResult=PushBack(fpStatTree, kAliHLTDataTypeTTree|kAliHLTDataOriginOut);
+ totalOutputSize+=GetLastObjectSize();
+ }
+ iResult=PushBack(fpFolder, kAliHLTDataTypeTObject|kAliHLTDataOriginOut);
+ totalOutputSize+=GetLastObjectSize();
+ }
+
+ // save objects to file
+ if ((fMode&kSaveObjects)!=0 && fFile!=NULL) {
+ HLTDebug("saving objects to file %s", fFileName.c_str());
+ fFile->cd();
+ if (!bEmbeddedTree) {
+ fpStatTree->Write("", TObject::kOverwrite);
+ }
+ fpFolder->Write("", TObject::kOverwrite);
+ }
}
+ if (iResult==-ENOSPC) {
+ fSizeEstimator+=totalOutputSize;
+ }
+
+ if (iResult>0) iResult=0;
return iResult;
}
memset(fpCTimeArray, 0, sizeof(UInt_t)*fArraySize);
memset(fpInputBlockCountArray, 0, sizeof(UInt_t)*fArraySize);
memset(fpTotalInputSizeArray, 0, sizeof(UInt_t)*fArraySize);
+ memset(fpNormalizedInputSizeArray, 0, sizeof(UInt_t)*fArraySize);
memset(fpOutputBlockCountArray, 0, sizeof(UInt_t)*fArraySize);
memset(fpTotalOutputSizeArray, 0, sizeof(UInt_t)*fArraySize);
+ memset(fpInputOutputRatioArray, 0, sizeof(UInt_t)*fArraySize);
+ memset(fpNormalizedInputOutputRatioArray, 0, sizeof(UInt_t)*fArraySize);
+ memset(fpComponentCycleTimeArray, 0, sizeof(UInt_t)*fArraySize);
+ memset(fpEventTypeArray, 0, sizeof(UInt_t)*fArraySize);
+ memset(fpEventCountArray, 0, sizeof(UInt_t)*fArraySize);
}
-int AliHLTCompStatCollector::FillVariablesSorted(void* ptr, int size)
+int AliHLTCompStatCollector::FillVariablesSorted(void* ptr, int size, AliHLTUInt32_t eventType)
{
// see header file for class documentation
int iResult=0;
if (size%sizeof(AliHLTComponentStatistics)) {
+ // older or invalid structure
HLTError("data block is not aligned to the size of the AliHLTComponentStatistics struct");
return -EINVAL;
}
+
AliHLTComponentStatistics* pStat=reinterpret_cast<AliHLTComponentStatistics*>(ptr);
UInt_t nofStats=size/sizeof(AliHLTComponentStatistics);
vector<int> indexList;
fpCTimeArray[i]=pStat[*element].fCTime;
fpInputBlockCountArray[i]=pStat[*element].fInputBlockCount;
fpTotalInputSizeArray[i]=pStat[*element].fTotalInputSize;
+ fpNormalizedInputSizeArray[i]=pStat[*element].fTotalInputSize;
+ if (pStat[*element].fInputBlockCount>0)
+ fpNormalizedInputSizeArray[i]/=pStat[*element].fInputBlockCount;
fpOutputBlockCountArray[i]=pStat[*element].fOutputBlockCount;
fpTotalOutputSizeArray[i]=pStat[*element].fTotalOutputSize;
+ if (pStat[*element].fTotalOutputSize>0)
+ fpInputOutputRatioArray[i]=pStat[*element].fTotalInputSize/pStat[*element].fTotalOutputSize;
+ if (pStat[*element].fInputBlockCount>0)
+ fpNormalizedInputOutputRatioArray[i]=fpInputOutputRatioArray[i]*pStat[*element].fOutputBlockCount/pStat[*element].fInputBlockCount;
+ fpComponentCycleTimeArray[i]=pStat[*element].fComponentCycleTime;
+ fpEventTypeArray[i]=eventType;
+ fpEventCountArray[i]=GetEventCount();
+ } else {
+ // TODO: dynamically grow arrays with placement new
}
}
void AliHLTCompStatCollector::ClearAll()
{
+ // see header file for class documentation
if (fpTimer) delete fpTimer; fpTimer=NULL;
+ if (fpFolder) delete fpFolder; fpFolder=NULL;
if (fpStatTree) delete fpStatTree; fpStatTree=NULL;
if (fpLevelArray) delete fpLevelArray; fpLevelArray=NULL;
if (fpSpecArray) delete fpSpecArray; fpSpecArray=NULL;
if (fpCTimeArray) delete fpCTimeArray; fpCTimeArray=NULL;
if (fpInputBlockCountArray) delete fpInputBlockCountArray; fpInputBlockCountArray=NULL;
if (fpTotalInputSizeArray) delete fpTotalInputSizeArray; fpTotalInputSizeArray=NULL;
+ if (fpNormalizedInputSizeArray) delete fpNormalizedInputSizeArray; fpNormalizedInputSizeArray=NULL;
if (fpOutputBlockCountArray) delete fpOutputBlockCountArray; fpOutputBlockCountArray=NULL;
if (fpTotalOutputSizeArray) delete fpTotalOutputSizeArray; fpTotalOutputSizeArray=NULL;
+ if (fpInputOutputRatioArray) delete fpInputOutputRatioArray; fpInputOutputRatioArray=NULL;
+ if (fpNormalizedInputOutputRatioArray) delete fpNormalizedInputOutputRatioArray; fpNormalizedInputOutputRatioArray=NULL;
+ if (fpComponentCycleTimeArray) delete fpComponentCycleTimeArray; fpComponentCycleTimeArray=NULL;
+ if (fpEventTypeArray) delete fpEventTypeArray; fpEventTypeArray=NULL;
+ if (fpEventCountArray) delete fpEventCountArray; fpEventCountArray=NULL;
+}
+
+int AliHLTCompStatCollector::RemoveRecurrence(TFolder* pRoot) const
+{
+ // see header file for class documentation
+ int iResult=0;
+ if (!pRoot) return -EINVAL;
+ TFolder* parentFolder=dynamic_cast<TFolder*>(pRoot->FindObject(HLTSTAT_ENTRY_PARENT_FOLDER_NAME));
+ assert(parentFolder);
+ vector<TFolder*> listRemove;
+ if (parentFolder) {
+ TIter entries(parentFolder->GetListOfFolders());
+ TFolder* entry=NULL;
+ TObject* obj=NULL;
+ while ((obj=entries.Next())!=NULL && (entry=dynamic_cast<TFolder*>(obj))!=NULL) {
+ TString name=entry->GetName();
+ HLTDebug("checking %s for recurrence", name.Data());
+ TIter tokens(parentFolder->GetListOfFolders());
+ TFolder* token=NULL;
+ while ((obj=tokens.Next())!=NULL && (token=dynamic_cast<TFolder*>(obj))!=NULL) {
+ if (name.CompareTo(token->GetName())==0) continue;
+ if ((obj=token->FindObjectAny(name))!=NULL) {
+ listRemove.push_back(entry);
+ HLTDebug("found recurrence in %s", token->GetName());
+ break;
+ } else {
+ HLTDebug("no recurrence found in %s", token->GetName());
+ }
+ }
+ RemoveRecurrence(entry);
+ }
+ for (vector<TFolder*>::iterator removeElement=listRemove.begin();
+ removeElement!=listRemove.end(); removeElement++) {
+ parentFolder->Remove(*removeElement);
+ }
+ }
+
+ return iResult;
+}
+
+bool AliHLTCompStatCollector::CheckPeriod(bool bUpdate)
+{
+ // see header file for class documentation
+ bool result=true;
+ if (fEventModulo>0) {
+ if ((result=((GetEventCount()+1)%fEventModulo)==0)) {
+ return true;
+ }
+ }
+ if (fPeriod>0) {
+ if ((result=((difftime(time(NULL), fLastTime)>(double)fPeriod))) &&
+ bUpdate) {
+ fLastTime=time(NULL);
+ }
+ }
+ return result;
}