first sketch of optimized memory handling for component output buffers
authorrichterm <richterm@f7af4fe6-9843-0410-8265-dc069ae4e863>
Tue, 1 Dec 2009 13:56:46 +0000 (13:56 +0000)
committerrichterm <richterm@f7af4fe6-9843-0410-8265-dc069ae4e863>
Tue, 1 Dec 2009 13:56:46 +0000 (13:56 +0000)
the code is not yet active

HLT/BASE/AliHLTDataBuffer.cxx
HLT/BASE/AliHLTDataBuffer.h
HLT/BASE/HLTbaseLinkDef.h

index a057783..79531d5 100644 (file)
@@ -36,7 +36,6 @@ using namespace std;
 //#include "AliHLTSystem.h"
 
 typedef vector<AliHLTDataBuffer::AliHLTDataSegment> AliHLTDataSegmentList;
-typedef vector<AliHLTDataBuffer::AliHLTRawBuffer*>  AliHLTRawBufferPList;
 
 /** ROOT macro for the implementation of ROOT specific class methods */
 ClassImp(AliHLTDataBuffer)
@@ -65,8 +64,8 @@ AliHLTDataBuffer::AliHLTDataBuffer()
 }
 
 int AliHLTDataBuffer::fgNofInstances=0;
-AliHLTRawBufferPList AliHLTDataBuffer::fgFreeBuffers;
-AliHLTRawBufferPList AliHLTDataBuffer::fgActiveBuffers;
+AliHLTDataBuffer::AliHLTRawBufferPList AliHLTDataBuffer::fgFreeBuffers;
+AliHLTDataBuffer::AliHLTRawBufferPList AliHLTDataBuffer::fgActiveBuffers;
 AliHLTUInt32_t AliHLTDataBuffer::fgMargin=1024;
 AliHLTLogging AliHLTDataBuffer::fgLogging;
 const Int_t AliHLTDataBuffer::fgkSafetyPatternSize=16;
@@ -724,11 +723,11 @@ int AliHLTDataBuffer::FindConsumer(const AliHLTComponent* pConsumer, int bAllLis
 }
 
 AliHLTDataBuffer::AliHLTRawBuffer::AliHLTRawBuffer(AliHLTUInt32_t size)
-  :
-  fSize(0),
-  fTotalSize(size),
-  fPtr(static_cast<AliHLTUInt8_t*>(malloc(size))),
-  fLastEventCount(0)
+  : fSize(0)
+  , fTotalSize(size)
+  , fExternalPtr(NULL)
+  , fPtr(static_cast<AliHLTUInt8_t*>(malloc(size)))
+  fLastEventCount(0)
 {
   // see header file for class documentation
   // or
@@ -741,9 +740,19 @@ AliHLTDataBuffer::AliHLTRawBuffer::AliHLTRawBuffer(AliHLTUInt32_t size)
   }
 }
 
+AliHLTDataBuffer::AliHLTRawBuffer::AliHLTRawBuffer(AliHLTUInt32_t size, AliHLTUInt8_t* buffer)
+  : fSize(0)
+  , fTotalSize(size)
+  , fExternalPtr(buffer)
+  , fPtr(fExternalPtr)
+  , fLastEventCount(0)
+{
+  // see header file for class documentation
+}
+
 AliHLTDataBuffer::AliHLTRawBuffer::~AliHLTRawBuffer()
 {
-  if (fPtr) {
+  if (fExternalPtr==NULL && fPtr) {
     free(fPtr);
   }
   fPtr=NULL;
@@ -757,6 +766,14 @@ int AliHLTDataBuffer::AliHLTRawBuffer::operator==(void* ptr) const
   return fPtr == static_cast<AliHLTUInt8_t*>(ptr);
 }
 
+int AliHLTDataBuffer::AliHLTRawBuffer::operator<(void* ptr) const
+{
+  // see header file for function documentation
+  int iResult=fPtr < static_cast<AliHLTUInt8_t*>(ptr);
+  //printf("%p: %p <= %p (%d)\n", this, fPtr, ptr, iResult);
+  return iResult;
+}
+
 int AliHLTDataBuffer::AliHLTRawBuffer::operator<=(void* ptr) const
 {
   // see header file for function documentation
@@ -779,9 +796,27 @@ int AliHLTDataBuffer::AliHLTRawBuffer::operator-(void* ptr) const
   return static_cast<int>(static_cast<AliHLTUInt8_t*>(ptr)-fPtr);
 }
 
-AliHLTUInt8_t* AliHLTDataBuffer::AliHLTRawBuffer::UseBuffer(AliHLTUInt32_t size)
+int AliHLTDataBuffer::AliHLTRawBuffer::operator<(const AliHLTRawBuffer& op) const
+{
+  // see header file for function documentation
+  return (fPtr+fSize < op.fPtr);
+}
+
+int AliHLTDataBuffer::AliHLTRawBuffer::operator<=(const AliHLTRawBuffer& op) const
 {
   // see header file for function documentation
+  return (fPtr+fSize <= op.fPtr);
+}
+
+int AliHLTDataBuffer::AliHLTRawBuffer::operator>(const AliHLTRawBuffer& op) const
+{
+  // see header file for function documentation
+  return (fPtr > op.fPtr+op.fSize);
+}
+
+AliHLTUInt8_t* AliHLTDataBuffer::AliHLTRawBuffer::UseBuffer(AliHLTUInt32_t size)
+{
+  // mark a portion of the buffer as used
   if (size>0 && fTotalSize>=size) {
     fSize=size;
     fLastEventCount=AliHLTDataBuffer::fgEventCount;
@@ -790,6 +825,22 @@ AliHLTUInt8_t* AliHLTDataBuffer::AliHLTRawBuffer::UseBuffer(AliHLTUInt32_t size)
   return NULL;
 }
 
+AliHLTDataBuffer::AliHLTRawBuffer* AliHLTDataBuffer::AliHLTRawBuffer::Split(AliHLTUInt32_t size)
+{
+  // split a buffer at specified size
+  // only possible for buffers with external memory
+  if (size>0 && fTotalSize>size && 
+      (fSize==0 || fSize<size) &&
+      fExternalPtr!=NULL) {
+    AliHLTRawBuffer* part2=new AliHLTRawBuffer(fTotalSize-size, fPtr+size);
+    if (part2) {
+      fTotalSize=size;
+    }
+    return part2;
+  }
+  return NULL;
+}
+
 int AliHLTDataBuffer::AliHLTRawBuffer::CheckSize(AliHLTUInt32_t size) const
 {
   // see header file for function documentation
@@ -836,3 +887,158 @@ int AliHLTDataBuffer::AliHLTRawBuffer::CheckPattern(const char* pattern, int siz
   }
   return iResult;
 }
+
+int AliHLTDataBuffer::AliHLTRawBuffer::Merge(const AliHLTDataBuffer::AliHLTRawBuffer& neighbor)
+{
+  // Merge buffer with neighboring buffer.
+  // Only possible if the buffers are consecutive with out any gap.
+
+  if (!fExternalPtr || !neighbor.fExternalPtr) return -EPERM;
+
+  if (fPtr+fTotalSize == neighbor.fPtr) {
+    fTotalSize+=neighbor.fTotalSize;
+    fSize=0;
+    return 0;
+  }
+  if (fPtr == neighbor.fPtr+neighbor.fTotalSize) {
+    fPtr=neighbor.fPtr;
+    fExternalPtr=fPtr;
+    fTotalSize+=neighbor.fTotalSize;
+    fSize=0;
+    return 0;
+  }
+  return -EINVAL;
+}
+
+void AliHLTDataBuffer::AliHLTRawBuffer::Print(const char* option)
+{
+  /// print buffer information
+  if (strcmp(option, "min")!=0) {
+    cout << "************* AliHLTRawBuffer status ***********" << endl;
+  }
+  cout << "  " << fPtr << " (" << fExternalPtr << ") size " << fTotalSize << " used " << fSize << endl;
+}
+
+AliHLTDataBuffer::AliHLTRawPage::AliHLTRawPage(AliHLTUInt32_t pagesize)
+  : fSize(pagesize)
+  , fPtr(static_cast<AliHLTUInt8_t*>(malloc(pagesize)))
+  , fFreeBuffers()
+  , fUsedBuffers()
+{
+  // constructor
+  if (fPtr) {
+    fFreeBuffers.push_back(new AliHLTRawBuffer(fSize, fPtr));
+  } else {
+    fSize=0;
+  }
+}
+
+AliHLTDataBuffer::AliHLTRawPage::~AliHLTRawPage()
+{
+  // destructor
+  if (fUsedBuffers.size()>0) {
+    // do not free if the resources have not been completely freed
+    HLTError("memory mismatch: not all allocated intances have been released");
+  } else {
+    if (fFreeBuffers.size()>0) {
+      HLTWarning("page still fragmented");
+    }
+    AliHLTRawBufferPList::iterator element=fFreeBuffers.begin();
+    while (element!=fFreeBuffers.end()) {
+      if (*element) delete *element;
+      element=fFreeBuffers.erase(element);
+    }
+    if (fPtr) {
+      free(fPtr);
+    }
+    fPtr=NULL;
+    fSize=0;
+  }
+}
+
+AliHLTDataBuffer::AliHLTRawBuffer* AliHLTDataBuffer::AliHLTRawPage::Alloc(AliHLTUInt32_t size)
+{
+  /// alloc a buffer of specified size
+  if (fFreeBuffers.size()>0) return NULL;
+  
+  AliHLTRawBuffer* buffer=NULL;
+  for (AliHLTRawBufferPList::iterator iter=fFreeBuffers.begin();
+       iter!=fFreeBuffers.end() && buffer==NULL;
+       iter++) {
+    if ((*iter)->GetTotalSize()>=size) {
+      buffer=(*iter)->Split(size);
+      if (buffer) {
+       fFreeBuffers.insert(iter, buffer);
+       buffer=*iter;
+       fFreeBuffers.erase(iter);
+       fUsedBuffers.push_back(buffer);
+       return buffer;
+      } else {
+       HLTWarning("failed to split raw buffer %p", *iter);
+      }
+    }
+  }
+  return NULL;
+}
+
+int AliHLTDataBuffer::AliHLTRawPage::Free(AliHLTRawBuffer* pBuffer)
+{
+  /// free a buffer and merge consecutive free buffers
+  int iResult=0;
+  for (AliHLTRawBufferPList::iterator iter=fUsedBuffers.begin();
+       iter!=fUsedBuffers.end() && iResult>=0;
+       iter++) {
+    if ((*iter)==pBuffer) {
+      fUsedBuffers.erase(iter);
+      for (AliHLTRawBufferPList::iterator prev=fFreeBuffers.begin();
+          prev!=fFreeBuffers.end() && iResult>=0;
+          prev++) {
+       if ((*pBuffer)<(*(*prev))) {
+         // check consecutive buffers
+         if ((*(*prev)) == (pBuffer->GetPointer()+pBuffer->GetTotalSize())) {
+           // the buffer to be released has a consecutive free buffer -> merge them
+           if ((iResult=pBuffer->Merge(*(*prev)))>=0) {
+             fFreeBuffers.insert(prev, pBuffer);
+             delete *prev;
+             fFreeBuffers.erase(prev);
+           }
+           break;
+         }
+         continue;
+       }
+       if ((*pBuffer)>(*(*prev))) {
+         // check consecutive buffers
+         if ((*(*prev)) == ((*prev)->GetPointer()+(*prev)->GetTotalSize())) {
+           // the buffer to be released is consecutive to a free buffer -> merge them
+           if ((iResult=pBuffer->Merge(*(*prev)))>=0) {
+             fFreeBuffers.insert(prev, pBuffer);
+             delete *prev;
+             fFreeBuffers.erase(prev);
+           }
+         } else {
+           fFreeBuffers.push_back(pBuffer);
+         }
+         break;
+       }       
+      }        
+      return 0;
+    }
+  }
+  return 1;
+}
+
+void AliHLTDataBuffer::AliHLTRawPage::Print(const char* /*option*/)
+{
+  /// print page information
+  cout << "************* AliHLTRawPage status ***********" << endl;
+  cout << "  used buffers:" << endl;
+  AliHLTRawBufferPList::iterator iter=fUsedBuffers.begin();
+  for (; iter!=fUsedBuffers.end(); iter++) {
+    cout << "    "; (*iter)->Print("min");
+  }
+  cout << "  used buffers:" << endl;
+  iter=fFreeBuffers.begin();
+  for (; iter!=fFreeBuffers.end(); iter++) {
+    cout << "    "; (*iter)->Print("min");
+  }
+}
index 55f571f..4c2eff1 100644 (file)
@@ -309,6 +309,50 @@ class AliHLTDataBuffer : public TObject, public AliHLTLogging
     AliHLTUInt32_t fSpecification;                                 // see above
   };
 
+  class AliHLTRawBuffer;
+  typedef vector<AliHLTRawBuffer*>  AliHLTRawBufferPList;
+
+  /**
+   * @class AliHLTRawPage
+   * Memory allocation is organized in pages of a fixed size. Within a
+   * page, AliHLTRawBuffer chunks are created.
+   */
+  class AliHLTRawPage : public AliHLTLogging {
+  public:
+    /** standard constructor */
+  AliHLTRawPage() : fSize(0), fPtr(NULL), fFreeBuffers(), fUsedBuffers() {}
+    /** constructor */
+    AliHLTRawPage(AliHLTUInt32_t pagesize);
+    /** destructor */
+    virtual ~AliHLTRawPage();
+
+    /** alloc a buffer of specified size */
+    AliHLTRawBuffer* Alloc(AliHLTUInt32_t size);
+    /** free a buffer and merge consecutive free buffers */
+    int Free(AliHLTRawBuffer* pBuffer);
+
+    /**
+     * Print page information
+     */
+    void Print(const char* option);
+
+  private:
+    /** copy constructor prohibited */
+    AliHLTRawPage(const AliHLTRawPage&);
+    /** assignment operator prohibited */
+    AliHLTRawPage& operator=(const AliHLTRawPage&);
+
+    /** page size */
+    AliHLTUInt32_t fSize;                                          // see above
+    /** the memory segment */
+    AliHLTUInt8_t* fPtr;                                           //! transient
+
+    /** list of free buffers */
+    AliHLTRawBufferPList fFreeBuffers;                             //! transient
+    /** list of used buffers */
+    AliHLTRawBufferPList fUsedBuffers;                             //! transient
+  };
+
   /**
    * @class AliHLTRawBuffer
    * @brief  Descriptor of the raw data buffer which can host several segments.
@@ -316,9 +360,11 @@ class AliHLTDataBuffer : public TObject, public AliHLTLogging
   class AliHLTRawBuffer {
   public:
     /** standard constructor */
-    AliHLTRawBuffer() : fSize(0), fTotalSize(0), fPtr(NULL), fLastEventCount(0) {}
+  AliHLTRawBuffer() : fSize(0), fTotalSize(0), fExternalPtr(NULL), fPtr(NULL), fLastEventCount(0) {}
     /** constructor */
     AliHLTRawBuffer(AliHLTUInt32_t size);
+    /** constructor */
+    AliHLTRawBuffer(AliHLTUInt32_t size, AliHLTUInt8_t* buffer);
     /** destructor */
     virtual ~AliHLTRawBuffer();
 
@@ -329,6 +375,12 @@ class AliHLTDataBuffer : public TObject, public AliHLTLogging
      */
     AliHLTUInt8_t* UseBuffer(AliHLTUInt32_t size);
 
+    /**
+     * split a buffer at specified size
+     * only possible for buffers with external memory
+     */
+    AliHLTRawBuffer* Split(AliHLTUInt32_t size);
+
     /**
      * Check whether buffer fits for a request.
      * A buffer fits if it is at least of the requested size and at most
@@ -370,11 +422,26 @@ class AliHLTDataBuffer : public TObject, public AliHLTLogging
      */
     int Reset();
 
+    /*
+     * Merge buffer with succeeding buffer.
+     * Only possible if the buffers are consecutive with out any gap.
+     */
+    int Merge(const AliHLTRawBuffer& succ);
+
+    /**
+     * Print buffer information
+     */
+    void Print(const char* option);
+
     int operator==(void*) const;
     int operator==(AliHLTUInt8_t* ptr) const {return fPtr==ptr;}
+    int operator<(void*) const;
     int operator<=(void*) const;
     int operator>(void*) const;
     int operator-(void*) const;
+    int operator<(const AliHLTRawBuffer&) const;
+    int operator<=(const AliHLTRawBuffer&) const;
+    int operator>(const AliHLTRawBuffer&) const;
 
     operator void*() const {return fPtr;}
     operator AliHLTUInt8_t*() const {return fPtr;}
@@ -389,7 +456,9 @@ class AliHLTDataBuffer : public TObject, public AliHLTLogging
     AliHLTUInt32_t fSize;                                          // see above
     /** total size of the buffer, including safety margin */
     AliHLTUInt32_t fTotalSize;                                     // see above
-    /** the buffer */
+    /** optional external buffer */
+    AliHLTUInt8_t* fExternalPtr;                                   //! transient
+    /** the buffer, external or allocated */
     AliHLTUInt8_t* fPtr;                                           //! transient
     /** last event count where the buffer has been used */
     AliHLTUInt32_t fLastEventCount;                                //! transient
index ba53d08..56b9612 100644 (file)
@@ -17,6 +17,8 @@
 #pragma link C++ class AliHLTControlTask+;
 #pragma link C++ class AliHLTLogging+;
 #pragma link C++ class AliHLTDataBuffer+;
+#pragma link C++ class AliHLTDataBuffer::AliHLTRawBuffer+;
+#pragma link C++ class AliHLTDataBuffer::AliHLTRawPage+;
 #pragma link C++ class AliHLTConsumerDescriptor+;
 #pragma link C++ class AliHLTDataSource+;
 #pragma link C++ class AliHLTDataSink+;