Index: content/browser/download/rate_estimator.cc |
diff --git a/content/browser/download/rate_estimator.cc b/content/browser/download/rate_estimator.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..e86287c463483168d0dce20e3c7517a9f3515912 |
--- /dev/null |
+++ b/content/browser/download/rate_estimator.cc |
@@ -0,0 +1,122 @@ |
+// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "content/browser/download/rate_estimator.h" |
+ |
+#include "base/logging.h" |
+ |
+using base::TimeDelta; |
+using base::TimeTicks; |
+ |
+namespace content { |
+ |
+namespace { |
+ |
+static const int kDefaultBucketTimeSeconds = 1; |
tfarina
2013/05/29 16:35:21
static not needed here. const has internal linkage
|
+static const size_t kDefaultNumBuckets = 10; |
+ |
+} // namespace |
+ |
+RateEstimator::RateEstimator() |
+ : history_(kDefaultNumBuckets), |
+ bucket_time_(TimeDelta::FromSeconds(kDefaultBucketTimeSeconds)), |
+ oldest_index_(0), |
+ bucket_count_(1) { |
+ ResetBuckets(TimeTicks::Now()); |
+} |
+ |
+RateEstimator::RateEstimator(TimeDelta bucket_time, |
+ size_t num_buckets, |
+ TimeTicks now) |
+ : history_(num_buckets), |
+ bucket_time_(bucket_time), |
+ oldest_index_(0), |
+ bucket_count_(1) { |
+ DCHECK(bucket_time_.InSeconds() > 0); |
tfarina
2013/05/29 16:35:21
DCHECK_GT?
|
+ ResetBuckets(now); |
+} |
+ |
+RateEstimator::~RateEstimator() { |
+} |
tfarina
2013/05/29 16:35:21
clang-format would put } in the above line.
|
+ |
+void RateEstimator::Increment(uint32 count) { |
+ Increment(count, TimeTicks::Now()); |
+} |
+ |
+void RateEstimator::Increment(uint32 count, TimeTicks now) { |
+ ClearOldBuckets(now); |
+ int64 seconds_since_oldest = (now - oldest_time_).InSeconds(); |
+ DCHECK(seconds_since_oldest >= 0); |
tfarina
2013/05/29 16:35:21
DCHECK_GE
|
+ int64 delta_buckets = seconds_since_oldest / bucket_time_.InSeconds(); |
+ DCHECK(delta_buckets >= 0); |
+ size_t index_offset = static_cast<size_t>(delta_buckets); |
+ DCHECK(index_offset <= history_.size()); |
+ int current_index = (oldest_index_ + delta_buckets) % history_.size(); |
+ history_[current_index] += count; |
+} |
+ |
+uint64 RateEstimator::GetCountPerSecond() const { |
+ return GetCountPerSecond(TimeTicks::Now()); |
+} |
+ |
+uint64 RateEstimator::GetCountPerSecond(TimeTicks now) const { |
+ const_cast<RateEstimator*>(this)->ClearOldBuckets(now); |
+ // TODO(cbentzel): Support fractional seconds for active bucket? |
+ // We explicitly don't check for overflow here. If it happens, unsigned |
+ // arithmetic at least guarantees behavior by wrapping around. The estimate |
+ // will be off, but the code will still be valid. |
+ uint64 total_count = 0; |
+ for (size_t i = 0; i < bucket_count_; ++i) { |
+ size_t index = (oldest_index_ + i) % history_.size(); |
+ total_count += history_[index]; |
+ } |
+ return total_count / (bucket_count_ * bucket_time_.InSeconds()); |
+} |
+ |
+void RateEstimator::ClearOldBuckets(TimeTicks now) { |
+ int64 seconds_since_oldest = (now - oldest_time_).InSeconds(); |
+ |
+ int64 delta_buckets = seconds_since_oldest / bucket_time_.InSeconds(); |
+ |
+ // It's possible (although unlikely) for there to be rollover with TimeTicks. |
+ // If that's the case, just reset the history. |
+ if (delta_buckets < 0) { |
+ ResetBuckets(now); |
+ return; |
+ } |
+ size_t delta_index = static_cast<size_t>(delta_buckets); |
+ |
+ // If we are within the current window, keep the existing data. |
+ if (delta_index < history_.size()) { |
+ bucket_count_ = delta_index + 1; |
+ return; |
+ } |
+ |
+ // If it's been long enough that all history data is too stale, just |
+ // clear all the buckets. |
+ size_t extra_buckets = delta_index - history_.size() + 1; |
+ if (extra_buckets > history_.size()) { |
+ ResetBuckets(now); |
+ return; |
+ } |
+ |
+ // Clear out stale buckets in the history. |
+ bucket_count_ = history_.size(); |
+ for (size_t i = 0; i < extra_buckets; ++i) { |
+ history_[oldest_index_] = 0; |
+ oldest_index_ = (oldest_index_ + 1) % history_.size(); |
+ oldest_time_ = oldest_time_ + bucket_time_; |
+ } |
+} |
+ |
+void RateEstimator::ResetBuckets(TimeTicks now) { |
+ for (size_t i = 0; i < history_.size(); ++i) { |
tfarina
2013/05/29 16:35:21
no curlies for single-line statements.
|
+ history_[i] = 0; |
+ } |
+ oldest_index_ = 0; |
+ bucket_count_ = 1; |
+ oldest_time_ = now; |
+} |
+ |
+} // namespace content |