Browse Source

Rewritten SpeedCalc

Tatsuhiro Tsujikawa 12 years ago
parent
commit
1ad815061b
2 changed files with 53 additions and 59 deletions
  1. 46 48
      src/SpeedCalc.cc
  2. 7 11
      src/SpeedCalc.h

+ 46 - 48
src/SpeedCalc.cc

@@ -41,71 +41,69 @@
 
 namespace aria2 {
 
-#define CHANGE_INTERVAL_SEC 15
+#define WINDOW_MSEC 15000
 
-SpeedCalc::SpeedCalc():sw_(0), maxSpeed_(0), prevSpeed_(0),
-                       accumulatedLength_(0),
-                       nextInterval_(CHANGE_INTERVAL_SEC)
-{
-  std::fill(&lengthArray_[0], &lengthArray_[2], 0);
-}
+SpeedCalc::SpeedCalc()
+  : accumulatedLength_(0),
+    bytesWindow_(0),
+    maxSpeed_(0)
+{}
 
-void SpeedCalc::reset() {
-  std::fill(&lengthArray_[0], &lengthArray_[2], 0);
-  std::fill(&cpArray_[0], &cpArray_[2], global::wallclock());
-  sw_ = 0;
-  maxSpeed_ = 0;
-  prevSpeed_ = 0;
+void SpeedCalc::reset()
+{
+  timeSlots_.clear();
   start_ = global::wallclock();
   accumulatedLength_ = 0;
-  nextInterval_ = CHANGE_INTERVAL_SEC;
+  bytesWindow_ = 0;
+  maxSpeed_ = 0;
 }
 
-int SpeedCalc::calculateSpeed() {
-  int64_t milliElapsed = cpArray_[sw_].differenceInMillis(global::wallclock());
-  if(milliElapsed) {
-    int speed = lengthArray_[sw_]*1000/milliElapsed;
-    prevSpeed_ = speed;
-    maxSpeed_ = std::max(speed, maxSpeed_);
-    if(isIntervalOver(milliElapsed)) {
-      changeSw();
+void SpeedCalc::removeStaleTimeSlot(int64_t now)
+{
+  while(!timeSlots_.empty()) {
+    if(now - timeSlots_[0].first <= WINDOW_MSEC) {
+      break;
+    } else {
+      bytesWindow_ -= timeSlots_[0].second;
+      timeSlots_.pop_front();
     }
-    return speed;
-  } else {
-    return prevSpeed_;
   }
 }
 
-void SpeedCalc::update(size_t bytes) {
-  accumulatedLength_ += bytes;
-  std::transform(&lengthArray_[0], &lengthArray_[2], &lengthArray_[0],
-                 std::bind1st(std::plus<int64_t>(), (int64_t)bytes));
-  if(isIntervalOver()) {
-    changeSw();
+int SpeedCalc::calculateSpeed()
+{
+  int64_t now = global::wallclock().getTimeInMillis();
+  removeStaleTimeSlot(now);
+  if(timeSlots_.empty()) {
+    return 0;
   }
+  int64_t elapsed = now - timeSlots_[0].first;
+  if(elapsed <= 0) {
+    elapsed = 1;
+  }
+  int speed = bytesWindow_*1000/elapsed;
+  maxSpeed_ = std::max(speed, maxSpeed_);
+  return speed;
 }
 
-bool SpeedCalc::isIntervalOver() const {
-  return nextInterval_ <= cpArray_[sw_].difference(global::wallclock());
-}
-
-bool SpeedCalc::isIntervalOver(int64_t milliElapsed) const
+void SpeedCalc::update(size_t bytes)
 {
-  return nextInterval_ <= milliElapsed/1000;
-}
-
-void SpeedCalc::changeSw() {
-  lengthArray_[sw_] = 0;
-  cpArray_[sw_] = global::wallclock();
-  sw_ ^= 0x01u;
-  nextInterval_ =
-    cpArray_[sw_].difference(global::wallclock())+CHANGE_INTERVAL_SEC;
+  int64_t now = global::wallclock().getTimeInMillis();
+  removeStaleTimeSlot(now);
+  if(timeSlots_.empty() || now/1000 != timeSlots_.back().first/1000) {
+    timeSlots_.push_back(std::make_pair(now, bytes));
+  } else {
+    timeSlots_.back().second += bytes;
+  }
+  bytesWindow_ += bytes;
+  accumulatedLength_ += bytes;
 }
 
-int SpeedCalc::calculateAvgSpeed() const {
+int SpeedCalc::calculateAvgSpeed() const
+{
   int64_t milliElapsed = start_.differenceInMillis(global::wallclock());
-
-  // if milliElapsed is too small, the average speed is rubish, better return 0
+  // if milliElapsed is too small, the average speed is rubish, better
+  // return 0
   if(milliElapsed > 4) {
     int speed = accumulatedLength_*1000/milliElapsed;
     return speed;

+ 7 - 11
src/SpeedCalc.h

@@ -36,29 +36,25 @@
 #define D_SPEED_CALC_H
 
 #include "common.h"
+
+#include <deque>
+
 #include "TimerA2.h"
 
 namespace aria2 {
 
 class SpeedCalc {
 private:
-  int64_t lengthArray_[2];
-  int sw_;
-  Timer cpArray_[2];
-  int maxSpeed_;
-  int prevSpeed_;
+  std::deque<std::pair<int64_t, size_t> > timeSlots_;
   Timer start_;
   int64_t accumulatedLength_;
-  time_t nextInterval_;
-
-  bool isIntervalOver(int64_t milliElapsed) const;
+  int64_t bytesWindow_;
+  int maxSpeed_;
 
-  void changeSw();
+  void removeStaleTimeSlot(int64_t now);
 public:
   SpeedCalc();
 
-  bool isIntervalOver() const;
-
   /**
    * Returns download/upload speed in byte per sec
    */