3 //**************************************************************************
4 //* This file is property of and copyright by the ALICE HLT Project *
5 //* ALICE Experiment at CERN, All rights reserved. *
7 //* Primary Authors: Matthias Richter <Matthias.Richter@ift.uib.no> *
8 //* for The ALICE HLT Project. *
10 //* Permission to use, copy, modify and distribute this software and its *
11 //* documentation strictly for non-commercial purposes is hereby granted *
12 //* without fee, provided that the above copyright notice appears in all *
13 //* copies and that both the copyright notice and this permission notice *
14 //* appear in the supporting documentation. The authors make no claims *
15 //* about the suitability of this software for any purpose. It is *
16 //* provided "as is" without express or implied warranty. *
17 //**************************************************************************
19 /** @file AliHLTOUTComponent.cxx
20 @author Matthias Richter
22 @brief The HLTOUT data sink component similar to HLTOUT nodes
31 #include "AliHLTOUTComponent.h"
32 #include "AliHLTOUT.h"
33 #include "AliHLTHOMERLibManager.h"
34 #include "AliHLTHOMERWriter.h"
35 #include "AliDAQ.h" // equipment Ids
36 #include "AliRawDataHeader.h" // Common Data Header
37 #include <TDatime.h> // seed for TRandom
38 #include <TRandom.h> // random int generation for DDL no
43 /** ROOT macro for the implementation of ROOT specific class methods */
44 ClassImp(AliHLTOUTComponent)
46 AliHLTOUTComponent::AliHLTOUTComponent()
48 AliHLTOfflineDataSink(),
51 fIdFirstDDL(7680), // 0x1e<<8
60 // see header file for class documentation
62 // refer to README to build package
64 // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
66 // I guess DDL definitions should never change any more
67 assert(fNofDDLs==AliDAQ::NumberOfDdls("HLT"));
68 fNofDDLs=AliDAQ::NumberOfDdls("HLT");
70 /* AliDAQ::DdlIDOffset returns wrong offset for HLT links
71 assert(fIdFirstDDL==AliDAQ::DdlIDOffset("HLT"));
72 fIdFirstDDL=AliDAQ::DdlIDOffset("HLT");
76 int AliHLTOUTComponent::fgOptions=kWriteRawFiles|kWriteDigits;
78 AliHLTOUTComponent::~AliHLTOUTComponent()
80 // see header file for class documentation
81 if (fpLibManager) delete fpLibManager;
85 const char* AliHLTOUTComponent::GetComponentID()
87 // see header file for class documentation
91 void AliHLTOUTComponent::GetInputDataTypes( vector<AliHLTComponentDataType>& list)
93 // see header file for class documentation
95 list.push_back(kAliHLTAnyDataType);
98 AliHLTComponent* AliHLTOUTComponent::Spawn()
100 // see header file for class documentation
101 return new AliHLTOUTComponent;
104 int AliHLTOUTComponent::DoInit( int argc, const char** argv )
106 // see header file for class documentation
110 for (int i=0; i<argc && iResult>=0; i++) {
112 if (argument.IsNull()) continue;
115 if (argument.CompareTo("-links")==0) {
116 if ((bMissingParam=(++i>=argc))) break;
117 TString parameter(argv[i]);
118 parameter.Remove(TString::kLeading, ' '); // remove all blanks
119 if (parameter.IsDigit()) {
120 fNofDDLs=parameter.Atoi();
122 HLTError("wrong parameter for argument %s, number expected", argument.Data());
126 HLTError("unknown argument %s", argument.Data());
132 HLTError("missing parameter for argument %s", argument.Data());
138 fpLibManager=new AliHLTHOMERLibManager;
141 for (writerNo=0; writerNo<fNofDDLs; writerNo++) {
142 AliHLTMonitoringWriter* pWriter=fpLibManager->OpenWriter();
144 HLTDebug("HOMER writer %p added", pWriter);
145 fWriters.push_back(pWriter);
147 HLTError("can not open HOMER writer");
159 int AliHLTOUTComponent::DoDeinit()
161 // see header file for class documentation
165 AliHLTMonitoringWriterPVector::iterator element=fWriters.begin();
166 while (element!= fWriters.end()) {
168 // wanted to have a dynamic_cast<AliHLTHOMERWriter*> here, but this results into
169 // undefined symbol when loading the library
171 if (*element!=NULL) fpLibManager->DeleteWriter((AliHLTHOMERWriter*)(*element));
172 element=fWriters.erase(element);
182 fpDigitFile->Close();
187 if (fppDigitArrays) {
188 for (int i=0; i<fNofDDLs; i++) {
189 if (fppDigitArrays[i]) delete fppDigitArrays[i];
191 delete[] fppDigitArrays;
198 int AliHLTOUTComponent::DumpEvent( const AliHLTComponentEventData& evtData,
199 const AliHLTComponentBlockData* blocks,
200 AliHLTComponentTriggerData& /*trigData*/ )
202 // see header file for class documentation
204 HLTInfo("write %d output block(s)", evtData.fBlockCnt);
206 AliHLTUInt32_t eventType=gkAliEventTypeUnknown;
207 bool bIsDataEvent=IsDataEvent(&eventType);
209 homer_uint64 homerHeader[kCount_64b_Words];
210 HOMERBlockDescriptor homerDescriptor(homerHeader);
211 for (int n=0; n<(int)evtData.fBlockCnt; n++ ) {
212 if (blocks[n].fDataType==kAliHLTDataTypeEvent ||
213 blocks[n].fDataType==kAliHLTDataTypeSOR ||
214 blocks[n].fDataType==kAliHLTDataTypeEOR ||
215 blocks[n].fDataType==kAliHLTDataTypeComConf ||
216 blocks[n].fDataType==kAliHLTDataTypeUpdtDCS)
218 // the special events have to be ignored.
222 (blocks[n].fDataType!=kAliHLTDataTypeComponentTable))
224 // In simulation, there are no SOR and EOR events created. Thats
225 // why all data blocks of those events are currently ignored.
226 // Strictly speaking, components should not create output blocks
227 // on the SOR/EOR event
229 // Exeptions: some blocks are added, the buffer must be prepared and
230 // kept since the pointers will be invalid
231 // - kAliHLTDataTypeComponentTable component table entries
234 memset( homerHeader, 0, sizeof(homer_uint64)*kCount_64b_Words );
235 homerDescriptor.Initialize();
236 // for some traditional reason the TCPDumpSubscriber swaps the bytes
237 // of the data type id and data type origin. Actually I do not understand
238 // the corresponding code line
239 // homerBlock.SetType( blocks[n].fDataType.fID );
240 // this compiles in the PubSub framework and in addition does a byte swap
242 homer_uint64 origin=0;
243 memcpy(&id, blocks[n].fDataType.fID, sizeof(homer_uint64));
244 memcpy(((AliHLTUInt8_t*)&origin)+sizeof(homer_uint32), blocks[n].fDataType.fOrigin, sizeof(homer_uint32));
245 homerDescriptor.SetType(AliHLTOUT::ByteSwap64(id));
246 homerDescriptor.SetSubType1(AliHLTOUT::ByteSwap64(origin));
247 homerDescriptor.SetSubType2(blocks[n].fSpecification);
248 homerDescriptor.SetBlockSize(blocks[n].fSize);
250 writerNo=ShuffleWriters(fWriters, blocks[n].fSize);
252 assert(writerNo>=0 && writerNo<(int)fWriters.size());
253 // I'm puzzled by the different headers, buffers etc. used in the
254 // HOMER writer/data. In additional, there is no type check as there
255 // are void pointers used and names mixed.
256 // It seems that HOMERBlockDescriptor is just a tool to set the
257 // different fields in the homer header, which is an array of 64 bit
259 fWriters[writerNo]->AddBlock(homerHeader, blocks[n].fPtr);
263 if (iResult>=0 && !bIsDataEvent) {
264 // data blocks from a special event are kept to be added to the
266 if (fReservedWriter>=0) {
267 HLTWarning("overriding previous buffer of non-data event data blocks");
269 const AliHLTUInt8_t* pBuffer=NULL;
271 // TODO: not yet clear whether it is smart to send the event id of
272 // this special event or if it should be set from the id of the
273 // following event where the data will be added
274 if ((bufferSize=FillOutputBuffer(evtData.fEventID, fWriters[writerNo], pBuffer))>0) {
275 fReservedWriter=writerNo;
276 fReservedData=bufferSize;
278 fWriters[writerNo]->Clear();
284 int AliHLTOUTComponent::FillESD(int eventNo, AliRunLoader* runLoader, AliESDEvent* /*esd*/)
286 // see header file for class documentation
289 if (fWriters.size()==0) return 0;
291 if (fReservedWriter>=0) {
292 if (fgOptions&kWriteDigits) WriteDigitArray(fReservedWriter, &fBuffer[0], fReservedData);
293 if (fgOptions&kWriteRawFiles) WriteRawFile(eventNo, runLoader, fReservedWriter, &fBuffer[0], fReservedData);
297 // search for the writer with the biggest data volume in order to allocate the
298 // output buffer of sufficient size
300 for (size_t i=0; i<fWriters.size(); i++) {
301 if ((int)i==fReservedWriter) continue;
304 if (sorted.size()==0 || fWriters[i]->GetTotalMemorySize()<=fWriters[sorted[0]]->GetTotalMemorySize()) {
307 sorted.insert(sorted.begin(), i);
313 vector<int>::iterator ddlno=sorted.begin();
314 while (ddlno!=sorted.end()) {
315 const AliHLTUInt8_t* pBuffer=NULL;
318 if ((bufferSize=FillOutputBuffer(eventNo, fWriters[*ddlno], pBuffer))>0) {
319 if (fgOptions&kWriteDigits) WriteDigitArray(*ddlno, pBuffer, bufferSize);
320 if (fgOptions&kWriteRawFiles) WriteRawFile(eventNo, runLoader, *ddlno, pBuffer, bufferSize);
322 fWriters[*ddlno]->Clear();
325 if (fgOptions&kWriteDigits) WriteDigits(eventNo, runLoader);
329 int AliHLTOUTComponent::ShuffleWriters(AliHLTMonitoringWriterPVector &list, AliHLTUInt32_t /*size*/)
331 // see header file for class documentation
333 assert(list.size()>0);
334 if (list.size()==0) return iResult;
337 for (i=0; i<list.size(); i++) {
338 if ((int)i==fReservedWriter) continue;
339 if (list[i]->GetTotalMemorySize()==0)
340 writers.push_back(i);
341 else if (iResult<0 ||
342 list[i]->GetTotalMemorySize()<list[iResult]->GetTotalMemorySize())
346 if (writers.size()>0) {
348 if (writers.size()>0) {
349 // shuffle among the empty writers
352 rand.SetSeed(dt.Get()*(iResult+1));
353 i=rand.Integer(writers.size()-1);
354 assert(i>0 && i<writers.size()-1);
358 // take the writer with the least data volume
364 int AliHLTOUTComponent::FillOutputBuffer(int eventNo, AliHLTMonitoringWriter* pWriter, const AliHLTUInt8_t* &pBuffer)
366 // see header file for class documentation
368 unsigned int bufferSize=0;
370 // space for common data header
371 bufferSize+=sizeof(AliRawDataHeader);
372 assert(sizeof(AliRawDataHeader)==32);
374 // space for HLT event header
375 bufferSize+=sizeof(AliHLTOUT::AliHLTOUTEventHeader);
377 // space for payload from the writer
378 if (pWriter) bufferSize+=pWriter->GetTotalMemorySize();
380 if (bufferSize>fBuffer.size())
381 fBuffer.resize(bufferSize);
383 if (bufferSize<=fBuffer.size()) {
384 AliRawDataHeader* pCDH=reinterpret_cast<AliRawDataHeader*>(&fBuffer[0]);
385 AliHLTOUT::AliHLTOUTEventHeader* pHLTH=reinterpret_cast<AliHLTOUT::AliHLTOUTEventHeader*>(&fBuffer[sizeof(AliRawDataHeader)]);
386 *pCDH = AliRawDataHeader(); // Fill with default values.
387 memset(pHLTH, 0, sizeof(AliHLTOUT::AliHLTOUTEventHeader));
391 pWriter->Copy(&fBuffer[sizeof(AliRawDataHeader)+sizeof(AliHLTOUT::AliHLTOUTEventHeader)], 0, 0, 0, 0);
392 pHLTH->fLength=pWriter->GetTotalMemorySize();
393 // set status bit to indicate HLT payload
394 pCDH->fStatusMiniEventID|=0x1<<(AliHLTOUT::kCDHStatusFlagsOffset+AliHLTOUT::kCDHFlagsHLTPayload);
396 pHLTH->fLength+=sizeof(AliHLTOUT::AliHLTOUTEventHeader);
397 // pHLTH->fEventIDLow is already set to zero in memset above.
398 pHLTH->fEventIDLow = eventNo;
399 // version does not really matter since we do not add decision data
400 pHLTH->fVersion=AliHLTOUT::kVersion1;
402 pCDH->fSize=sizeof(AliRawDataHeader)+pHLTH->fLength;
403 pCDH->fStatusMiniEventID|=0x1<<(AliHLTOUT::kCDHStatusFlagsOffset + AliHLTOUT::kCDHFlagsHLTPayload);
406 iResult=(int)bufferSize;
415 int AliHLTOUTComponent::WriteDigitArray(int hltddl, const AliHLTUInt8_t* pBuffer, unsigned int bufferSize)
417 // see header file for class documentation
419 assert(hltddl<fNofDDLs);
420 if (hltddl>=fNofDDLs) return -ERANGE;
422 if (!fppDigitArrays) {
423 fppDigitArrays=new TArrayC*[fNofDDLs];
424 if (fppDigitArrays) {
425 for (int i=0; i<fNofDDLs; i++) {
426 fppDigitArrays[i]=new TArrayC(0);
430 if (fppDigitArrays && fppDigitArrays[hltddl]) {
431 fppDigitArrays[hltddl]->Set(bufferSize, reinterpret_cast<const Char_t*>(pBuffer));
438 int AliHLTOUTComponent::WriteDigits(int /*eventNo*/, AliRunLoader* /*runLoader*/)
440 // see header file for class documentation
442 const char* digitFileName="HLT.Digits.root";
444 fpDigitFile=new TFile(digitFileName, "RECREATE");
446 if (fpDigitFile && !fpDigitFile->IsZombie()) {
448 fpDigitTree=new TTree("rawhltout","HLTOUT raw data");
449 if (fpDigitTree && fppDigitArrays) {
450 for (int i=0; i<fNofDDLs; i++) {
451 const char* branchName=AliDAQ::DdlFileName("HLT", i);
452 if (fppDigitArrays[i]) fpDigitTree->Branch(branchName, "TArrayC", &fppDigitArrays[i], 32000/*just as the default*/, 0);
457 int res=fpDigitTree->Fill();
458 HLTDebug("writing digit tree: %d", res);
460 res=fpDigitTree->Write("",TObject::kOverwrite);
461 HLTDebug("writing digit tree: %d", res);
462 if (fppDigitArrays) for (int i=0; i<fNofDDLs; i++) {
463 if (fppDigitArrays[i]) fppDigitArrays[i]->Set(0);
467 const char* errorMsg="";
468 if (GetEventCount()==5) {
469 errorMsg=" (suppressing further error messages)";
471 if (GetEventCount()<5) {
472 HLTError("can not open HLT digit file %s%s", digitFileName, errorMsg);
479 int AliHLTOUTComponent::WriteRawFile(int eventNo, AliRunLoader* /*runLoader*/, int hltddl, const AliHLTUInt8_t* pBuffer, unsigned int bufferSize)
481 // see header file for class documentation
483 const char* fileName=AliDAQ::DdlFileName("HLT", hltddl);
484 assert(fileName!=NULL);
486 filePath.Form("raw%d/", eventNo);
489 ios::openmode filemode=(ios::openmode)0;
490 ofstream rawfile(filePath.Data(), filemode);
491 if (rawfile.good()) {
492 if (pBuffer && bufferSize>0) {
493 rawfile.write(reinterpret_cast<const char*>(pBuffer), bufferSize);
495 HLTWarning("writing zero length raw data file %s");
497 HLTDebug("wrote %d byte(s) to file %s", bufferSize, filePath.Data());
499 HLTError("can not open file %s for writing", filePath.Data());
507 void AliHLTOUTComponent::SetGlobalOption(unsigned int options)
509 // see header file for class documentation
513 void AliHLTOUTComponent::ClearGlobalOption(unsigned int options)
515 // see header file for class documentation