2e2cc0c938c3e57f3942693a504ae0adc6bfbf5e
[u/mrichter/AliRoot.git] / HLT / BASE / AliHLTDataBuffer.h
1 //-*- Mode: C++ -*-
2 // $Id$
3
4 #ifndef ALIHLTDATABUFFER_H
5 #define ALIHLTDATABUFFER_H
6 //* This file is property of and copyright by the ALICE HLT Project        * 
7 //* ALICE Experiment at CERN, All rights reserved.                         *
8 //* See cxx source for full Copyright notice                               *
9
10 //  @file   AliHLTDataBuffer.h
11 //  @author Matthias Richter
12 //  @date   
13 //  @brief  Handling of Data Buffers for HLT components.
14 //  @note   The class is used in Offline (AliRoot) context
15
16 // see below for class documentation
17 // or
18 // refer to README to build package
19 // or
20 // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
21
22 #include <vector>
23 #include "TObject.h"
24 #include "AliHLTLogging.h"
25 #include "AliHLTDataTypes.h"
26 #include "AliHLTComponent.h"
27
28 class AliHLTConsumerDescriptor;
29 class AliHLTTask;
30
31 /** list of AliHLTConsumerDescriptor pointers */
32 typedef vector<AliHLTConsumerDescriptor*> AliHLTConsumerDescriptorPList;
33
34 typedef AliHLTUInt8_t* AliHLTUInt8Pointer_t;
35
36 /**
37  * @class AliHLTDataBuffer
38  * @brief  Handling of data buffers for the HLT.
39  * 
40  * The class provides handling of data buffers for HLT tasks. Each task gets
41  * its own Data Buffer instance. The buffer is grouped into different data
42  * segments according to the output of the component.<br>
43  * The Data Buffer keeps control over the data requests of the 'child'
44  * components. Each component can subscribe to a certain segment of the data
45  * buffer. It's state is then changed from 'reserved' to 'active'. After the
46  * data processing, the component has to release the segment and it's state is
47  * set to 'processed'. If all components have requested and released their data,
48  * the Raw Buffer is released and pushed back in the list of available buffers.
49  *
50  * @note This class is only used for the @ref alihlt_system.
51  *
52  * @ingroup alihlt_system
53  */
54 class AliHLTDataBuffer : public TObject, public AliHLTLogging 
55 {
56  public:
57   //////////////////////////////////////////////////////////////////////////////
58   // constructors and destructors
59
60   /* standard constructor
61    */
62   AliHLTDataBuffer();
63   /** destructor */
64   virtual ~AliHLTDataBuffer();
65
66   //////////////////////////////////////////////////////////////////////////////
67   // initialization
68
69   /**
70    * Add component to the list of consumers
71    * @param pConsumer - a consumer of type AliHLTComponent
72    */
73   int SetConsumer(AliHLTComponent* pConsumer);
74
75   //////////////////////////////////////////////////////////////////////////////
76   // component to component communication
77
78   /**
79    * Determine the number of matching data blocks for the component and a
80    * consumer component. <br>
81    * The first approach will support only one output data type for processing
82    * components.
83    * @param pConsumer       the component which subscribes to the buffer
84    * @param tgtList         (optional) the list to receive the data types
85    * @return: number of data blocks which match the input data types 
86    *          of the consumer, neg. error code if failed <br>
87    *          -EINVAL       invalid parameter <br>
88    */
89   int FindMatchingDataBlocks(const AliHLTComponent* pConsumer,
90                              AliHLTComponentDataTypeList* tgtList=NULL);
91
92   /**
93    * Subscribe to a segment of the data buffer.
94    * The function prepares the block descriptor for subsequent use with the
95    * AliHLTComponent::ProcessEvent method, the method can prepare several block
96    * descriptors up to the array size specified by iArraySize. The return value
97    * is independent from the array size the number of block descriptors which
98    * would have been prepared if there was enough space in the array<br>
99    * The method is used by the consumer component.
100    * @param pConsumer       the component which subscribes to the buffer
101    * @param blockDescList   block descriptor vector to be filled
102    * @return: number of matching data blocks, neg. error code if failed<br>
103    *          -EACCESS      the consumer state can't be changed (activated)
104    *          -EBADF        unresolved data segments <br>
105    *          -ENOENT       consumer component not found <br>
106    *          -ENODATA      data buffer does not have raw data <br>
107    *          -EINVAL       invalid parameter <br>
108    */
109   int Subscribe(const AliHLTComponent* pConsumer,
110                 AliHLTComponentBlockDataList& blockDescList);
111
112   /**
113    * Release an instance of the data buffer.
114    * Resets the variables of the block descriptor.
115    * If all buffer segments are released, the Data Buffer is reseted
116    * and the Raw Buffer released.<br>
117    * The method is used by the consumer component.
118    * @param pBlockDesc      descriptor of the data segment
119    * @param pConsumer       the component which subscribes to the buffer
120    * @param pOwnerTask      task owning this buffer
121    * @return: >0 if success, negative error code if failed <br>
122    *          -EACCESS      the consumer state can not be changed (de-activated)
123    *          -ENOENT       consumer has not subscribed to the buffer <br>
124    *          -EINVAL       invalid parameter <br>
125    */
126   int Release(AliHLTComponentBlockData* pBlockDesc, const AliHLTComponent* pConsumer,
127               const AliHLTTask* pOwnerTask);
128
129   /**
130    * Release a forwarded data block.
131    */
132   int ReleaseForwardedBlock(AliHLTComponentBlockData* pBlockDesc,
133                              const AliHLTTask* pOwnerTask);
134
135   /**
136    * Register an input data block for forwarding.
137    * Consumer of this data buffer subscribe to forwarded data blocks in te same way.
138    * Forwarded data blocks are released when the last consumer has released the
139    * blocks.
140    * @param pSrcTask        original source task of the data block
141    * @param pBlockDesc      descriptor of the data segment
142    */
143   int Forward(AliHLTTask* pSrcTask, AliHLTComponentBlockData* pBlockDesc);
144
145   /**
146    * Get a target buffer of minimum size iMinSize.
147    * The method is used by the component which owns the Data Buffer to 
148    * allocate a buffer for the data it is going to produce.
149    * @param iMinSize        minumum size of the requested buffer
150    * @return: pointer to target buffer if 
151    */
152   AliHLTUInt8_t* GetTargetBuffer(int iMinSize);
153
154   /**
155    * Set the segments for the data buffer.
156    * This is usually done after the component has written the data to the buffer, 
157    * which was requested by the @ref GetTargetBuffer method. The component might
158    * produce different types of data, for each type a segment has to be defined
159    * which describes the data inside the buffer.<br>
160    * The @ref AliHLTComponentBlockData segment descriptor comes directly from
161    * the @ref AliHLTComponent::ProcessEvent method.
162    * @param pTgt            the target buffer which the segments refer to
163    * @param arraySegments   the output block descriptors of the component
164    * @param iSize           size of the array
165    */
166   int SetSegments(AliHLTUInt8_t* pTgt, AliHLTComponentBlockData* arraySegments, int iSize);
167
168   /**
169    * Check if the data buffer is empty.
170    * @return 1 if empty, 0 if not
171    */
172   int IsEmpty();
173
174   /**
175    * Get the total and maximum size of the buffer.
176    * Lets see if this is needed later
177    */
178   //int GetTotalSize();
179
180   /**
181    * Get the number of segments including the forwarded data blocks.
182    * @return number of segments
183    */
184   int GetNofSegments();
185
186   /**
187    * Get the total number of consumers.
188    * This gives the number of consumers regardless of their state.
189    * @return number of consumers
190    */
191   int GetNofConsumers();
192
193   /**
194    * Get the number of consumers which still need to be processed during
195    * the current event.
196    * @return number of consumers
197    */
198   int GetNofPendingConsumers();
199
200   /**
201    * Get the number of consumers currently under processing.
202    * @return number of active consumers
203    */
204   int GetNofActiveConsumers();
205
206   /**
207    * Check if a consumer is already in the list
208    * @param pConsumer   pointer to consumer component
209    * @param bAllLists   search in all lists if 1
210    *                    search only in fConsumer list if 0
211    * @return 1 if found, 0 if not
212    */
213   int FindConsumer(const AliHLTComponent* pConsumer, int bAllLists=1);
214
215   /**
216    * Public method to reset the buffer.
217    * Eventually with some additional checks. In normal operation,
218    * an external reset should not be necessary.
219    */
220   int Reset();
221
222   /**
223    * Set local logging level
224    * logging filter for individual object
225    */
226   void SetLocalLoggingLevel(AliHLTComponentLogSeverity level)
227   {fgLogging.SetLocalLoggingLevel(level); AliHLTLogging::SetLocalLoggingLevel(level);}
228
229   /**
230    * Print summary of the global buffer management.
231    */
232   static int PrintStatistics();
233
234   /**
235    * Set the global event count.
236    * The event count is deployed to find buffers which have not been used
237    * for a while. In such a case to policy to find an appropriate buffer is
238    * adjusted.
239    */
240   static int SetGlobalEventCount(AliHLTUInt32_t eventCount) {fgEventCount=eventCount; return 0;}
241
242   /**
243    * @class AliHLTDataSegment
244    * @brief  Descriptor of a data segment within the buffer.
245    */
246   class AliHLTDataSegment {
247   public:
248     AliHLTDataSegment()
249       :
250       fDataType(kAliHLTVoidDataType),
251       fPtr(NULL),
252       fSegmentOffset(0),
253       fSegmentSize(0),
254       fSpecification(0)
255     {
256     }
257
258     AliHLTDataSegment(AliHLTUInt8_t* ptr, AliHLTUInt32_t offset, AliHLTUInt32_t size) 
259       :
260       fDataType(kAliHLTVoidDataType),
261       fPtr(ptr),
262       fSegmentOffset(offset),
263       fSegmentSize(size),
264       fSpecification(0)
265     {
266     }
267
268     AliHLTDataSegment(void* ptr, AliHLTUInt32_t offset, AliHLTUInt32_t size) 
269       :
270       fDataType(kAliHLTVoidDataType),
271       fPtr(reinterpret_cast<AliHLTUInt8_t*>(ptr)),
272       fSegmentOffset(offset),
273       fSegmentSize(size),
274       fSpecification(0)
275     {
276     }
277
278     AliHLTDataSegment(void* ptr, AliHLTUInt32_t offset, AliHLTUInt32_t size, AliHLTComponentDataType dt, AliHLTUInt32_t spec)
279       :
280       fDataType(dt),
281       fPtr(reinterpret_cast<AliHLTUInt8_t*>(ptr)),
282       fSegmentOffset(offset),
283       fSegmentSize(size),
284       fSpecification(spec)
285     {
286     }
287
288     AliHLTUInt8_t* GetPtr() const {return (AliHLTUInt8_t*)*this;}
289
290     AliHLTUInt32_t GetSize() const {return fSegmentSize;}
291     
292     int operator==(const AliHLTDataSegment& seg) const
293     {
294       return (fPtr+fSegmentOffset==seg.fPtr+seg.fSegmentOffset) && (fSegmentSize==seg.fSegmentSize);
295     }
296     operator AliHLTUInt8_t*() const {return fPtr+fSegmentOffset;}
297
298   private:
299     /** the data type of this segment */
300     AliHLTComponentDataType fDataType;                             // see above
301     /** pointer to the buffer */
302     AliHLTUInt8Pointer_t fPtr;                                     //!transient
303     /** offset in byte within the data buffer */
304     AliHLTUInt32_t fSegmentOffset;                                 // see above
305     /** size of the actual content */
306     AliHLTUInt32_t fSegmentSize;                                   // see above
307     /** data specification */
308     AliHLTUInt32_t fSpecification;                                 // see above
309
310     friend class AliHLTDataBuffer; // TODO: implement some getters/setters
311   };
312
313   class AliHLTRawBuffer;
314   typedef vector<AliHLTRawBuffer*>  AliHLTRawBufferPList;
315
316   /**
317    * @class AliHLTRawPage
318    * Memory allocation is organized in pages of a fixed size. Within a
319    * page, AliHLTRawBuffer chunks are created.
320    */
321   class AliHLTRawPage : public AliHLTLogging {
322   public:
323     /** standard constructor */
324   AliHLTRawPage() : fSize(0), fPtr(NULL), fFreeBuffers(), fUsedBuffers() {}
325     /** constructor */
326     AliHLTRawPage(AliHLTUInt32_t pagesize);
327     /** destructor */
328     virtual ~AliHLTRawPage();
329
330     /** alloc a buffer of specified size from the global pages*/
331     static AliHLTRawBuffer* GlobalAlloc(AliHLTUInt32_t size, int verbosity=0);
332     /** find buffer in the global pages */
333     static AliHLTRawPage* FindPage(AliHLTRawBuffer* buffer);
334     /** cleanup the global pages */
335     static int GlobalClean();
336     /** adjust global page size */
337     static void SetGlobalPageSize(AliHLTUInt32_t size) {fgGlobalPageSize=size;}
338     /** find next page after prev, or first page */
339     static AliHLTRawPage* NextPage(const AliHLTRawPage* prev=NULL);
340
341     /** alloc a buffer of specified size */
342     AliHLTRawBuffer* Alloc(AliHLTUInt32_t size);
343     /** free a buffer and merge consecutive free buffers */
344     int Free(AliHLTRawBuffer* pBuffer);
345     /** set the size of a raw buffer and release the remaining part */
346     int SetSize(const AliHLTRawBuffer* pBuffer, AliHLTUInt32_t size);
347     /// check if the buffer is in this page
348     bool HasBuffer(const AliHLTRawBuffer* pBuffer);
349
350     AliHLTUInt32_t Size() const {return fSize;}
351     AliHLTUInt32_t Capacity() const;
352     bool IsUsed() const {return fUsedBuffers.size()>0;}
353     bool IsFragmented() const {return (fFreeBuffers.size()+fUsedBuffers.size())>1;}
354
355     /**
356      * Print page information
357      */
358     void Print(const char* option);
359
360   private:
361     /** copy constructor prohibited */
362     AliHLTRawPage(const AliHLTRawPage&);
363     /** assignment operator prohibited */
364     AliHLTRawPage& operator=(const AliHLTRawPage&);
365
366     /// list of global pages
367     static vector<AliHLTDataBuffer::AliHLTRawPage*> fgGlobalPages; //! transient
368     /// pages size of global pages
369     static AliHLTUInt32_t fgGlobalPageSize;                        //! transient
370
371     /** page size */
372     AliHLTUInt32_t fSize;                                          // see above
373     /** the memory segment */
374     AliHLTUInt8_t* fPtr;                                           //! transient
375
376     /** list of free buffers */
377     AliHLTRawBufferPList fFreeBuffers;                             //! transient
378     /** list of used buffers */
379     AliHLTRawBufferPList fUsedBuffers;                             //! transient
380   };
381
382   /**
383    * @class AliHLTRawBuffer
384    * @brief  Descriptor of the raw data buffer which can host several segments.
385    */
386   class AliHLTRawBuffer {
387   public:
388     /** standard constructor */
389   AliHLTRawBuffer() : fSize(0), fTotalSize(0), fExternalPtr(NULL), fPtr(NULL), fLastEventCount(0) {}
390     /** constructor */
391     AliHLTRawBuffer(AliHLTUInt32_t size);
392     /** constructor */
393     AliHLTRawBuffer(AliHLTUInt32_t size, AliHLTUInt8_t* buffer);
394     /** destructor */
395     virtual ~AliHLTRawBuffer();
396
397     /**
398      * Use a fraction of the buffer.
399      * @param size    size in bytes to be used
400      * @return pointer to buffer
401      */
402     AliHLTUInt8_t* UseBuffer(AliHLTUInt32_t size);
403
404     /**
405      * split a buffer at specified size
406      * only possible for buffers with external memory
407      */
408     AliHLTRawBuffer* Split(AliHLTUInt32_t size);
409
410     /**
411      * Check whether buffer fits for a request.
412      * A buffer fits if it is at least of the requested size and at most
413      * the requested size plus a margin. The margin increases with the
414      * number of events the buffer has not been used.
415      * @param size    size of the request in bytes
416      * @return 1 if buffer is big enough, 0 if not
417      */
418     int CheckSize(AliHLTUInt32_t size) const;
419
420     /**
421      * Get used size of the buffer
422      */
423     AliHLTUInt32_t GetUsedSize() const {return fSize;}
424
425     /**
426      * Get total size of the buffer
427      */
428     AliHLTUInt32_t GetTotalSize() const {return fTotalSize;}
429
430     /**
431      * Get pointer of data buffer
432      */
433     AliHLTUInt8_t* GetPointer() const {return fPtr;}
434
435     /**
436      * Write check pattern
437      */
438     int WritePattern(const char* pattern, int size);
439
440     /**
441      * Check pattern
442      */
443     int CheckPattern(const char* pattern, int size) const;
444
445     /**
446      * Reset buffer.
447      * Data buffer remains allocated, used size set to 0
448      */
449     int Reset();
450
451     /*
452      * Merge buffer with succeeding buffer.
453      * Only possible if the buffers are consecutive with out any gap.
454      */
455     int Merge(const AliHLTRawBuffer& succ);
456
457     /**
458      * Print buffer information
459      */
460     void Print(const char* option);
461
462     int operator==(void*) const;
463     int operator==(AliHLTUInt8_t* ptr) const {return fPtr==ptr;}
464     int operator<(void*) const;
465     int operator<=(void*) const;
466     int operator>(void*) const;
467     int operator-(void*) const;
468     int operator<(const AliHLTRawBuffer&) const;
469     int operator<=(const AliHLTRawBuffer&) const;
470     int operator>(const AliHLTRawBuffer&) const;
471
472     operator void*() const {return fPtr;}
473     operator AliHLTUInt8_t*() const {return fPtr;}
474
475   private:
476     /** copy constructor prohibited */
477     AliHLTRawBuffer(const AliHLTRawBuffer&);
478     /** assignment operator prohibited */
479     AliHLTRawBuffer& operator=(const AliHLTRawBuffer&);
480
481     /** size of the currently occupied partition of the buffer */
482     AliHLTUInt32_t fSize;                                          // see above
483     /** total size of the buffer, including safety margin */
484     AliHLTUInt32_t fTotalSize;                                     // see above
485     /** optional external buffer */
486     AliHLTUInt8_t* fExternalPtr;                                   //! transient
487     /** the buffer, external or allocated */
488     AliHLTUInt8_t* fPtr;                                           //! transient
489     /** last event count where the buffer has been used */
490     AliHLTUInt32_t fLastEventCount;                                //! transient
491   };
492
493  private:
494   /** copy constructor prohibited */
495   AliHLTDataBuffer(const AliHLTDataBuffer&);
496   /** assignment operator prohibited */
497   AliHLTDataBuffer& operator=(const AliHLTDataBuffer&);
498
499   /* lets see if this is needed
500      AliHLTDataSegment* FindDataSegment(AliHLTComponentDataType datatype);
501   */
502
503   /**
504    * Find those data segments which match the input types of a component.
505    * @param pConsumer       the component which subscribes to the buffer
506    * @param tgtList         the list to receive the data segment descriptors
507    * @return: number of data blocks which match the input data types 
508    *          of the consumer, neg. error code if failed <br>
509    *          -EINVAL       invalid parameter <br>
510    */
511   int FindMatchingDataSegments(const AliHLTComponent* pConsumer, 
512                                vector<AliHLTDataBuffer::AliHLTDataSegment>& tgtList);
513
514  protected:
515   // 2010-02-01 make function protected in order to be used from unit test
516   /**
517    * Reset the data buffer.
518    * Removes all consumers back to the @ref fConsumers list, deletes
519    * segments and releases the Raw Buffer.
520    */
521   int ResetDataBuffer();
522  private:
523
524   //////////////////////////////////////////////////////////////////////////////
525
526   // the data description
527
528   // the data segments within this buffer
529   vector<AliHLTDataSegment> fSegments;                             // see above
530
531   // the list of all consumers which are going to subscribe to the buffer
532   AliHLTConsumerDescriptorPList fConsumers;                         // see above
533   // the list of all consumers which are currently subscribed to the buffer
534   AliHLTConsumerDescriptorPList fActiveConsumers;                   // see above
535   // the list of all consumers which are already released for the current event
536   AliHLTConsumerDescriptorPList fReleasedConsumers;                 // see above
537
538   // the buffer instance
539   AliHLTRawBuffer* fpBuffer;                                       //! transient
540
541   // flags indicating the state of the buffer
542   AliHLTUInt32_t fFlags;                                           // see above
543
544   /** list of tasks with forwarded data blocks */
545   vector<AliHLTTask*> fForwardedSegmentSources;                    //! transient
546
547   /** list of forwarded block descriptors */
548   vector<AliHLTDataSegment> fForwardedSegments;                    //! transient
549
550   //////////////////////////////////////////////////////////////////////////////
551   // global buffer handling, internal use only
552
553   /**
554    * Create a raw buffer of a certain size.
555    * The function tries to find a buffer of the given size (or a bit bigger by a 
556    * certain margin @ref fgMargin) from the list of free buffers.
557    * If no buffer is available, a new one is created and added to the buffer handling.
558    * @param size            min. size of the requested buffer
559    * @return pointer to raw buffer
560    */
561   static AliHLTRawBuffer* CreateRawBuffer(AliHLTUInt32_t size);
562
563   /**
564    * Set the data size of a raw buffer after it has been filled by
565    * the component.
566    */
567   int SetRawBufferDataSize(AliHLTRawBuffer* pBuffer, AliHLTUInt32_t size) const;
568
569   /**
570    * Mark a buffer as free.
571    * After the Data Buffer has finnished using the raw buffer, it is released
572    * and added to the list of available buffers.
573    * @param pBuffer         the raw buffer to release
574    * @return >=0 if succeeded, neg. error code if failed
575    */
576   static int ReleaseRawBuffer(AliHLTRawBuffer* pBuffer);
577
578   /**
579    * Deletes all the raw buffers.
580    * When the last Data Buffer object is destructed, all raw data buffers are
581    * relesed.
582    */
583   static int DeleteRawBuffers();
584
585   /**
586    * Number of instances of AliHLTDataBuffer.
587    * The statice variable is incremented and decremented in the constructor/
588    * destructor. All internal data structures are cleaned up when the last
589    * instance is exiting.
590    */
591   static int fgNofInstances;                                       // see above
592   /** global list of free raw buffers */
593   static vector<AliHLTRawBuffer*> fgFreeBuffers;                   // see above
594   /** global list of currently active raw buffers */
595   static vector<AliHLTRawBuffer*> fgActiveBuffers;                 // see above
596   /** determines the raw buffer size margin at buffer requests */
597   static AliHLTUInt32_t fgMargin;                                  // see above
598
599   /** global instance to HLT logging class for static methods */
600   static AliHLTLogging fgLogging;                                  // see above
601
602   /** size of the safety pattern */
603   static const Int_t fgkSafetyPatternSize;                         // see above
604
605   /** the safety pattern */
606   static const char fgkSafetyPattern[];                            //!transient
607
608   static AliHLTUInt32_t fgEventCount;                              //!transient
609
610   //////////////////////////////////////////////////////////////////////////////
611   // internal helper functions
612
613   /**
614    * Find the consumer descriptor for a certain component and data type in 
615    * a list of consumers.<br>
616    * <b>Note:</b> There are three lists which contain the consumers in the
617    * different states.
618    * @param pConsumer       pointer to consumer component
619    * @param list            list where to search for the consumer
620    */
621   AliHLTConsumerDescriptor* FindConsumer(const AliHLTComponent* pConsumer,
622                                          AliHLTConsumerDescriptorPList &list) const;
623
624   /**
625    * Change the state of a consumer.
626    * The state of a consumer is determined by the list it is strored in, the
627    * method moves a consumer from the source to the target list.
628    * @param pDesc           pointer to consumer descriptor
629    * @param srcList         list where the consumer is currently to be found
630    * @param tgtList         list where to move the consumer
631    */
632   int ChangeConsumerState(AliHLTConsumerDescriptor* pDesc,
633                           AliHLTConsumerDescriptorPList &srcList,
634                           AliHLTConsumerDescriptorPList &tgtList);
635
636   /**
637    * Cleanup a consumer list.
638    * Release all allocated data structures. <b>Note:</b> Not the component itself!
639    */
640   int CleanupConsumerList();
641
642   ClassDef(AliHLTDataBuffer, 1)
643 };
644
645 #endif // ALIHLTDATABUFFER_H