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
58 // see header file for class documentation
60 // refer to README to build package
62 // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
64 // I guess DDL definitions should never change any more
65 assert(fNofDDLs==AliDAQ::NumberOfDdls("HLT"));
66 fNofDDLs=AliDAQ::NumberOfDdls("HLT");
68 /* AliDAQ::DdlIDOffset returns wrong offset for HLT links
69 assert(fIdFirstDDL==AliDAQ::DdlIDOffset("HLT"));
70 fIdFirstDDL=AliDAQ::DdlIDOffset("HLT");
74 int AliHLTOUTComponent::fgOptions=kWriteRawFiles|kWriteDigits;
76 AliHLTOUTComponent::~AliHLTOUTComponent()
78 // see header file for class documentation
79 if (fpLibManager) delete fpLibManager;
83 const char* AliHLTOUTComponent::GetComponentID()
85 // see header file for class documentation
89 void AliHLTOUTComponent::GetInputDataTypes( vector<AliHLTComponentDataType>& list)
91 // see header file for class documentation
93 list.push_back(kAliHLTAnyDataType);
96 AliHLTComponent* AliHLTOUTComponent::Spawn()
98 // see header file for class documentation
99 return new AliHLTOUTComponent;
102 int AliHLTOUTComponent::DoInit( int argc, const char** argv )
104 // see header file for class documentation
108 for (int i=0; i<argc && iResult>=0; i++) {
110 if (argument.IsNull()) continue;
113 if (argument.CompareTo("-links")==0) {
114 if ((bMissingParam=(++i>=argc))) break;
115 TString parameter(argv[i]);
116 parameter.Remove(TString::kLeading, ' '); // remove all blanks
117 if (parameter.IsDigit()) {
118 fNofDDLs=parameter.Atoi();
120 HLTError("wrong parameter for argument %s, number expected", argument.Data());
124 HLTError("unknown argument %s", argument.Data());
130 HLTError("missing parameter for argument %s", argument.Data());
136 fpLibManager=new AliHLTHOMERLibManager;
139 for (writerNo=0; writerNo<fNofDDLs; writerNo++) {
140 AliHLTMonitoringWriter* pWriter=fpLibManager->OpenWriter();
142 HLTDebug("HOMER writer %p added", pWriter);
143 fWriters.push_back(pWriter);
145 HLTError("can not open HOMER writer");
157 int AliHLTOUTComponent::DoDeinit()
159 // see header file for class documentation
163 AliHLTMonitoringWriterPVector::iterator element=fWriters.begin();
164 while (element!= fWriters.end()) {
166 // wanted to have a dynamic_cast<AliHLTHOMERWriter*> here, but this results into
167 // undefined symbol when loading the library
169 if (*element!=NULL) fpLibManager->DeleteWriter((AliHLTHOMERWriter*)(*element));
170 element=fWriters.erase(element);
180 fpDigitFile->Close();
185 if (fppDigitArrays) {
186 for (int i=0; i<fNofDDLs; i++) {
187 if (fppDigitArrays[i]) delete fppDigitArrays[i];
189 delete[] fppDigitArrays;
196 int AliHLTOUTComponent::DumpEvent( const AliHLTComponentEventData& evtData,
197 const AliHLTComponentBlockData* blocks,
198 AliHLTComponentTriggerData& /*trigData*/ )
200 // see header file for class documentation
202 HLTInfo("write %d output block(s)", evtData.fBlockCnt);
204 homer_uint64 homerHeader[kCount_64b_Words];
205 HOMERBlockDescriptor homerDescriptor(homerHeader);
206 for (int n=0; n<(int)evtData.fBlockCnt; n++ ) {
207 memset( homerHeader, 0, sizeof(homer_uint64)*kCount_64b_Words );
208 homerDescriptor.Initialize();
209 // for some traditional reason the TCPDumpSubscriber swaps the bytes
210 // of the data type id and data type origin. Actually I do not understand
211 // the corresponding code line
212 // homerBlock.SetType( blocks[n].fDataType.fID );
213 // this compiles in the PubSub framework and in addition does a byte swap
215 homer_uint64 origin=0;
216 memcpy(&id, blocks[n].fDataType.fID, sizeof(homer_uint64));
217 memcpy(((AliHLTUInt8_t*)&origin)+sizeof(homer_uint32), blocks[n].fDataType.fOrigin, sizeof(homer_uint32));
218 homerDescriptor.SetType(AliHLTOUT::ByteSwap64(id));
219 homerDescriptor.SetSubType1(AliHLTOUT::ByteSwap64(origin));
220 homerDescriptor.SetSubType2(blocks[n].fSpecification);
221 homerDescriptor.SetBlockSize(blocks[n].fSize);
222 int writerNo=ShuffleWriters(fWriters, blocks[n].fSize);
223 assert(writerNo>=0 && writerNo<(int)fWriters.size());
224 // I'm puzzled by the different headers, buffers etc. used in the
225 // HOMER writer/data. In additional, there is no type check as there
226 // are void pointers used and names mixed.
227 // It seems that HOMERBlockDescriptor is just a tool to set the
228 // different fields in the homer header, which is an array of 64 bit
230 fWriters[writerNo]->AddBlock(homerHeader, blocks[n].fPtr);
237 int AliHLTOUTComponent::FillESD(int eventNo, AliRunLoader* runLoader, AliESDEvent* /*esd*/)
239 // see header file for class documentation
241 if (fWriters.size()==0) return 0;
243 // search for the writer with the biggest data volume in order to allocate the
244 // output buffer of sufficient size
246 for (size_t i=0; i<fWriters.size(); i++) {
249 if (sorted.size()==0 || fWriters[i]->GetTotalMemorySize()<=fWriters[sorted[0]]->GetTotalMemorySize()) {
252 sorted.insert(sorted.begin(), i);
257 vector<int>::iterator ddlno=sorted.begin();
258 while (ddlno!=sorted.end()) {
259 const AliHLTUInt8_t* pBuffer=NULL;
262 if ((bufferSize=FillOutputBuffer(eventNo, fWriters[*ddlno], pBuffer))>0) {
263 if (fgOptions&kWriteDigits) WriteDigitArray(*ddlno, pBuffer, bufferSize);
264 if (fgOptions&kWriteRawFiles) WriteRawFile(eventNo, runLoader, *ddlno, pBuffer, bufferSize);
266 fWriters[*ddlno]->Clear();
269 if (fgOptions&kWriteDigits) WriteDigits(eventNo, runLoader);
273 int AliHLTOUTComponent::ShuffleWriters(AliHLTMonitoringWriterPVector &list, AliHLTUInt32_t /*size*/)
275 // see header file for class documentation
277 assert(list.size()>0);
278 if (list.size()==0) return iResult;
281 for (i=0; i<list.size(); i++) {
282 if (list[i]->GetTotalMemorySize()==0)
283 writers.push_back(i);
284 else if (iResult<0 ||
285 list[i]->GetTotalMemorySize()<list[iResult]->GetTotalMemorySize())
289 if (writers.size()>0) {
291 if (writers.size()>0) {
292 // shuffle among the empty writers
295 rand.SetSeed(dt.Get()*(iResult+1));
296 i=rand.Integer(writers.size()-1);
297 assert(i>0 && i<writers.size()-1);
301 // take the writer with the least data volume
307 int AliHLTOUTComponent::FillOutputBuffer(int eventNo, AliHLTMonitoringWriter* pWriter, const AliHLTUInt8_t* &pBuffer)
309 // see header file for class documentation
311 unsigned int bufferSize=0;
313 // space for common data header
314 bufferSize+=sizeof(AliRawDataHeader);
315 assert(sizeof(AliRawDataHeader)==32);
317 // space for HLT event header
318 bufferSize+=sizeof(AliHLTOUT::AliHLTOUTEventHeader);
320 // space for payload from the writer
321 if (pWriter) bufferSize+=pWriter->GetTotalMemorySize();
323 if (bufferSize>fBuffer.size())
324 fBuffer.resize(bufferSize);
326 if (bufferSize<=fBuffer.size()) {
327 AliRawDataHeader* pCDH=reinterpret_cast<AliRawDataHeader*>(&fBuffer[0]);
328 AliHLTOUT::AliHLTOUTEventHeader* pHLTH=reinterpret_cast<AliHLTOUT::AliHLTOUTEventHeader*>(&fBuffer[sizeof(AliRawDataHeader)]);
329 memset(pCDH, 0, sizeof(AliRawDataHeader));
330 memset(pHLTH, 0, sizeof(AliHLTOUT::AliHLTOUTEventHeader));
334 pWriter->Copy(&fBuffer[sizeof(AliRawDataHeader)+sizeof(AliHLTOUT::AliHLTOUTEventHeader)], 0, 0, 0, 0);
335 pHLTH->fLength=pWriter->GetTotalMemorySize();
336 // set status bit to indicate HLT payload
337 pCDH->fStatusMiniEventID|=0x1<<(AliHLTOUT::kCDHStatusFlagsOffset+AliHLTOUT::kCDHFlagsHLTPayload);
339 pHLTH->fLength+=sizeof(AliHLTOUT::AliHLTOUTEventHeader);
340 pHLTH->fEventID=eventNo;
341 // version does not really matter since we do not add decision data
342 pHLTH->fVersion=AliHLTOUT::kVersion1;
344 pCDH->fSize=sizeof(AliRawDataHeader)+pHLTH->fLength;
345 pCDH->fStatusMiniEventID|=0x1<<(AliHLTOUT::kCDHStatusFlagsOffset + AliHLTOUT::kCDHFlagsHLTPayload);
348 iResult=(int)bufferSize;
357 int AliHLTOUTComponent::WriteDigitArray(int hltddl, const AliHLTUInt8_t* pBuffer, unsigned int bufferSize)
359 // see header file for class documentation
361 assert(hltddl<fNofDDLs);
362 if (hltddl>=fNofDDLs) return -ERANGE;
364 if (!fppDigitArrays) {
365 fppDigitArrays=new TArrayC*[fNofDDLs];
366 if (fppDigitArrays) {
367 for (int i=0; i<fNofDDLs; i++) {
368 fppDigitArrays[i]=new TArrayC(0);
372 if (fppDigitArrays && fppDigitArrays[hltddl]) {
373 fppDigitArrays[hltddl]->Set(bufferSize, reinterpret_cast<const Char_t*>(pBuffer));
380 int AliHLTOUTComponent::WriteDigits(int /*eventNo*/, AliRunLoader* /*runLoader*/)
382 // see header file for class documentation
384 const char* digitFileName="HLT.Digits.root";
386 fpDigitFile=new TFile(digitFileName, "RECREATE");
388 if (fpDigitFile && !fpDigitFile->IsZombie()) {
390 fpDigitTree=new TTree("rawhltout","HLTOUT raw data");
391 if (fpDigitTree && fppDigitArrays) {
392 for (int i=0; i<fNofDDLs; i++) {
393 const char* branchName=AliDAQ::DdlFileName("HLT", i);
394 if (fppDigitArrays[i]) fpDigitTree->Branch(branchName, "TArrayC", &fppDigitArrays[i], 32000/*just as the default*/, 0);
399 int res=fpDigitTree->Fill();
400 HLTDebug("writing digit tree: %d", res);
402 res=fpDigitTree->Write("",TObject::kOverwrite);
403 HLTDebug("writing digit tree: %d", res);
404 if (fppDigitArrays) for (int i=0; i<fNofDDLs; i++) {
405 if (fppDigitArrays[i]) fppDigitArrays[i]->Set(0);
409 const char* errorMsg="";
410 if (GetEventCount()==5) {
411 errorMsg=" (suppressing further error messages)";
413 if (GetEventCount()<5) {
414 HLTError("can not open HLT digit file %s%s", digitFileName, errorMsg);
421 int AliHLTOUTComponent::WriteRawFile(int eventNo, AliRunLoader* /*runLoader*/, int hltddl, const AliHLTUInt8_t* pBuffer, unsigned int bufferSize)
423 // see header file for class documentation
425 const char* fileName=AliDAQ::DdlFileName("HLT", hltddl);
426 assert(fileName!=NULL);
428 filePath.Form("raw%d/", eventNo);
431 ios::openmode filemode=(ios::openmode)0;
432 ofstream rawfile(filePath.Data(), filemode);
433 if (rawfile.good()) {
434 if (pBuffer && bufferSize>0) {
435 rawfile.write(reinterpret_cast<const char*>(pBuffer), bufferSize);
437 HLTWarning("writing zero length raw data file %s");
439 HLTDebug("wrote %d byte(s) to file %s", bufferSize, filePath.Data());
441 HLTError("can not open file %s for writing", filePath.Data());
449 void AliHLTOUTComponent::SetGlobalOption(unsigned int options)
451 // see header file for class documentation
455 void AliHLTOUTComponent::ClearGlobalOption(unsigned int options)
457 // see header file for class documentation