Преглед на файлове

Simplified PieceStatMan and RarestPieceSelector.

Simplified PieceStatMan and RarestPieceSelector, but computation order
 to select piece index is still O(N) and unchanged.  Updating piece
 stat is improved to O(N) for bitfield update and O(1) for single
 index update, while old implementation needs O(NlogN) and O(N)
 respectively.
Tatsuhiro Tsujikawa преди 14 години
родител
ревизия
6ee913b0bc
променени са 4 файла, в които са добавени 72 реда и са изтрити 251 реда
  1. 28 85
      src/PieceStatMan.cc
  2. 6 51
      src/PieceStatMan.h
  3. 15 27
      src/RarestPieceSelector.cc
  4. 23 88
      test/PieceStatManTest.cc

+ 28 - 85
src/PieceStatMan.cc

@@ -34,6 +34,7 @@
 /* copyright --> */
 #include "PieceStatMan.h"
 
+#include <limits>
 #include <algorithm>
 
 #include "SimpleRandomizer.h"
@@ -41,138 +42,80 @@
 
 namespace aria2 {
 
-PieceStat::PieceStat(size_t index):order_(0), index_(index), count_(0) {}
-
-void PieceStat::addCount()
-{
-  if(count_ < SIZE_MAX) {
-    ++count_;
-  }
-}
-
-void PieceStat::subCount()
-{
-  if(count_ > 0) {
-    --count_;
-  }
-}
-
-namespace {
-class GenPieceStat {
-private:
-  size_t index_;
-public:
-  GenPieceStat():index_(0) {}
-
-  SharedHandle<PieceStat> operator()()
-  {
-    return SharedHandle<PieceStat>(new PieceStat(index_++));
-  }
-};
-} // namespace
-
 PieceStatMan::PieceStatMan(size_t pieceNum, bool randomShuffle):
-  pieceStats_(pieceNum),
-  sortedPieceStatIndexes_(pieceNum)
+  order_(pieceNum),
+  counts_(pieceNum)
 {
-  std::generate(pieceStats_.begin(), pieceStats_.end(), GenPieceStat());
-  std::vector<SharedHandle<PieceStat> > sortedPieceStats(pieceStats_);
+  for(size_t i = 0; i < pieceNum; ++i) {
+    order_[i] = i;
+  }
   // we need some randomness in ordering.
   if(randomShuffle) {
-    std::random_shuffle(sortedPieceStats.begin(), sortedPieceStats.end(),
+    std::random_shuffle(order_.begin(), order_.end(),
                         *(SimpleRandomizer::getInstance().get()));
   }
-  {
-    size_t order = 0;
-    for(std::vector<SharedHandle<PieceStat> >::const_iterator i =
-          sortedPieceStats.begin(), eoi = sortedPieceStats.end();
-        i != eoi; ++i) {
-      sortedPieceStatIndexes_[order] = (*i)->getIndex();
-      (*i)->setOrder(order++);
-    }
-  }  
 }
 
 PieceStatMan::~PieceStatMan() {}
 
 namespace {
-class PieceStatRarer {
-private:
-  const std::vector<SharedHandle<PieceStat> >& pieceStats_;
-public:
-  PieceStatRarer(const std::vector<SharedHandle<PieceStat> >& ps):
-    pieceStats_(ps) {}
+void inc(int& x)
+{
+  if(x < std::numeric_limits<int>::max()) {
+    ++x;
+  }
+}
+} // namespace
 
-  bool operator()(size_t lhs, size_t rhs) const
-  {
-    return *pieceStats_[lhs] < *pieceStats_[rhs];
+namespace {
+void sub(int& x)
+{
+  if(x > 0) {
+    --x;
   }
-};
+}
 } // namespace
 
 void PieceStatMan::addPieceStats(const unsigned char* bitfield,
                                  size_t bitfieldLength)
 {
-  const size_t nbits = pieceStats_.size();
-  assert(nbits <= bitfieldLength*8);
-  for(size_t i = 0; i < nbits; ++i) {
+  for(size_t i = 0, nbits = counts_.size(); i < nbits; ++i) {
     if(bitfield::test(bitfield, nbits, i)) {
-      pieceStats_[i]->addCount();
+      inc(counts_[i]);
     }
   }
-  std::sort(sortedPieceStatIndexes_.begin(), sortedPieceStatIndexes_.end(),
-            PieceStatRarer(pieceStats_));
 }
 
 void PieceStatMan::subtractPieceStats(const unsigned char* bitfield,
                                       size_t bitfieldLength)
 {
-  const size_t nbits = pieceStats_.size();
-  assert(nbits <= bitfieldLength*8);
-  for(size_t i = 0; i < nbits; ++i) {
+  for(size_t i = 0, nbits = counts_.size(); i < nbits; ++i) {
     if(bitfield::test(bitfield, nbits, i)) {
-      pieceStats_[i]->subCount();
+      sub(counts_[i]);
     }
   }
-  std::sort(sortedPieceStatIndexes_.begin(), sortedPieceStatIndexes_.end(),
-            PieceStatRarer(pieceStats_));
 }
 
 void PieceStatMan::updatePieceStats(const unsigned char* newBitfield,
                                     size_t newBitfieldLength,
                                     const unsigned char* oldBitfield)
 {
-  const size_t nbits = pieceStats_.size();
-  assert(nbits <= newBitfieldLength*8);
-  for(size_t i = 0; i < nbits; ++i) {
+  for(size_t i = 0, nbits = counts_.size(); i < nbits; ++i) {
     bool inNew = bitfield::test(newBitfield, nbits, i);
     bool inOld = bitfield::test(oldBitfield, nbits, i);
     if(inNew) {
       if(!inOld) {
-        pieceStats_[i]->addCount();
+        inc(counts_[i]);
       }
     } else if(inOld) {
-      pieceStats_[i]->subCount();
+      sub(counts_[i]);
     }
   }
-  std::sort(sortedPieceStatIndexes_.begin(), sortedPieceStatIndexes_.end(),
-            PieceStatRarer(pieceStats_));
 }
 
 void PieceStatMan::addPieceStats(size_t index)
 {
-  std::vector<size_t>::iterator cur =
-    std::lower_bound(sortedPieceStatIndexes_.begin(),
-                     sortedPieceStatIndexes_.end(),
-                     index, PieceStatRarer(pieceStats_));
-
-  pieceStats_[index]->addCount();
-
-  std::vector<size_t>::iterator to =
-    std::upper_bound(cur+1, sortedPieceStatIndexes_.end(),
-                     index, PieceStatRarer(pieceStats_));
-  
-  std::rotate(cur, cur+1, to);
+  inc(counts_[index]);
 }
 
 } // namespace aria2

+ 6 - 51
src/PieceStatMan.h

@@ -43,53 +43,10 @@
 
 namespace aria2 {
 
-class PieceStat {
-private:
-  size_t order_;
-  size_t index_;
-  size_t count_;
-public:
-  PieceStat(size_t index);
-
-  bool operator<(const PieceStat& pieceStat) const
-  {
-    if(count_ == pieceStat.count_) {
-      return order_ < pieceStat.order_;
-    } else {
-      return count_ < pieceStat.count_;
-    }
-  }
-
-  void addCount();
-  void subCount();
-
-  size_t getOrder() const
-  {
-    return order_;
-  }
-
-  void setOrder(size_t order)
-  {
-    order_ = order;
-  }
-
-  size_t getIndex() const
-  {
-    return index_;
-  }
-
-  size_t getCount() const
-  {
-    return count_;
-  }
-
-};
-
 class PieceStatMan {
 private:
-  std::vector<SharedHandle<PieceStat> > pieceStats_;
-
-  std::vector<size_t> sortedPieceStatIndexes_;
+  std::vector<size_t> order_;
+  std::vector<int> counts_;
 public:
   PieceStatMan(size_t pieceNum, bool randomShuffle);
 
@@ -107,17 +64,15 @@ public:
                         size_t newBitfieldLength,
                         const unsigned char* oldBitfield);
 
-  // Returns piece index in rarest first order.
-  const std::vector<size_t>& getRarerPieceIndexes() const
+  const std::vector<size_t>& getOrder() const
   {
-    return sortedPieceStatIndexes_;
+    return order_;
   }
 
-  const std::vector<SharedHandle<PieceStat> >& getPieceStats() const
+  const std::vector<int>& getCounts() const
   {
-    return pieceStats_;
+    return counts_;
   }
-
 };
 
 } // namespace aria2

+ 15 - 27
src/RarestPieceSelector.cc

@@ -34,47 +34,35 @@
 /* copyright --> */
 #include "RarestPieceSelector.h"
 
-#include <cassert>
+#include <limits>
 #include <algorithm>
 
 #include "PieceStatMan.h"
+#include "bitfield.h"
 
 namespace aria2 {
 
 RarestPieceSelector::RarestPieceSelector
 (const SharedHandle<PieceStatMan>& pieceStatMan):pieceStatMan_(pieceStatMan) {}
 
-namespace {
-class FindRarestPiece
-{
-private:
-  const unsigned char* misbitfield_;
-  size_t numbits_;
-public:
-  FindRarestPiece(const unsigned char* misbitfield, size_t numbits):
-    misbitfield_(misbitfield), numbits_(numbits) {}
-
-  bool operator()(const size_t& index)
-  {
-    assert(index < numbits_);
-    unsigned char mask = (128 >> (index%8));
-    return misbitfield_[index/8]&mask;
-  }
-};
-} // namespace
-
 bool RarestPieceSelector::select
 (size_t& index, const unsigned char* bitfield, size_t nbits) const
 {
-  const std::vector<size_t>& pieceIndexes =
-    pieceStatMan_->getRarerPieceIndexes();
-  std::vector<size_t>::const_iterator i =
-    std::find_if(pieceIndexes.begin(), pieceIndexes.end(),
-                 FindRarestPiece(bitfield, nbits));
-  if(i == pieceIndexes.end()) {
+  const std::vector<size_t>& order = pieceStatMan_->getOrder();
+  const std::vector<int>& counts = pieceStatMan_->getCounts();
+  int min = std::numeric_limits<int>::max();
+  size_t bestIdx = nbits;
+  for(size_t i = 0; i < nbits; ++i) {
+    size_t idx = order[i];
+    if(bitfield::test(bitfield, nbits, idx) && counts[idx] < min) {
+      min = counts[idx];
+      bestIdx = idx;
+    }
+  }
+  if(bestIdx == nbits) {
     return false;
   } else {
-    index = *i;
+    index = bestIdx;
     return true;
   }
 }

+ 23 - 88
test/PieceStatManTest.cc

@@ -31,56 +31,33 @@ void PieceStatManTest::testAddPieceStats_index()
   PieceStatMan pieceStatMan(10, false);
   pieceStatMan.addPieceStats(1);
   {
-    size_t indexes[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 1 };
-    size_t counts[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
-    
-    const std::vector<size_t>& statsidx(pieceStatMan.getRarerPieceIndexes());
-    const std::vector<SharedHandle<PieceStat> >& stats
-      (pieceStatMan.getPieceStats());
-
-    CPPUNIT_ASSERT_EQUAL((size_t)10, stats.size());
-    
+    int ans[] = { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 };
+    const std::vector<size_t>& order(pieceStatMan.getOrder());
+    const std::vector<int>& counts(pieceStatMan.getCounts());
     for(size_t i = 0; i < 10; ++i) {
-      CPPUNIT_ASSERT_EQUAL(indexes[i], statsidx[i]);
-      CPPUNIT_ASSERT_EQUAL(counts[i], stats[statsidx[i]]->getCount());
+      CPPUNIT_ASSERT_EQUAL(i, order[i]);
+      CPPUNIT_ASSERT_EQUAL(ans[i], counts[i]);
     }
   }
-
   pieceStatMan.addPieceStats(1);
-
   {
-    size_t indexes[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 1 };
-    size_t counts[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 };
-
-    const std::vector<size_t>& statsidx(pieceStatMan.getRarerPieceIndexes());
-    const std::vector<SharedHandle<PieceStat> >& stats
-      (pieceStatMan.getPieceStats());
-
+    int ans[] = { 0, 2, 0, 0, 0, 0, 0, 0, 0, 0 };
+    const std::vector<int>& counts(pieceStatMan.getCounts());
     for(size_t i = 0; i < 10; ++i) {
-      CPPUNIT_ASSERT_EQUAL(indexes[i], statsidx[i]);
-      CPPUNIT_ASSERT_EQUAL(counts[i], stats[statsidx[i]]->getCount());
+      CPPUNIT_ASSERT_EQUAL(ans[i], counts[i]);
     }
   }
-
   pieceStatMan.addPieceStats(3);
   pieceStatMan.addPieceStats(9);
   pieceStatMan.addPieceStats(3);
   pieceStatMan.addPieceStats(0);
-
   {
-    size_t indexes[] = { 2, 4, 5, 6, 7, 8, 0, 9, 1, 3 };
-    size_t counts[] = {  0, 0, 0, 0, 0, 0, 1, 1, 2, 2 };
-
-    const std::vector<size_t>& statsidx(pieceStatMan.getRarerPieceIndexes());
-    const std::vector<SharedHandle<PieceStat> >& stats
-      (pieceStatMan.getPieceStats());
-
+    int ans[] = {  1, 2, 0, 2, 0, 0, 0, 0, 0, 1 };
+    const std::vector<int>& counts(pieceStatMan.getCounts());
     for(size_t i = 0; i < 10; ++i) {
-      CPPUNIT_ASSERT_EQUAL(indexes[i], statsidx[i]);
-      CPPUNIT_ASSERT_EQUAL(counts[i], stats[statsidx[i]]->getCount());
+      CPPUNIT_ASSERT_EQUAL(ans[i], counts[i]);
     }
   }
-
 }
 
 void PieceStatManTest::testAddPieceStats_bitfield()
@@ -89,36 +66,18 @@ void PieceStatManTest::testAddPieceStats_bitfield()
   const unsigned char bitfield[] = { 0xaa, 0x80 };
   pieceStatMan.addPieceStats(bitfield, sizeof(bitfield));
   {
-    size_t indexes[] = { 1, 3, 5, 7, 9, 0, 2, 4, 6, 8 };
-    size_t counts[] = { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1 };
-
-    const std::vector<size_t>& statsidx(pieceStatMan.getRarerPieceIndexes());
-    const std::vector<SharedHandle<PieceStat> >& stats
-      (pieceStatMan.getPieceStats());
-
-    CPPUNIT_ASSERT_EQUAL((size_t)10, stats.size());
-    
+    int ans[] = { 1, 0, 1, 0, 1, 0, 1, 0, 1, 0 };
+    const std::vector<int>& counts(pieceStatMan.getCounts());
     for(size_t i = 0; i < 10; ++i) {
-      CPPUNIT_ASSERT_EQUAL(indexes[i], statsidx[i]);
-      CPPUNIT_ASSERT_EQUAL(counts[i], stats[statsidx[i]]->getCount());
+      CPPUNIT_ASSERT_EQUAL(ans[i], counts[i]);
     }
   }
-
   pieceStatMan.addPieceStats(bitfield, sizeof(bitfield));
-
   {
-    size_t indexes[] = { 1, 3, 5, 7, 9, 0, 2, 4, 6, 8 };
-    size_t counts[] = { 0, 0, 0, 0, 0, 2, 2, 2, 2, 2 };
-
-    const std::vector<size_t>& statsidx(pieceStatMan.getRarerPieceIndexes());
-    const std::vector<SharedHandle<PieceStat> >& stats
-      (pieceStatMan.getPieceStats());
-
-    CPPUNIT_ASSERT_EQUAL((size_t)10, stats.size());
-    
+    int ans[] = { 2, 0, 2, 0, 2, 0, 2, 0, 2, 0 };
+    const std::vector<int>& counts(pieceStatMan.getCounts());
     for(size_t i = 0; i < 10; ++i) {
-      CPPUNIT_ASSERT_EQUAL(indexes[i], statsidx[i]);
-      CPPUNIT_ASSERT_EQUAL(counts[i], stats[statsidx[i]]->getCount());
+      CPPUNIT_ASSERT_EQUAL(ans[i], counts[i]);
     }
   }
 }
@@ -126,13 +85,10 @@ void PieceStatManTest::testAddPieceStats_bitfield()
 void PieceStatManTest::testUpdatePieceStats()
 {
   PieceStatMan pieceStatMan(10, false);
-
   const unsigned char bitfield[] = { 0xff, 0xc0 };
   pieceStatMan.addPieceStats(bitfield, sizeof(bitfield));
-
   const unsigned char oldBitfield[] = { 0xf0, 0x00 };
   const unsigned char newBitfield[] = { 0x1f, 0x00 };
-
   pieceStatMan.updatePieceStats(newBitfield, sizeof(newBitfield), oldBitfield);
   {
     // idx: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
@@ -141,19 +97,10 @@ void PieceStatManTest::testUpdatePieceStats()
     // new: 0, 0, 0, 1, 1, 1, 1, 1, 0, 0
     // ---------------------------------
     // res: 0, 0, 0, 1, 2, 2, 2, 2, 1, 1
-
-    size_t indexes[] = { 0, 1, 2, 3, 8, 9, 4, 5, 6, 7 };
-    size_t counts[] =  { 0, 0, 0, 1, 1, 1, 2, 2, 2, 2 };
-
-    const std::vector<size_t>& statsidx(pieceStatMan.getRarerPieceIndexes());
-    const std::vector<SharedHandle<PieceStat> >& stats
-      (pieceStatMan.getPieceStats());
-
-    CPPUNIT_ASSERT_EQUAL((size_t)10, stats.size());
-    
+    int ans[] =  { 0, 0, 0, 1, 2, 2, 2, 2, 1, 1 };
+    const std::vector<int>& counts(pieceStatMan.getCounts());
     for(size_t i = 0; i < 10; ++i) {
-      CPPUNIT_ASSERT_EQUAL(indexes[i], statsidx[i]);
-      CPPUNIT_ASSERT_EQUAL(counts[i], stats[statsidx[i]]->getCount());
+      CPPUNIT_ASSERT_EQUAL(ans[i], counts[i]);
     }
   }
 }
@@ -161,12 +108,9 @@ void PieceStatManTest::testUpdatePieceStats()
 void PieceStatManTest::testSubtractPieceStats()
 {
   PieceStatMan pieceStatMan(10, false);
-
   const unsigned char bitfield[] = { 0xf0, 0x00 };
   pieceStatMan.addPieceStats(bitfield, sizeof(bitfield));
-
   const unsigned char newBitfield[] = { 0x3f, 0x00 };
-
   pieceStatMan.subtractPieceStats(newBitfield, sizeof(newBitfield));
   {
     // idx: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
@@ -174,19 +118,10 @@ void PieceStatManTest::testSubtractPieceStats()
     // new: 0, 0, 1, 1, 1, 1, 1, 1, 0, 0
     // ---------------------------------
     // res: 1, 1, 0, 0, 0, 0, 0, 0, 0, 0
-
-    size_t indexes[] = { 2, 3, 4, 5, 6, 7, 8, 9, 0, 1 };
-    size_t counts[] =  { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 };
-
-    const std::vector<size_t>& statsidx(pieceStatMan.getRarerPieceIndexes());
-    const std::vector<SharedHandle<PieceStat> >& stats
-      (pieceStatMan.getPieceStats());
-
-    CPPUNIT_ASSERT_EQUAL((size_t)10, stats.size());
-    
+    int ans[] =  { 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 };
+    const std::vector<int>& counts(pieceStatMan.getCounts());
     for(size_t i = 0; i < 10; ++i) {
-      CPPUNIT_ASSERT_EQUAL(indexes[i], statsidx[i]);
-      CPPUNIT_ASSERT_EQUAL(counts[i], stats[statsidx[i]]->getCount());
+      CPPUNIT_ASSERT_EQUAL(ans[i], counts[i]);
     }
   }
 }