#include "TObjectTable.h"
#include "TClass.h"
#include "TStopwatch.h"
+#include "TFormula.h"
#include "AliHLTMemoryFile.h"
#include "AliHLTMisc.h"
#include <cassert>
fEventDoneDataSize(0),
fCompressionLevel(ALIHLTCOMPONENT_DEFAULT_OBJECT_COMPRESSION)
, fLastObjectSize(0)
+ , fpTriggerClasses(NULL)
{
// see header file for class documentation
// or
}
if (fEventDoneData)
delete [] reinterpret_cast<AliHLTUInt8_t*>( fEventDoneData );
+ fEventDoneData=NULL;
+
+ if (fpTriggerClasses) {
+ fpTriggerClasses->Delete();
+ delete fpTriggerClasses;
+ }
+ fpTriggerClasses=NULL;
}
AliHLTComponentHandler* AliHLTComponent::fgpComponentHandler=NULL;
int iResult=0;
iResult=DoDeinit();
if (fpRunDesc) {
- HLTWarning("did not receive EOR for run %d", fpRunDesc->fRunNo);
+ // TODO: the warning should be kept, but the condition is wrong since the
+ // AliHLTRunDesc is set before the SOR event in the SetRunDescription
+ // method. A couple of state flags should be defined but that is a bit more
+ // work to do. For the moment disable the warning (2009-07-01)
+ //HLTWarning("did not receive EOR for run %d", fpRunDesc->fRunNo);
AliHLTRunDesc* pRunDesc=fpRunDesc;
fpRunDesc=NULL;
delete pRunDesc;
}
+ if (fpTriggerClasses) {
+ fpTriggerClasses->Delete();
+ delete fpTriggerClasses;
+ }
+ fpTriggerClasses=NULL;
+
fEventCount=0;
return iResult;
}
int indexUpdtDCSEvent=-1;
int indexSOREvent=-1;
int indexEOREvent=-1;
+ int indexECSParamBlock=-1;
for (unsigned int i=0; i<evtData.fBlockCnt && iResult>=0; i++) {
if (fpInputBlocks[i].fDataType==kAliHLTDataTypeSOR) {
indexSOREvent=i;
} else if (fpInputBlocks[i].fDataType==kAliHLTDataTypeComponentTable) {
forwardedBlocks.push_back(fpInputBlocks[i]);
parentComponentTables.push_back(fpInputBlocks[i].fSpecification);
+ } else if (fpInputBlocks[i].fDataType==kAliHLTDataTypeECSParam) {
+ indexECSParamBlock=i;
} else {
// the processing function is called if there is at least one
// non-steering data block. Steering blocks are not filtered out
} else {
iResult=-ENOMEM;
}
+
+ if (indexECSParamBlock>=0) {
+ if (fpInputBlocks[indexECSParamBlock].fSize>0) {
+ const char* param=reinterpret_cast<const char*>(fpInputBlocks[indexECSParamBlock].fPtr);
+ TString paramString;
+ if (param[fpInputBlocks[indexECSParamBlock].fSize-1]!=0) {
+ HLTWarning("ECS parameter string not terminated");
+ paramString.Insert(0, param, fpInputBlocks[indexECSParamBlock].fSize);
+ paramString+="";
+ } else {
+ paramString=param;
+ }
+ ScanECSParam(paramString.Data());
+ } else {
+ HLTWarning("empty ECS parameter received");
+ }
+ } else {
+ // TODO: later on we might throw a warning here since the CTP trigger classes
+ // should be mandatory
+ }
}
if (indexEOREvent>=0) {
bAddComponentTableEntry=true;
return iResult;
}
+
+int AliHLTComponent::ScanECSParam(const char* ecsParam)
+{
+ // see header file for function documentation
+
+ // format of the parameter string from ECS
+ // <command>;<parameterkey>=<parametervalue>;<parameterkey>=<parametervalue>;...
+ // search for a subset of the parameterkeys
+ int iResult=0;
+ TString string=ecsParam;
+ TObjArray* parameter=string.Tokenize(";");
+ if (parameter) {
+ for (int i=0; i<parameter->GetEntries(); i++) {
+ TString entry=((TObjString*)parameter->At(i))->GetString();
+ HLTDebug("scanning ECS entry: %s", entry.Data());
+ TObjArray* entryParams=entry.Tokenize("=");
+ if (entryParams) {
+ if (entryParams->GetEntries()>1) {
+ if ((((TObjString*)entryParams->At(0))->GetString()).CompareTo("CTP_TRIGGER_CLASS")==0) {
+ int result=InitCTPTriggerClasses((((TObjString*)entryParams->At(1))->GetString()).Data());
+ if (iResult>=0 && result<0) iResult=result;
+ } else {
+ // TODO: scan the other parameters
+ // e.g. consistency check of run number
+ }
+ }
+ delete entryParams;
+ }
+ }
+ delete parameter;
+ }
+
+ return iResult;
+}
+
+int AliHLTComponent::InitCTPTriggerClasses(const char* ctpString)
+{
+ // see header file for function documentation
+ if (!ctpString) return -EINVAL;
+
+ if (fpTriggerClasses) {
+ fpTriggerClasses->Delete();
+ } else {
+ fpTriggerClasses=new TObjArray(gkNCTPTriggerClasses);
+ }
+ if (!fpTriggerClasses) return -ENOMEM;
+
+ // general format of the CTP_TRIGGER_CLASS parameter
+ // <bit position>:<Trigger class identifier string>:<detector-id-nr>-<detector-id-nr>-...,<bit position>:<Trigger class identifier string>:<detector-id-nr>-<detector-id-nr>-...,...
+ // the detector ids are ignored for the moment
+ HLTDebug(": %s", ctpString);
+ TString string=ctpString;
+ TObjArray* classEntries=string.Tokenize(",");
+ if (classEntries) {
+ for (int i=0; i<classEntries->GetEntries(); i++) {
+ TString entry=((TObjString*)classEntries->At(i))->GetString();
+ TObjArray* entryParams=entry.Tokenize(":");
+ if (entryParams) {
+ if (entryParams->GetEntries()==3 &&
+ (((TObjString*)entryParams->At(0))->GetString()).IsDigit()) {
+ int index=(((TObjString*)entryParams->At(0))->GetString()).Atoi();
+ if (index<gkNCTPTriggerClasses) {
+ fpTriggerClasses->AddAt(new TNamed("TriggerClass", (((TObjString*)entryParams->At(1))->GetString()).Data()), index);
+ } else {
+ // the trigger bitfield is fixed to 50 bits (gkNCTPTriggerClasses)
+ HLTError("invalid trigger class entry %s, index width of trigger bitfield", entry.Data());
+ }
+ } else {
+ HLTError("invalid trigger class entry %s", entry.Data());
+ }
+ delete entryParams;
+ }
+ }
+ delete classEntries;
+ }
+ return 0;
+}
+
+bool AliHLTComponent::EvaluateCTPTriggerClass(const char* expression, AliHLTComponentTriggerData& trigData) const
+{
+ // see header file for function documentation
+ if (!fpTriggerClasses) {
+ HLTError("trigger classes not initialized");
+ return false;
+ }
+
+ if (trigData.fDataSize != sizeof(AliHLTEventTriggerData)) {
+ HLTError("invalid trigger data size: %d expected %d", trigData.fDataSize, sizeof(AliHLTEventTriggerData));
+ return false;
+ }
+
+ // trigger mask is 50 bit wide and is stored in word 5 and 6 of the CDH
+ AliHLTEventTriggerData* evtData=reinterpret_cast<AliHLTEventTriggerData*>(trigData.fData);
+ AliHLTUInt64_t triggerMask=evtData->fCommonHeader[6];
+ triggerMask<<=32;
+ triggerMask|=evtData->fCommonHeader[5];
+
+ // use a TFormula to interprete the expression
+ // all classname are replaced by '[n]' which means the n'th parameter in the formula
+ // the parameters are set to 0 or 1 depending on the bit in the trigger mask
+ //
+ // TODO: this will most likely fail for class names like 'base', 'baseA', 'baseB'
+ // the class names must be fully unique, none must be contained as substring in
+ // another class name. Probably not needed for the moment but needs to be extended.
+ vector<Double_t> par;
+ TString condition=expression;
+ for (int i=0; i<gkNCTPTriggerClasses; i++) {
+ if (fpTriggerClasses->At(i)) {
+ TString className=fpTriggerClasses->At(i)->GetTitle();
+ //HLTDebug("checking trigger class %s", className.Data());
+ if (condition.Contains(className)) {
+ TString replace; replace.Form("[%d]", par.size());
+ //HLTDebug("replacing %s with %s in \"%s\"", className.Data(), replace.Data(), condition.Data());
+ condition.ReplaceAll(className, replace);
+ if (triggerMask&((AliHLTUInt64_t)0x1<<i)) par.push_back(1.0);
+ else par.push_back(0.0);
+ }
+ }
+ }
+
+ TFormula form("trigger expression", condition);
+ if (form.Compile()!=0) {
+ HLTError("invalid expression %s", expression);
+ return false;
+ }
+ if (form.EvalPar(&par[0], &par[0])>0.5) return true;
+ return false;
+}
--- /dev/null
+// $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 testAliHLTComponent_CTPTrigger.C
+ @author Matthias Richter
+ @date
+ @brief Test program for default data types
+ */
+
+#ifndef __CINT__
+#include "TDatime.h"
+#include "TRandom.h"
+#include "AliHLTDataTypes.h"
+#include "AliHLTProcessor.h"
+#endif
+
+class AliHLTTestComponent : public AliHLTProcessor
+{
+public:
+ AliHLTTestComponent() {}
+ ~AliHLTTestComponent() {}
+
+ const char* GetComponentID() {return "TestComponent";};
+ void GetInputDataTypes(AliHLTComponentDataTypeList& list) {list.clear();}
+ AliHLTComponentDataType GetOutputDataType() {return kAliHLTAnyDataType;}
+ void GetOutputDataSize(unsigned long& constBase, double& inputMultiplier) {constBase=0; inputMultiplier=0;}
+ AliHLTComponent* Spawn() {return new AliHLTTestComponent;}
+
+ int InitTest(const char* param) {
+ return ScanECSParam(param);
+ //return InitCTPTriggerClasses(param);
+ }
+
+ bool Check(const char* expression, AliHLTComponentTriggerData* data) {
+ return EvaluateCTPTriggerClass(expression, *data);
+ }
+
+ class AliHLTCTPTriggerClass {
+ public:
+ AliHLTCTPTriggerClass() : fBit(~(unsigned)0), fClassName(""), fTrigger(false) {}
+ ~AliHLTCTPTriggerClass() {}
+
+ bool Valid() {return fBit!=~(unsigned)0;}
+ unsigned Bit() {return fBit;}
+ void Bit(unsigned bit) {fBit=bit;}
+ bool Trigger() {return fTrigger;}
+ void Trigger(bool trigger) {fTrigger=trigger;}
+ const char* ClassName() {return fClassName.c_str();}
+ void ClassName(const char* classname) {fClassName=classname;}
+ private:
+ unsigned fBit;
+ string fClassName;
+ bool fTrigger;
+ };
+protected:
+ int DoInit(int /*argc*/, const char** /*argv*/) {
+ return 0;
+ }
+
+ int DoDeinit() {
+ return 0;
+ }
+
+ int DoEvent( const AliHLTComponentEventData& /*evtData*/,
+ AliHLTComponentTriggerData& /*trigData*/) {
+ return 0;
+ }
+};
+
+class AliHLTTriggerDataAccess
+{
+public:
+ AliHLTTriggerDataAccess()
+ : fData(NULL)
+ , fEventData(NULL)
+ , fCDH(NULL)
+ , fMine(NULL)
+ {
+ unsigned size=sizeof(AliHLTComponentTriggerData) + sizeof(AliHLTEventTriggerData);
+ fMine=new Byte_t[size];
+ memset(fMine, 0, size);
+ AliHLTComponentTriggerData* data=reinterpret_cast<AliHLTComponentTriggerData*>(fMine);
+ data->fData=fMine+sizeof(AliHLTComponentTriggerData);
+ Set(data);
+ }
+
+ AliHLTTriggerDataAccess(AliHLTComponentTriggerData* pData)
+ : fData(NULL)
+ , fEventData(NULL)
+ , fCDH(NULL)
+ , fMine(NULL)
+ {
+ if (fMine) delete [] fMine;
+ fMine=NULL;
+ Set(pData);
+ }
+
+ ~AliHLTTriggerDataAccess(){
+ if (fMine) delete [] fMine;
+ fMine=NULL;
+ fData=NULL;
+ fEventData=NULL;
+ fCDH=NULL;
+ }
+
+ AliHLTComponentTriggerData* Data() {return fData;}
+
+ Long64_t TriggerMask() {
+ Long64_t mask=0;
+ if (fCDH) {
+ mask=fCDH[6];
+ mask<<=32;
+ mask|=fCDH[5];
+ }
+ return mask;
+ }
+
+ int Set(AliHLTComponentTriggerData* data) {
+ fData=data;
+ fData->fDataSize=sizeof(AliHLTEventTriggerData);
+ fEventData=reinterpret_cast<AliHLTEventTriggerData*>(fData->fData);
+ fCDH=fEventData->fCommonHeader;
+ return 0;
+ }
+
+ int ResetCDH() {
+ if (fCDH) {
+ memset(fCDH, 0, 32);
+ }
+ return 0;
+ }
+
+ int TriggerBit(unsigned bit, bool set) {
+ if ((int)bit>=gkNCTPTriggerClasses) return -EINVAL;
+ if (!fCDH) return -ENODATA;
+
+ int word=5;
+ if (bit>=32) {
+ word++;
+ bit-=32;
+ }
+ if (set)
+ fCDH[word]|=(UInt_t)0x1<<bit;
+ else
+ fCDH[word]&=~((UInt_t)0x1<<bit);
+
+ return bit;
+ }
+
+private:
+ AliHLTTriggerDataAccess(const AliHLTTriggerDataAccess&);
+ AliHLTTriggerDataAccess& operator=(const AliHLTTriggerDataAccess&);
+
+ AliHLTComponentTriggerData* fData;
+ AliHLTEventTriggerData* fEventData;
+ AliHLTUInt32_t* fCDH;
+ Byte_t* fMine;
+};
+
+/**
+ * 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);
+}
+
+/**
+ * Generate a random name of given length
+ */
+string GenerateTriggerClassName(int length)
+{
+ string tcn;
+ for (int i=0; i<length; i++) {
+ unsigned char c=GetRandom(48, 83);
+ if (c>57) c+=7;
+ tcn+=c;
+ }
+ return tcn;
+}
+
+/**
+ * Generate an array of trigger classes.
+ * The array has the specified size but the number antries which are actually
+ * filled is randomized.
+ */
+int GenerateTriggerClasses(int size, vector<AliHLTTestComponent::AliHLTCTPTriggerClass>& classes)
+{
+ classes.clear();
+ classes.resize(size);
+ unsigned count=GetRandom(4, size>16?size/2:size);
+ for (unsigned i=0; i<count; i++) {
+ int bit=0;
+ do {
+ bit=GetRandom(0, size);
+ } while (classes[bit].Valid());
+ classes[bit].Bit(bit);
+ classes[bit].ClassName((GenerateTriggerClassName(GetRandom(5,15))).c_str());
+ }
+ return classes.size();
+}
+
+int testAliHLTComponent_CTPTrigger()
+{
+ int iResult=0;
+ vector<AliHLTTestComponent::AliHLTCTPTriggerClass> triggerClasses;
+ if (GenerateTriggerClasses(GetRandom(5,gkNCTPTriggerClasses), triggerClasses)<=0) {
+ return -1;
+ }
+
+ TString parameter="CONFIGURE;CTP_TRIGGER_CLASS=";
+ vector<AliHLTTestComponent::AliHLTCTPTriggerClass>::iterator element=triggerClasses.begin();
+ while (element!=triggerClasses.end()) {
+ if (!element->Valid()) {
+ element=triggerClasses.erase(element);
+ continue;
+ }
+ if (!parameter.EndsWith("=")) parameter+=",";
+ parameter+=element->Bit(); parameter+=":";
+ parameter+=element->ClassName(); parameter+=":";
+ parameter+=0;
+ element++;
+ }
+ parameter+=";HLT_MODE=A;RUN_NO=0";
+
+ AliHLTTestComponent component;
+ component.SetGlobalLoggingLevel(kHLTLogDefault);
+ if ((iResult=component.InitTest(parameter.Data()))<0) return iResult;
+
+ AliHLTTriggerDataAccess trigData;
+ for (int cycle=0; cycle<500 && iResult>=0; cycle++) {
+ for (element=triggerClasses.begin();
+ element!=triggerClasses.end(); element++) {
+ element->Trigger(GetRandom(0,100)>50);
+ }
+
+ vector<AliHLTTestComponent::AliHLTCTPTriggerClass> shuffle;
+ shuffle.assign(triggerClasses.begin(), triggerClasses.end());
+ for (unsigned int trial=0; trial<2*triggerClasses.size() && iResult>=0; trial++) {
+ random_shuffle(shuffle.begin(), shuffle.end());
+
+ bool result=0;
+ bool trigger=0;
+ TString expression;
+ trigData.ResetCDH();
+ for (element=shuffle.begin();
+ element!=shuffle.end(); element++) {
+ trigData.TriggerBit(element->Bit(), element->Trigger());
+ }
+
+ // single class
+ for (element=shuffle.begin();
+ element!=shuffle.end() && iResult>=0 && trial<3;
+ element++) {
+ // is
+ result=element->Trigger();
+ expression=element->ClassName();
+ trigger=component.Check(expression.Data(), trigData.Data());
+ if (trigger!=result) {
+ cout << expression << ": " << element->Trigger()
+ << "->" << trigger
+ << std::hex << " (" << trigData.TriggerMask() << ")"
+ << endl;
+ cerr << "trigger does not match, expected " << result << endl;
+ iResult=-1;
+ break;
+ }
+
+ // is not
+ expression="!";
+ expression+=element->ClassName();
+ result=!result;
+ trigger=component.Check(expression.Data(), trigData.Data());
+ if (trigger!=result) {
+ cout << expression << ": " << element->Trigger()
+ << "->" << trigger
+ << std::hex << " (" << trigData.TriggerMask() << ")"
+ << endl;
+ cerr << "trigger does not match, expected " << result << endl;
+ iResult=-1;
+ break;
+ }
+ }
+
+ // OR
+ result=shuffle[0].Trigger() || shuffle[1].Trigger() || shuffle[2].Trigger();
+ expression.Form("%s || %s || %s",
+ shuffle[0].ClassName(), shuffle[1].ClassName(), shuffle[2].ClassName());
+ trigger=component.Check(expression.Data(), trigData.Data());
+ if (trigger!=result) {
+ cout << expression << ": " << shuffle[0].Trigger() << shuffle[1].Trigger() << shuffle[2].Trigger()
+ << "->" << trigger
+ << std::hex << " (" << trigData.TriggerMask() << ")"
+ << endl;
+ cerr << "trigger does not match, expected " << result << endl;
+ iResult=-1;
+ break;
+ }
+
+ // AND
+ result=shuffle[0].Trigger() && shuffle[1].Trigger() && shuffle[2].Trigger();
+ expression.Form("%s && %s && %s",
+ shuffle[0].ClassName(), shuffle[1].ClassName(), shuffle[2].ClassName());
+
+ trigger=component.Check(expression.Data(), trigData.Data());
+ if (trigger!=result) {
+ cout << expression << ": " << shuffle[0].Trigger() << shuffle[1].Trigger() << shuffle[2].Trigger()
+ << "->" << trigger
+ << std::hex << " (" << trigData.TriggerMask() << ")"
+ << endl;
+ cerr << "trigger does not match, expected " << result << endl;
+ iResult=-1;
+ break;
+ }
+
+ // mixed OR/AND
+ result=shuffle[0].Trigger() && (shuffle[1].Trigger() || shuffle[2].Trigger());
+ expression.Form("%s && (%s || %s)",
+ shuffle[0].ClassName(), shuffle[1].ClassName(), shuffle[2].ClassName());
+
+ trigger=component.Check(expression.Data(), trigData.Data());
+ if (trigger!=result) {
+ cout << expression << ": " << shuffle[0].Trigger() << shuffle[1].Trigger() << shuffle[2].Trigger()
+ << "->" << trigger
+ << std::hex << " (" << trigData.TriggerMask() << ")"
+ << endl;
+ cerr << "trigger does not match, expected " << result << endl;
+ iResult=-1;
+ break;
+ }
+ }
+ }
+ if (iResult<0) {
+ cerr << "check failed, dumping info" << endl;
+ cerr << "ECS param: " << parameter << endl;
+ for (element=triggerClasses.begin();
+ element!=triggerClasses.end(); element++) {
+ cerr << element->Trigger() << " " << element->Bit() << ": " << element->ClassName() << endl;
+ }
+ }
+ return iResult;
+}
+
+int main(int /*argc*/, const char** /*argv*/)
+{
+ int iResult=0;
+ iResult=testAliHLTComponent_CTPTrigger();
+ return iResult;
+}