]> git.uio.no Git - u/mrichter/AliRoot.git/blob - MUON/AliMUONRawStreamTrackerHP.cxx
Memory leaks
[u/mrichter/AliRoot.git] / MUON / AliMUONRawStreamTrackerHP.cxx
1 /**************************************************************************
2  * This file is property of and copyright by the ALICE HLT Project        *
3  * All rights reserved.                                                   *
4  *                                                                        *
5  * Primary Authors:                                                       *
6  *   Artur Szostak <artursz@iafrica.com>                                  *
7  *                                                                        *
8  * Permission to use, copy, modify and distribute this software and its   *
9  * documentation strictly for non-commercial purposes is hereby granted   *
10  * without fee, provided that the above copyright notice appears in all   *
11  * copies and that both the copyright notice and this permission notice   *
12  * appear in the supporting documentation. The authors make no claims     *
13  * about the suitability of this software for any purpose. It is          *
14  * provided "as is" without express or implied warranty.                  *
15  **************************************************************************/
16
17 /* $Id$*/
18
19 ///
20 /// \file   AliMUONRawStreamTrackerHP.cxx
21 /// \author Artur Szostak <artursz@iafrica.com>
22 /// \date   29-11-2007
23 /// \brief  Implementation of the the high performance decoder AliMUONRawStreamTrackerHP.
24 ///
25
26 //-----------------------------------------------------------------------------
27 /// \ingroup raw
28 /// \class AliMUONRawStreamTrackerHP
29 /// \brief A high performance stream decoder for muon tracking DDL streams.
30 ///
31 /// This is the raw stream class which interfaces between the high performance
32 /// core decoder and the AliRawReader class.
33 /// To gain the most out of the decoder, the Next() method which returns batches
34 /// of decoded digit / channel information should be used. That is:
35 /// \code
36 ///   const AliBusPatch* Next();
37 /// \endcode
38 ///
39 /// This decoder tries to implement as similar an interface as possible to
40 /// AliMUONRawStreamTracker where possible. However certain constructs which
41 /// would slow us down too much are avoided.
42 ///
43 /// \author Artur Szostak <artursz@iafrica.com>
44 //-----------------------------------------------------------------------------
45
46 #include "AliMUONRawStreamTrackerHP.h"
47 #include "AliRawReader.h"
48 #include "AliLog.h"
49 #include <cassert>
50 #include <iostream>
51 #include <iomanip>
52 using std::cout;
53 using std::endl;
54 using std::hex;
55 using std::dec;
56
57 /// \cond CLASSIMP
58 ClassImp(AliMUONRawStreamTrackerHP)
59 /// \endcond
60
61
62 AliMUONRawStreamTrackerHP::AliMUONRawStreamTrackerHP() :
63         AliMUONVRawStreamTracker(),
64         fDecoder(),
65         fDDL(0),
66         fBufferSize(8192),
67         fBuffer(new UChar_t[8192]),
68         fCurrentBusPatch(NULL),
69         fCurrentData(NULL),
70         fEndOfData(NULL),
71         fHadError(kFALSE),
72         fDone(kFALSE)
73 {
74         ///
75         /// Default constructor.
76         ///
77         
78         // Must set this flag to get all information about parity errors though
79         // the OnData method. OnError gets them either way.
80         fDecoder.ExitOnError(false);
81         fDecoder.SendDataOnParityError(true);
82
83         fDecoder.GetHandler().SetMaxStructs(
84                         fDecoder.MaxBlocks(),
85                         fDecoder.MaxDSPs(),
86                         fDecoder.MaxBusPatches()
87                 );
88
89         fDecoder.GetHandler().SetRawStream(this);
90 }
91
92
93 AliMUONRawStreamTrackerHP::AliMUONRawStreamTrackerHP(AliRawReader* rawReader) :
94         AliMUONVRawStreamTracker(rawReader),
95         fDecoder(),
96         fDDL(0),
97         fBufferSize(8192),
98         fBuffer(new UChar_t[8192]),
99         fCurrentBusPatch(NULL),
100         fCurrentData(NULL),
101         fEndOfData(NULL),
102         fHadError(kFALSE),
103         fDone(kFALSE)
104 {
105         ///
106         /// Constructor with AliRawReader as argument.
107         ///
108         
109         // Must set this flag to get all information about parity errors though
110         // the OnData method. OnError gets them either way.
111         fDecoder.ExitOnError(false);
112         fDecoder.SendDataOnParityError(true);
113
114         fDecoder.GetHandler().SetMaxStructs(
115                         fDecoder.MaxBlocks(),
116                         fDecoder.MaxDSPs(),
117                         fDecoder.MaxBusPatches()
118                 );
119         
120         fDecoder.GetHandler().SetRawStream(this);
121 }
122
123
124 AliMUONRawStreamTrackerHP::~AliMUONRawStreamTrackerHP()
125 {
126         ///
127         /// Default destructor.
128         ///
129         
130         if (fBuffer != NULL)
131         {
132                 delete [] fBuffer;
133         }
134 }
135
136
137 void AliMUONRawStreamTrackerHP::First()
138 {
139         /// Initialise or reset the iterator.
140         /// The first DDL will be found and decoded.
141         
142         assert( GetReader() != NULL );
143         
144         fDDL = 0;
145         fDone = kFALSE;
146         NextDDL();
147 }
148
149
150 Bool_t AliMUONRawStreamTrackerHP::NextDDL()
151 {
152         /// Reading the next tracker DDL and decode the payload with the 
153         /// high performance decoder.
154         /// \return kTRUE if the next DDL was successfully read and kFALSE otherwise.
155
156         assert( GetReader() != NULL );
157         
158         // Better to reset these pointers.
159         fCurrentBusPatch = NULL;
160         fCurrentData = NULL;
161         fEndOfData = NULL;
162         
163         while (fDDL < GetMaxDDL())
164         {
165                 GetReader()->Reset();
166                 GetReader()->Select("MUONTRK", fDDL, fDDL);  // Select the DDL file to be read.
167                 if (GetReader()->ReadHeader()) break;
168                 AliDebug(3, Form("Skipping DDL %d which does not seem to be there", fDDL+1));
169                 fDDL++;
170         }
171
172         // If we reach the end of the DDL list for this event then reset the
173         // DDL counter, mark the iteration as done and exit.
174         if (fDDL >= GetMaxDDL())
175         {
176                 fDDL = 0;
177                 fDone = kTRUE;
178                 return kFALSE;
179         }
180         else
181         {
182                 fDone = kFALSE;
183         }
184
185         AliDebug(3, Form("DDL Number %d\n", fDDL));
186         
187         Int_t dataSize = GetReader()->GetDataSize(); // in bytes
188         // Check if we have enough buffer space already in fBuffer. If we do then
189         // just continue reading otherwise we need to resize the buffer.
190         if (fBufferSize < dataSize)
191         {
192                 if (fBuffer != NULL)
193                 {
194                         delete [] fBuffer;
195                         fBuffer = NULL;
196                         fBufferSize = 0;
197                 }
198                 try
199                 {
200                         fBuffer = new UChar_t[dataSize];
201                         fBufferSize = dataSize;
202                 }
203                 catch (const std::bad_alloc&)
204                 {
205                         AliError("Could not allocate more buffer space. Cannot decode DDL.");
206                         return kFALSE;
207                 }
208         }
209         
210         if (not GetReader()->ReadNext(fBuffer, dataSize))
211         {
212                 return kFALSE;
213         }
214         
215 #ifndef R__BYTESWAP
216         Swap(reinterpret_cast<UInt_t*>(fBuffer), dataSize / sizeof(UInt_t)); // Swap needed for mac power pc.
217 #endif
218         
219         bool result = false;
220         try
221         {
222                 // Since we might allocate memory inside OnNewBuffer in the event
223                 // handler we need to trap any memory allocation exception to be robust.
224                 result = fDecoder.Decode(fBuffer, dataSize);
225                 fHadError = (result == true ? kFALSE : kTRUE);
226         }
227         catch (const std::bad_alloc&)
228         {
229                 AliError("Could not allocate more buffer space. Cannot decode DDL.");
230                 return kFALSE;
231         }
232
233         // Update the current bus patch pointers.
234         fCurrentBusPatch = fDecoder.GetHandler().FirstBusPatch();
235         if (fCurrentBusPatch != fDecoder.GetHandler().EndOfBusPatch())
236         {
237                 fCurrentData = fCurrentBusPatch->GetData();
238                 fEndOfData = fCurrentData + fCurrentBusPatch->GetDataCount();
239         }
240         else
241         {
242                 // If the DDL did not have any bus patches then mark both fCurrentData
243                 // and fEndOfData as NULL so that in Next() we are forced to find the
244                 // first non empty DDL.
245                 fCurrentData = fEndOfData = NULL;
246         }
247
248         fDDL++; // Remember to increment index to next DDL.
249         return kTRUE;
250 }
251
252
253 Bool_t AliMUONRawStreamTrackerHP::IsDone() const
254 {
255         /// Indicates whether the iteration is finished or not.
256         /// \return kTRUE if we already read all the digits and kFALSE if not.
257         
258         return fDone;
259 }
260
261
262 Bool_t AliMUONRawStreamTrackerHP::Next(
263                 Int_t& busPatchId, UShort_t& manuId, UChar_t& manuChannel,
264                 UShort_t& adc
265         )
266 {
267         /// Advance one step in the iteration. Returns false if finished.
268         /// [out] \param busPatchId  This is filled with the bus patch ID of the digit.
269         /// [out] \param manuId      This is filled with the MANU ID of the digit.
270         /// [out] \param manuChannel This is filled with the MANU channel ID of the digit.
271         /// [out] \param adc         This is filled with the ADC signal value of the digit.
272         /// \return kTRUE if we read another digit and kFALSE if we have read all the
273         ///    digits already, i.e. at the end of the iteration.
274         
275         if (fCurrentData == NULL) return kFALSE;
276         
277 retry:
278         // Check if we still have data to be returned for the current bus patch.
279         if (fCurrentData != fEndOfData)
280         {
281                 busPatchId = fCurrentBusPatch->GetBusPatchId();
282                 AliMUONTrackerDDLDecoderEventHandler::UnpackADC(*fCurrentData, manuId, manuChannel, adc);
283                 fCurrentData++;
284                 return kTRUE;
285         }
286         else
287         {
288                 // We hit the end of the current bus patch so check if we have any more
289                 // bus patches to process for the current DDL. If we do, then increment
290                 // the current bus patch, make sure it is not the last one and then try
291                 // reading the first element again.
292                 if (fCurrentBusPatch != fDecoder.GetHandler().EndOfBusPatch())
293                 {
294                         fCurrentBusPatch++;
295                         if (fCurrentBusPatch != fDecoder.GetHandler().EndOfBusPatch())
296                         {
297                                 fCurrentData = fCurrentBusPatch->GetData();
298                                 fEndOfData = fCurrentData + fCurrentBusPatch->GetDataCount();
299                                 goto retry;
300                         }
301                 }
302
303                 // This was the last bus patch in the DDL so read in the next one and
304                 // try reading the first data element again.
305                 // Note: fCurrentBusPatch is set inside NextDDL().
306                 if (NextDDL()) goto retry;
307         }
308         return kFALSE;
309 }
310
311
312 void AliMUONRawStreamTrackerHP::SetMaxBlock(Int_t blk)
313 {
314         /// Set maximum number of blocks per DDL allowed.
315         fDecoder.MaxBlocks( (UInt_t) blk );
316         
317         fDecoder.GetHandler().SetMaxStructs(
318                         fDecoder.MaxBlocks(),
319                         fDecoder.MaxDSPs(),
320                         fDecoder.MaxBusPatches()
321                 );
322 }
323
324
325 void AliMUONRawStreamTrackerHP::SetMaxDsp(Int_t dsp)
326 {
327         /// Set maximum number of Dsp per block allowed.
328         fDecoder.MaxDSPs( (UInt_t) dsp );
329         
330         fDecoder.GetHandler().SetMaxStructs(
331                         fDecoder.MaxBlocks(),
332                         fDecoder.MaxDSPs(),
333                         fDecoder.MaxBusPatches()
334                 );
335 }
336
337
338 void AliMUONRawStreamTrackerHP::SetMaxBus(Int_t bus)
339 {
340         /// Set maximum number of Buspatch per Dsp allowed.
341         fDecoder.MaxBusPatches( (UInt_t) bus );
342         
343         fDecoder.GetHandler().SetMaxStructs(
344                         fDecoder.MaxBlocks(),
345                         fDecoder.MaxDSPs(),
346                         fDecoder.MaxBusPatches()
347                 );
348 }
349
350 ///////////////////////////////////////////////////////////////////////////////
351
352 void AliMUONRawStreamTrackerHP::AliBlockHeader::Print() const
353 {
354         /// Print header to screen.
355         
356         cout << "CRT info"        << endl;
357         if (fHeader == NULL)
358         {
359                 cout << "Header is NULL" << endl;
360                 return;
361         }
362         cout << "DataKey: 0x"     << hex << fHeader->fDataKey << dec << endl;
363         cout << "TotalLength: "   << fHeader->fTotalLength << endl;
364         cout << "Length: "        << fHeader->fLength << endl;
365         cout << "DspId: "         << fHeader->fDSPId << endl;
366         cout << "L0Trigger: "     << fHeader->fL0Trigger << endl;
367         cout << "MiniEventId: "   << fHeader->fMiniEventId<< endl; 
368         cout << "EventId1: "      << fHeader->fEventId1 << endl;
369         cout << "EventId2: "      << fHeader->fEventId2 << endl;
370 }
371
372
373 void AliMUONRawStreamTrackerHP::AliDspHeader::Print() const
374 {
375         /// Print header to screen.
376         
377         cout << "FRT info"        << endl;
378         if (fHeader == NULL)
379         {
380                 cout << "Header is NULL" << endl;
381                 return;
382         }
383         cout << "DataKey: 0x"     << hex << fHeader->fDataKey << dec << endl;
384         cout << "TotalLength: "   << fHeader->fTotalLength << endl;
385         cout << "Length : "       << fHeader->fLength << endl;
386         cout << "DspId: "         << fHeader->fDSPId << endl;
387         cout << "BlkL1ATrigger: " << fHeader->fBlkL1ATrigger << endl;
388         cout << "MiniEventId: "   << fHeader->fMiniEventId << endl;
389         cout << "L1ATrigger: "    << fHeader->fL1ATrigger << endl;
390         cout << "L1RTrigger: "    << fHeader->fL1RTrigger << endl;
391         cout << "PaddingWord: "   << fHeader->fPaddingWord << endl;
392         cout << "ErrorWord: "     << fHeader->fErrorWord << endl;
393 }
394
395
396 void AliMUONRawStreamTrackerHP::AliBusPatch::Print(const Option_t* opt) const
397 {
398         /// Print header to screen.
399         cout << "Bus patch info" << endl;
400         if (fHeader == NULL)
401         {
402                 cout << "Header is NULL" << endl;
403                 return;
404         }
405         cout << "DataKey: 0x"    << hex << fHeader->fDataKey << dec << endl;
406         cout << "fTotalLength: " << fHeader->fTotalLength << endl;
407         cout << "fLength: "      << fHeader->fLength << endl;
408         cout << "fBusPatchId: "  << fHeader->fBusPatchId << endl;
409
410         if (TString(opt).Contains("all"))
411         {
412                 for (UInt_t i = 0; i < fHeader->fLength; ++i)
413                         cout << "Data["<< i << "] = " << fData[i] << endl;
414         }
415 }
416
417 ///////////////////////////////////////////////////////////////////////////////
418
419 AliMUONRawStreamTrackerHP::AliDecoderEventHandler::AliDecoderEventHandler() :
420         fRawStream(NULL),
421         fBufferStart(NULL),
422         fBlockCount(0),
423         fBlocks(NULL),
424         fDSPs(NULL),
425         fBusPatches(NULL),
426         fEndOfBusPatches(NULL),
427         fMaxChannels(8192),
428         fParityOk(new Bool_t[8192]),
429         fCurrentBlock(NULL),
430         fCurrentDSP(NULL),
431         fCurrentBusPatch(NULL),
432         fCurrentParityOkFlag(NULL),
433         fParityErrors(0),
434         fGlitchErrors(0),
435         fPaddingErrors(0),
436         fWarnings(kTRUE)
437 {
438         /// Default constructor initialises the internal parity flags buffer to
439         /// store 8192 elements. This array will grow dynamically if needed.
440 }
441
442
443 AliMUONRawStreamTrackerHP::AliDecoderEventHandler::~AliDecoderEventHandler()
444 {
445         /// Default destructor cleans up the allocated memory.
446         
447         if (fParityOk != NULL) delete [] fParityOk;
448         if (fBlocks != NULL) delete [] fBlocks;
449         if (fDSPs != NULL) delete [] fDSPs;
450         if (fBusPatches != NULL) delete [] fBusPatches;
451 }
452
453
454 void AliMUONRawStreamTrackerHP::AliDecoderEventHandler::SetMaxStructs(
455                 UInt_t maxBlocks, UInt_t maxDsps, UInt_t maxBusPatches
456         )
457 {
458         /// Sets the maximum number of structures allowed.
459         
460         // Start by clearing the current arrays.
461         if (fBlocks != NULL)
462         {
463                 delete [] fBlocks;
464                 fBlocks = NULL;
465         }
466         if (fDSPs != NULL)
467         {
468                 delete [] fDSPs;
469                 fDSPs = NULL;
470         }
471         if (fBusPatches != NULL)
472         {
473                 delete [] fBusPatches;
474                 fBusPatches = NULL;
475         }
476         fCurrentBlock = NULL;
477         fCurrentDSP = NULL;
478         fCurrentBusPatch = NULL;
479         
480         // Allocate new memory.
481         fBlocks = new AliBlockHeader[maxBlocks];
482         fDSPs = new AliDspHeader[maxBlocks*maxDsps];
483         fBusPatches = new AliBusPatch[maxBlocks*maxDsps*maxBusPatches];
484         fEndOfBusPatches = fBusPatches;
485 }
486
487
488 void AliMUONRawStreamTrackerHP::AliDecoderEventHandler::OnNewBuffer(
489                 const void* buffer, UInt_t bufferSize
490         )
491 {
492         /// This is called by the high performance decoder when a new DDL payload
493         /// is about to be decoded.
494         /// \param buffer  The pointer to the buffer storing the DDL payload.
495         /// \param bufferSize  The size of the buffer in bytes.
496
497         assert( fRawStream != NULL );
498         
499         // remember the start of the buffer to be used in OnError.
500         fBufferStart = buffer;
501
502         // Reset error counters.
503         fParityErrors = 0;
504         fGlitchErrors = 0;
505         fPaddingErrors = 0;
506
507         // Check if we will have enough space in the fParityOk array.
508         // If we do not then we need to resize the array.
509         // bufferSize / sizeof(UInt_t) will be a safe over estimate of the
510         // number of channels that we will find.
511         UInt_t maxChannelsPossible = bufferSize / sizeof(UInt_t);
512         if (maxChannelsPossible > fMaxChannels)
513         {
514                 if (fParityOk != NULL)
515                 {
516                         delete [] fParityOk;
517                         fParityOk = NULL;
518                         fMaxChannels = 0;
519                 }
520                 fParityOk = new Bool_t[maxChannelsPossible];
521                 fMaxChannels = maxChannelsPossible;
522         }
523         
524         // Reset the current pointers which will be used to track where we need to
525         // fill fBlocks, fDSPs, fBusPatches and the parity flag. We have to subtract
526         // one space because we will increment the pointer the first time in the
527         // OnNewXZY methods.
528         fCurrentBlock = fBlocks-1;
529         fCurrentDSP = fDSPs-1;
530         fCurrentBusPatch = fBusPatches-1;
531         fCurrentParityOkFlag = fParityOk-1;
532         fBlockCount = 0;
533 }
534
535
536 void AliMUONRawStreamTrackerHP::AliDecoderEventHandler::OnError(
537                 ErrorCode error, const void* location
538         )
539 {
540         /// This is called by the high performance decoder when a error occurs
541         /// when trying to decode the DDL payload. This indicates corruption in
542         /// the data. This method converts the error code to a descriptive message
543         /// and logs this with the raw reader.
544         /// \param error  The error code indicating the problem.
545         /// \param location  A pointer to the location within the DDL payload buffer
546         ///              being decoded where the problem with the data was found.
547
548         assert( fRawStream != NULL );
549         assert( fRawStream->GetReader() != NULL );
550         
551         Char_t* message = NULL;
552         UInt_t word = 0;
553
554         switch (error)
555         {
556         case kGlitchFound:
557                 fGlitchErrors++;
558                 message = Form(
559                         "Glitch error detected in DSP %d, skipping event ",
560                         fCurrentBlock->GetDspId()
561                 );
562                 fRawStream->GetReader()->AddMajorErrorLog(error, message);
563                 break;
564
565         case kBadPaddingWord:
566                 fPaddingErrors++;
567                 // We subtract 1 from the current numbers of blocks, DSPs
568                 // and bus patches to get the indices.
569                 message = Form(
570                         "Padding word error for iBlock %d, iDsp %d, iBus %d\n", 
571                         fBlockCount-1,
572                         fCurrentBlock->GetDspCount()-1,
573                         fCurrentDSP->GetBusPatchCount()-1
574                 );
575                 fRawStream->GetReader()->AddMinorErrorLog(error, message);
576                 break;
577
578         case kParityError:
579                 fParityErrors++;
580                 // location points to the incorrect data word and
581                 // fCurrentBusPatch->GetData() returns a pointer to the start of
582                 // bus patches data, so the difference divided by 4 gives the 32
583                 // bit word number.
584                 word = ((unsigned long)location - (unsigned long)fCurrentBusPatch->GetData())
585                                 / sizeof(UInt_t);
586                 message = Form(
587                         "Parity error in word %d for manuId %d and channel %d in buspatch %d\n", 
588                         word,
589                         fCurrentBusPatch->GetManuId(word),
590                         fCurrentBusPatch->GetChannelId(word),
591                         fCurrentBusPatch->GetBusPatchId()
592                 );
593                 fRawStream->GetReader()->AddMinorErrorLog(error, message);
594                 break;
595
596         default:
597                 message = Form(
598                         "%s (At byte %d in DDL.)",
599                         ErrorCodeToMessage(error),
600                         (unsigned long)location - (unsigned long)fBufferStart + sizeof(AliRawDataHeader)
601                 );
602                 fRawStream->GetReader()->AddMajorErrorLog(error, message);
603                 break;
604         }
605
606         if (fWarnings)
607         {
608                 AliWarningGeneral(
609                                 "AliMUONRawStreamTrackerHP::AliDecoderEventHandler",
610                                 message
611                         );
612         }
613 }
614