speedup of cluster decoding by ~60%: more efficient access to data stream and avoidin...
authorrichterm <richterm@f7af4fe6-9843-0410-8265-dc069ae4e863>
Wed, 5 Dec 2012 19:09:14 +0000 (19:09 +0000)
committerrichterm <richterm@f7af4fe6-9843-0410-8265-dc069ae4e863>
Wed, 5 Dec 2012 19:09:14 +0000 (19:09 +0000)
HLT/BASE/AliHLTDataInflaterHuffman.cxx
HLT/BASE/AliHLTDataInflaterHuffman.h
HLT/BASE/AliHLTHuffman.cxx
HLT/BASE/AliHLTHuffman.h

index f895642..626b62d 100644 (file)
@@ -35,6 +35,8 @@ AliHLTDataInflaterHuffman::AliHLTDataInflaterHuffman()
   , fHuffmanCoderList(NULL)
   , fCurrentParameter(-1)
   , fLegacyMode(-1)
+  , fInput(0)
+  , fInputLength(0)
 {
   // see header file for class documentation
   // or
@@ -97,12 +99,14 @@ int AliHLTDataInflaterHuffman::InitDecoders(TList* decoderlist)
   TIter next(decoderlist);
   TObject* pObj=NULL;
   while ((pObj=next())!=NULL) {
-    if (dynamic_cast<AliHLTHuffman*>(pObj)==NULL) continue;
+    AliHLTHuffman* coder=NULL;
+    if ((coder=dynamic_cast<AliHLTHuffman*>(pObj))==NULL) continue;
     if (fHuffmanCoderList->FindObject(pObj->GetName())) {
       HLTError("duplicate entry of name '%s'", pObj->GetName());
       return -EEXIST;
     }
     fHuffmanCoderList->Add(pObj);
+    coder->InitMaxCodeLength();
   }
 
   return fHuffmanCoderList->GetEntries();
@@ -115,42 +119,56 @@ bool AliHLTDataInflaterHuffman::NextValue(AliHLTUInt64_t& value, AliHLTUInt32_t&
   /// list, than it starts at the first parameter again
   value=0;
   length=0;
-  AliHLTUInt64_t input=0;
-  AliHLTUInt32_t inputLength=64;
-  if (GetRemainingBitDataSizeBytes()<=sizeof(AliHLTUInt64_t)) {
-    inputLength=8*GetRemainingBitDataSizeBytes();
-    inputLength-=(7-GetCurrentBitInputPosition());
-  }
-  if (!InputBits(input, inputLength)) return false;
   if (fLegacyMode!=0) {
   if ((++fCurrentParameter)>=(int)fHuffmanCoders.size()) fCurrentParameter=0;
   fLegacyMode=1;
   }
   if (fHuffmanCoders.size()==0 || fCurrentParameter<0) return false;
-  // the huffman code is decoded from bit 0 corresponding to the top node and then to
-  // the left. The bitstream stores the reversed huffman code from MSB to LSB to ensure
-  // a continous bit stream, that's why then input word needs to be reversed before
-  // decoding.
-  // TODO: introducing DecodeReverse into AliHLTHuffman can speed up the reading
-  std::bitset<64> bits;
-  for (unsigned bit=0; bit<inputLength; bit++) {bits[inputLength-1-bit]=input&0x1;input>>=1;}
+  if (fInputLength<fHuffmanCoders[fCurrentParameter]->GetMaxCodeLength() ||
+      fHuffmanCoders[fCurrentParameter]->GetMaxCodeLength()==0)
+  {
+    AliHLTUInt64_t input=0;
+    AliHLTUInt32_t inputLength=64-fInputLength;
+    if (GetRemainingBitDataSizeBytes()<=sizeof(AliHLTUInt64_t)) {
+      inputLength=8*GetRemainingBitDataSizeBytes();
+      inputLength-=(7-GetCurrentBitInputPosition());
+    }
+    if (64-fInputLength<inputLength) inputLength=64-fInputLength;
+    if (!InputBits(input, inputLength)) return false;
+    input<<=(64-inputLength);
+    input>>=fInputLength;
+    fInput|=input;
+    fInputLength+=inputLength;
+  }
   AliHLTUInt32_t codeLength=0;
-  if (!fHuffmanCoders[fCurrentParameter]->Decode(bits, value, length, codeLength)) return false;
-  if (inputLength<codeLength) {
+  if (!fHuffmanCoders[fCurrentParameter]->DecodeUp(fInput, value, length, codeLength)) return false;
+  if (fInputLength<codeLength) {
     HLTError("huffman decoder '%s' pretends to have %d bit(s) decoded, but only %d available",
-            fHuffmanCoders[fCurrentParameter]->GetName(), codeLength, inputLength);
+            fHuffmanCoders[fCurrentParameter]->GetName(), codeLength, fInputLength);
     return false;
   }
-  inputLength-=codeLength;
-  RewindBitPosition(inputLength);
+  fInput<<=codeLength;
+  fInputLength-=codeLength;
 
   return true;
 }
 
+void AliHLTDataInflaterHuffman::Print(Option_t* option) const
+{
+  /// Print info
+  for (vector<AliHLTHuffman*>::const_iterator coder=fHuffmanCoders.begin();
+       coder!=fHuffmanCoders.end(); coder++) {
+    if (!*coder) continue;
+    (*coder)->Print(option);
+  }
+}
+
 void AliHLTDataInflaterHuffman::Clear(Option_t * option)
 {
   /// clear the object
   fCurrentParameter=-1;
+  fInput=0;
+  fInputLength=0;
 
   if (strcmp(option, "all")==0) {
     fHuffmanCoders.clear();
index 7c38fd8..413b3a9 100644 (file)
@@ -42,6 +42,8 @@ public:
     return fCurrentParameter;
   }
 
+  /// Print info
+  void Print(Option_t* option = "") const;
   /// clear the object and reset pointer references
   virtual void Clear(Option_t * option ="");
 
@@ -62,6 +64,10 @@ private:
   int fCurrentParameter; //!
   /// legacy mode to handle code not using NextParameter()
   int fLegacyMode;
+  /// buffered input
+  AliHLTUInt64_t fInput; //!
+  /// valid MSBs in the buffered input
+  AliHLTUInt32_t fInputLength; //!
 
   ClassDef(AliHLTDataInflaterHuffman, 0)
 };
index 1b689f8..2ffdc60 100644 (file)
@@ -120,7 +120,7 @@ AliHLTHuffmanTreeNode::AliHLTHuffmanTreeNode()
 }
 
 AliHLTHuffmanTreeNode::AliHLTHuffmanTreeNode(const AliHLTHuffmanTreeNode& other)
-       : AliHLTHuffmanNode()
+       : AliHLTHuffmanNode(other)
        , fBinaryCodeLength(other.fBinaryCodeLength)
        , fBinaryCode(other.fBinaryCode)
        , fLeft(other.GetLeftChild())
@@ -176,7 +176,7 @@ AliHLTHuffmanLeaveNode::AliHLTHuffmanLeaveNode()
 }
 
 AliHLTHuffmanLeaveNode::AliHLTHuffmanLeaveNode(const AliHLTHuffmanLeaveNode& other)
-       : AliHLTHuffmanNode()
+       : AliHLTHuffmanNode(other)
        , fBinaryCodeLength(other.fBinaryCodeLength)
        , fBinaryCode(other.fBinaryCode)
        , fLeft(other.GetLeftChild())
@@ -213,6 +213,7 @@ AliHLTHuffman::AliHLTHuffman()
        , fNodes(0)
        , fHuffTopNode(NULL)
        , fReverseCode(true)
+       , fMaxCodeLength(0)
 {
         /// nop
 }
@@ -225,6 +226,7 @@ AliHLTHuffman::AliHLTHuffman(const AliHLTHuffman& other)
        , fNodes(other.fNodes)
        , fHuffTopNode(NULL)
        , fReverseCode(other.fReverseCode)
+       , fMaxCodeLength(other.fMaxCodeLength)
 {
         /// nop
 }
@@ -236,6 +238,7 @@ AliHLTHuffman::AliHLTHuffman(const char* name, UInt_t maxBits)
        , fNodes((((AliHLTUInt64_t) 1) << maxBits))
        , fHuffTopNode(NULL)
        , fReverseCode(true)
+       , fMaxCodeLength(0)
  {
         /// standard constructor
        for (AliHLTUInt64_t i = 0; i <= fMaxValue; i++) {
@@ -267,9 +270,9 @@ const std::bitset<64>& AliHLTHuffman::Encode(const AliHLTUInt64_t v, AliHLTUInt6
        return dummy;
 }
 
-Bool_t AliHLTHuffman::Decode(std::bitset<64> bits, AliHLTUInt64_t& value,
+Bool_t AliHLTHuffman::DecodeDown(std::bitset<64> bits, AliHLTUInt64_t& value,
                             AliHLTUInt32_t& length, AliHLTUInt32_t& codeLength) const {
-       // TODO: check decoding logic, righ now it is just as written
+       // huffman decoding
        AliHLTHuffmanNode* currNode = fHuffTopNode;
        if (!currNode) return kFALSE;
        if (currNode->GetValue() >= 0) {
@@ -307,6 +310,46 @@ Bool_t AliHLTHuffman::Decode(std::bitset<64> bits, AliHLTUInt64_t& value,
        return kFALSE;
 }
 
+Bool_t AliHLTHuffman::DecodeUp(std::bitset<64> bits, AliHLTUInt64_t& value,
+                            AliHLTUInt32_t& length, AliHLTUInt32_t& codeLength) const {
+       // huffman decoding
+       AliHLTHuffmanNode* currNode = fHuffTopNode;
+       if (!currNode) return kFALSE;
+       if (currNode->GetValue() >= 0) {
+               // handle case with just one node - also quite unlikely
+               value = currNode->GetValue();
+               return kTRUE;
+       }
+       while (currNode) {
+               if (bits[63] && currNode->GetLeftChild()) {
+                       // follow left branch
+                       currNode = currNode->GetLeftChild();
+                       bits <<= 1;
+                       if (currNode->GetValue() >= 0) {
+                               value = currNode->GetValue();
+                               length = fMaxBits;
+                               codeLength = currNode->GetBinaryCodeLength();
+                               return kTRUE;
+                       }
+                       continue;
+               }
+               if (!bits[63] && currNode->GetRightChild()) {
+                       currNode = currNode->GetRightChild();
+                       bits <<= 1;
+                       if (currNode->GetValue() >= 0) {
+                               value = currNode->GetValue();
+                               length = fMaxBits;
+                               codeLength = currNode->GetBinaryCodeLength();
+                               return kTRUE;
+                       }
+                       continue;
+               }
+               break;
+       }
+       value = ((AliHLTUInt64_t)1) << 63;
+       return kFALSE;
+}
+
 Bool_t AliHLTHuffman::AddTrainingValue(const AliHLTUInt64_t value,
                const Float_t weight) {
        if (value > fMaxValue) {
@@ -337,12 +380,13 @@ Bool_t AliHLTHuffman::GenerateHuffmanTree() {
        //assign value
        fHuffTopNode = *nodeCollection.begin();
        fHuffTopNode->AssignCode(fReverseCode);
+       InitMaxCodeLength();
        return kTRUE;
 }
 
 void AliHLTHuffman::Print(Option_t* option) const {
         std::cout << GetName() << endl;
-        bool bPrintShort=strcmp(option, "short")==0;
+        bool bPrintShort=strcmp(option, "full")!=0;
        if (fHuffTopNode && !bPrintShort) {
                std::cout << "Huffman tree:" << endl;
                fHuffTopNode->Print();
@@ -374,6 +418,7 @@ AliHLTHuffman& AliHLTHuffman::operator =(const AliHLTHuffman& other) {
        fMaxValue = other.fMaxValue;
        fNodes = other.fNodes;
        fHuffTopNode = NULL;
+       fMaxCodeLength = 0;
        return *this;
 }
 
@@ -390,17 +435,17 @@ bool AliHLTHuffman::CheckConsistency() const
     AliHLTUInt32_t readbacklen=0;
     AliHLTUInt32_t readbackcodelen=0;
     if (fReverseCode) {
-      // reverse if needed
-      // Note: for optimized bit stream the huffman code is reversed, and
-      // that needs to be taken into account
-      std::bitset<64> rcode;
-      for (AliHLTUInt64_t i=0; i<codeLength; i++) {rcode<<=1; rcode[0]=code[i];}
-      code=rcode;
-    }
-    if (!Decode(code, readback, readbacklen, readbackcodelen)) {
+      code<<=64-codeLength;
+      if (!DecodeUp(code, readback, readbacklen, readbackcodelen)) {
+       cout << "Decode failed" << endl;
+       return false;
+      }
+    } else {
+    if (!DecodeDown(code, readback, readbacklen, readbackcodelen)) {
       cout << "Decode failed" << endl;
       return false;
     }
+    }
     if (v!=readback) {
       cout << "readback of value " << v << " code length " << codeLength << " failed: got " << readback << " code length " << readbackcodelen << endl;
       return false;
@@ -409,5 +454,17 @@ bool AliHLTHuffman::CheckConsistency() const
   return true;
 }
 
+UInt_t AliHLTHuffman::InitMaxCodeLength()
+{
+  // loop over leave nodes and set maximum code length
+  fMaxCodeLength=0;
+  for (std::vector<AliHLTHuffmanLeaveNode>::const_iterator node=fNodes.begin();
+       node!=fNodes.end(); node++) {
+    if (fMaxCodeLength<node->GetBinaryCodeLength())
+      fMaxCodeLength=node->GetBinaryCodeLength();
+  }
+  return fMaxCodeLength;
+}
+
 ClassImp(AliHLTHuffman)
 
index 8961042..8cba6b5 100644 (file)
@@ -229,14 +229,20 @@ public:
        AliHLTHuffman(const char* name, UInt_t maxBits);
        ~AliHLTHuffman();
 
+       UInt_t InitMaxCodeLength();
+
        UInt_t GetMaxBits() const {return fMaxBits;}
        UInt_t GetMaxValue() const {return fMaxValue;}
+       UInt_t GetMaxCodeLength() const {return fMaxCodeLength;}
 
        /// Return huffman code for a value
        const std::bitset<64>& Encode(const AliHLTUInt64_t v, AliHLTUInt64_t& codeLength) const;
 
-       /// Return value for bit pattern
-        Bool_t Decode(std::bitset<64> /*bits*/, AliHLTUInt64_t& /*value*/, AliHLTUInt32_t& length, AliHLTUInt32_t& codeLength) const;
+       /// Return value for bit pattern, LSB first
+        Bool_t DecodeDown(std::bitset<64> /*bits*/, AliHLTUInt64_t& /*value*/, AliHLTUInt32_t& length, AliHLTUInt32_t& codeLength) const;
+       /// Return value for bit pattern, MSB first
+        Bool_t DecodeUp(std::bitset<64> /*bits*/, AliHLTUInt64_t& /*value*/, AliHLTUInt32_t& length, AliHLTUInt32_t& codeLength) const;
+
        /// Add a new training value (with optional weight) to the training sample
        Bool_t AddTrainingValue(const AliHLTUInt64_t value,
                        const Float_t weight = 1.);
@@ -255,8 +261,9 @@ private:
        std::vector<AliHLTHuffmanLeaveNode> fNodes; // array of nodes
        AliHLTHuffmanNode* fHuffTopNode;       // top node
        bool fReverseCode; // indicate the type of the binary code
+       UInt_t fMaxCodeLength; //! maximum code length
 
-ClassDef(AliHLTHuffman, 2)
+ClassDef(AliHLTHuffman, 3)
 };
 
 #endif