various fixes in the HLTOUT treatment
[u/mrichter/AliRoot.git] / HLT / sim / AliHLTOUTComponent.cxx
1 // $Id$
2
3 /**************************************************************************
4  * This file is property of and copyright by the ALICE HLT Project        * 
5  * ALICE Experiment at CERN, All rights reserved.                         *
6  *                                                                        *
7  * Primary Authors: Matthias Richter <Matthias.Richter@ift.uib.no>        *
8  *                  for The ALICE HLT Project.                            *
9  *                                                                        *
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  **************************************************************************/
18
19 /** @file   AliHLTOUTComponent.cxx
20     @author Matthias Richter
21     @date   
22     @brief  The HLTOUT data sink component similar to HLTOUT nodes */
23
24 // see header file for class documentation
25 // or
26 // refer to README to build package
27 // or
28 // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
29
30 #if __GNUC__>= 3
31 using namespace std;
32 #endif
33
34 #include <cassert>
35 #include <iostream>
36 #include "AliHLTOUTComponent.h"
37 #include "AliHLTOUT.h"
38 #include "AliHLTHOMERLibManager.h"
39 #include "AliHLTHOMERWriter.h"
40 #include "AliDAQ.h" // equipment Ids
41 #include "AliRawDataHeader.h" // Common Data Header 
42 #include <TDatime.h> // seed for TRandom
43 #include <TRandom.h> // random int generation for DDL no
44
45 /** ROOT macro for the implementation of ROOT specific class methods */
46 ClassImp(AliHLTOUTComponent)
47
48 AliHLTOUTComponent::AliHLTOUTComponent()
49   :
50   AliHLTOfflineDataSink(),
51   fWriters(),
52   fNofDDLs(10),
53   fIdFirstDDL(4864), // 0x13<<8
54   fWriteDigits(kTRUE),
55   fWriteRaw(kTRUE),
56   fBuffer(),
57   fpLibManager(NULL)
58 {
59   // see header file for class documentation
60   // or
61   // refer to README to build package
62   // or
63   // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
64
65   // I guess DDL definitions should never change any more
66   assert(fNofDDLs==AliDAQ::NumberOfDdls("HLT"));
67   fNofDDLs=AliDAQ::NumberOfDdls("HLT");
68   assert(fIdFirstDDL==AliDAQ::DdlIDOffset("HLT"));
69   fIdFirstDDL=AliDAQ::DdlIDOffset("HLT");
70 }
71
72 AliHLTOUTComponent::~AliHLTOUTComponent()
73 {
74   // see header file for class documentation
75   if (fpLibManager) delete fpLibManager;
76   fpLibManager=NULL;
77 }
78
79 const char* AliHLTOUTComponent::GetComponentID()
80 {
81   // see header file for class documentation
82   return "HLTOUT";
83 }
84
85 void AliHLTOUTComponent::GetInputDataTypes( vector<AliHLTComponentDataType>& list)
86 {
87   // see header file for class documentation
88   list.clear();
89   list.push_back(kAliHLTAnyDataType);
90 }
91
92 AliHLTComponent* AliHLTOUTComponent::Spawn()
93 {
94   // see header file for class documentation
95   return new AliHLTOUTComponent;
96 }
97
98 int AliHLTOUTComponent::DoInit( int argc, const char** argv )
99 {
100   // see header file for class documentation
101   int iResult=0;
102   TString argument="";
103   int bMissingParam=0;
104   for (int i=0; i<argc && iResult>=0; i++) {
105     argument=argv[i];
106     if (argument.IsNull()) continue;
107
108     // -links
109     if (argument.CompareTo("-links")==0) {
110       if ((bMissingParam=(++i>=argc))) break;
111       TString parameter(argv[i]);
112       parameter.Remove(TString::kLeading, ' '); // remove all blanks
113       if (parameter.IsDigit()) {
114         fNofDDLs=parameter.Atoi();
115       } else {
116         HLTError("wrong parameter for argument %s, number expected", argument.Data());
117         iResult=-EINVAL;
118       }
119     } else {
120       HLTError("unknown argument %s", argument.Data());
121       iResult=-EINVAL;
122       break;
123     }
124   }
125   if (bMissingParam) {
126     HLTError("missing parameter for argument %s", argument.Data());
127     iResult=-EINVAL;
128   }
129   if (iResult>=0) {
130   }
131
132   fpLibManager=new AliHLTHOMERLibManager;
133   if (fpLibManager) {
134     int writerNo=0;
135     for (writerNo=0; writerNo<fNofDDLs; writerNo++) {
136       AliHLTMonitoringWriter* pWriter=fpLibManager->OpenWriter();
137       if (pWriter) {
138         HLTDebug("HOMER writer %p added", pWriter);
139         fWriters.push_back(pWriter);
140       } else {
141         HLTError("can nor open HOMER writer");
142         iResult=-ENODEV;
143         break;
144       }
145     }
146   } else {
147     iResult=-ENOMEM;
148   }
149
150   return iResult;
151 }
152
153 int AliHLTOUTComponent::DoDeinit()
154 {
155   // see header file for class documentation
156   int iResult=0;
157
158   if (fpLibManager) {
159     AliHLTMonitoringWriterPVector::iterator element=fWriters.begin();
160     while (element!= fWriters.end()) {
161       assert(*element);
162       // wanted to have a dynamic_cast<AliHLTHOMERWriter*> here, but this results into
163       // undefined symbol when loading the library
164       (*element)->Clear();
165       if (*element!=NULL) fpLibManager->DeleteWriter((AliHLTHOMERWriter*)(*element));
166       element=fWriters.erase(element);
167     }
168   }
169   
170   return iResult;
171 }
172
173 int AliHLTOUTComponent::DumpEvent( const AliHLTComponentEventData& evtData,
174                          const AliHLTComponentBlockData* blocks, 
175                          AliHLTComponentTriggerData& /*trigData*/ )
176 {
177   // see header file for class documentation
178   int iResult=0;
179   HLTInfo("write %d output blocks", evtData.fBlockCnt);
180   if (iResult>=0) {
181     homer_uint64 homerHeader[kCount_64b_Words];
182     HOMERBlockDescriptor homerDescriptor(homerHeader);
183     for (int n=0; n<(int)evtData.fBlockCnt; n++ ) {
184       memset( homerHeader, 0, sizeof(homer_uint64)*kCount_64b_Words );
185       homerDescriptor.Initialize();
186       homerDescriptor.SetType(*(reinterpret_cast<const homer_uint64*>(blocks[n].fDataType.fID)));
187       homerDescriptor.SetSubType1(*(reinterpret_cast<const homer_uint32*>(blocks[n].fDataType.fOrigin)));
188       homerDescriptor.SetSubType2(static_cast<homer_uint64>(blocks[n].fSpecification));
189       homerDescriptor.SetBlockSize(blocks[n].fSize);
190       int writerNo=ShuffleWriters(fWriters, blocks[n].fSize);
191       assert(writerNo>=0 && writerNo<fWriters.size());
192       // I'm puzzled by the different headers, buffers etc. used in the
193       // HOMER writer/data. In additional, there is no type check as there
194       // are void pointers used and names mixed.
195       // It seems that HOMERBlockDescriptor is just a tool to set the
196       // different fields in the homer header, which is an array of 64 bit
197       // words.
198       fWriters[writerNo]->AddBlock(homerHeader, blocks[n].fPtr);
199     }
200   }
201
202   return iResult;
203 }
204
205 int AliHLTOUTComponent::FillESD(int eventNo, AliRunLoader* runLoader, AliESDEvent* /*esd*/)
206 {
207   // see header file for class documentation
208   int iResult=0;
209   if (fWriters.size()==0) return 0;
210   
211   // search for the writer with the biggest data volume in order to allocate the
212   // output buffer of sufficient size
213   vector<int> sorted;
214   for (size_t i=0; i<fWriters.size(); i++) {
215     assert(fWriters[i]);
216     if (fWriters[i]) {
217       if (sorted.size()==0 || fWriters[i]->GetTotalMemorySize()<=fWriters[sorted[0]]->GetTotalMemorySize()) {
218         sorted.push_back(i);
219       } else {
220         sorted.insert(sorted.begin(), i);
221       }
222     }
223   }
224
225   vector<int>::iterator ddlno=sorted.begin();
226   while (ddlno!=sorted.end()) {
227     const AliHLTUInt8_t* pBuffer=NULL;
228     int bufferSize=0;
229     
230     if ((bufferSize=FillOutputBuffer(eventNo, fWriters[*ddlno], pBuffer))>0) {
231       if (fWriteDigits) WriteDigits(eventNo, runLoader, *ddlno, pBuffer, bufferSize);
232       if (fWriteRaw) WriteRawFile(eventNo, runLoader, *ddlno, pBuffer, bufferSize);
233     }
234     fWriters[*ddlno]->Clear();
235     ddlno++;
236   }
237   return iResult;
238 }
239
240 int AliHLTOUTComponent::ShuffleWriters(AliHLTMonitoringWriterPVector &list, AliHLTUInt32_t /*size*/)
241 {
242   // see header file for class documentation
243   int iResult=-ENOENT;
244   assert(list.size()>0);
245   if (list.size()==0) return iResult;
246   vector<int> writers;
247   size_t i=0;
248   for (i=0; i<list.size(); i++) {
249     if (list[i]->GetTotalMemorySize()==0)
250       writers.push_back(i);
251     else if (iResult<0 ||
252              list[i]->GetTotalMemorySize()<list[iResult]->GetTotalMemorySize())
253       iResult=i;
254       
255   }
256   if (writers.size()>0) {
257     iResult=writers[0];
258     if (writers.size()>0) {
259       // shuffle among the empty writers
260       TDatime dt;
261       TRandom rand;
262       rand.SetSeed(dt.Get()*(iResult+1));
263       i=rand.Integer(writers.size()-1);
264       assert(i>0 && i<writers.size()-1);
265       iResult=writers[i];
266     }
267   } else {
268     // take the writer with the least data volume
269     assert(iResult>=0);
270   }
271   return iResult;
272 }
273
274 int AliHLTOUTComponent::FillOutputBuffer(int eventNo, AliHLTMonitoringWriter* pWriter, const AliHLTUInt8_t* &pBuffer)
275 {
276   // see header file for class documentation
277   int iResult=0;
278   unsigned int bufferSize=0;
279
280   // space for common data header
281   bufferSize+=sizeof(AliRawDataHeader);
282   assert(sizeof(AliRawDataHeader)==32);
283
284   // space for HLT event header
285   bufferSize+=sizeof(AliHLTOUT::AliHLTOUTEventHeader);
286
287   // space for payload from the writer
288   if (pWriter) bufferSize+=pWriter->GetTotalMemorySize();
289
290   if (bufferSize>fBuffer.size())
291     fBuffer.resize(bufferSize);
292
293   if (bufferSize<=fBuffer.size()) {
294     AliRawDataHeader* pCDH=reinterpret_cast<AliRawDataHeader*>(&fBuffer[0]);
295     AliHLTOUT::AliHLTOUTEventHeader* pHLTH=reinterpret_cast<AliHLTOUT::AliHLTOUTEventHeader*>(&fBuffer[sizeof(AliRawDataHeader)]);
296     memset(pCDH, 0, sizeof(AliRawDataHeader));
297     memset(pHLTH, 0, sizeof(AliHLTOUT::AliHLTOUTEventHeader));
298     pHLTH->fVersion=1;
299     if (pWriter) {
300       // copy payload
301       pWriter->Copy(&fBuffer[sizeof(AliRawDataHeader)+sizeof(AliHLTOUT::AliHLTOUTEventHeader)], 0, 0, 0, 0);
302       pHLTH->fLength=pWriter->GetTotalMemorySize();
303       // set status bit to indicate HLT payload
304       pCDH->fStatusMiniEventID|=0x1<<(AliHLTOUT::fgkCDHStatusFlagsOffset+AliHLTOUT::fgkCDHFlagsHLTPayload);
305     }
306     pHLTH->fLength+=sizeof(AliHLTOUT::AliHLTOUTEventHeader);
307     pHLTH->fEventID=eventNo;
308
309     pCDH->fSize=sizeof(AliRawDataHeader)+pHLTH->fLength;
310     
311     pBuffer=&fBuffer[0];
312     iResult=(int)bufferSize;
313   } else {
314     pBuffer=NULL;
315     iResult=-ENOMEM;
316   }
317
318   return iResult;
319 }
320
321 int AliHLTOUTComponent::WriteDigits(int /*eventNo*/, AliRunLoader* /*runLoader*/, int /*hltddl*/, const AliHLTUInt8_t* /*pBuffer*/, unsigned int /*bufferSize*/)
322 {
323   // see header file for class documentation
324   int iResult=0;
325   return iResult;
326 }
327
328 int AliHLTOUTComponent::WriteRawFile(int eventNo, AliRunLoader* /*runLoader*/, int hltddl, const AliHLTUInt8_t* pBuffer, unsigned int bufferSize)
329 {
330   // see header file for class documentation
331   int iResult=0;
332   const char* fileName=AliDAQ::DdlFileName("HLT", hltddl);
333   assert(fileName!=NULL);
334   TString filePath;
335   filePath.Form("raw%d/", eventNo);
336   filePath+=fileName;
337   if (fileName) {
338     ios::openmode filemode=(ios::openmode)0;
339     ofstream rawfile(filePath.Data(), filemode);
340     if (rawfile.good()) {
341       if (pBuffer && bufferSize>0) {
342         rawfile.write(reinterpret_cast<const char*>(pBuffer), bufferSize);
343       } else {
344         HLTWarning("writing zero length raw data file %s");
345       }
346       HLTDebug("wrote %d byte(s) to file %s", bufferSize, filePath.Data());
347     } else {
348       HLTError("can not open file %s for writing", filePath.Data());
349       iResult=-EBADF;
350     }
351     rawfile.close();
352   }
353   return iResult;
354 }