| Index: net/base/network_quality_estimator.cc
|
| diff --git a/net/base/network_quality_estimator.cc b/net/base/network_quality_estimator.cc
|
| index 6415ee6e6d7eb36b47ab4fd568d3537283b27729..e864c7e1f4619501fb8ce7073545f6f4c3ab7752 100644
|
| --- a/net/base/network_quality_estimator.cc
|
| +++ b/net/base/network_quality_estimator.cc
|
| @@ -4,6 +4,7 @@
|
|
|
| #include "net/base/network_quality_estimator.h"
|
|
|
| +#include <limits>
|
| #include <string>
|
|
|
| #include "base/logging.h"
|
| @@ -13,6 +14,13 @@
|
| #include "net/url_request/url_request.h"
|
| #include "url/gurl.h"
|
|
|
| +namespace {
|
| +
|
| +// Maximum number of observations that can be held in the ObservationBuffer.
|
| +const size_t kMaximumObservationsBufferSize = 500;
|
| +
|
| +} // namespace
|
| +
|
| namespace net {
|
|
|
| NetworkQualityEstimator::NetworkQualityEstimator()
|
| @@ -24,7 +32,7 @@ NetworkQualityEstimator::NetworkQualityEstimator(
|
| : allow_localhost_requests_(allow_local_host_requests_for_tests),
|
| last_connection_change_(base::TimeTicks::Now()),
|
| current_connection_type_(NetworkChangeNotifier::GetConnectionType()),
|
| - bytes_read_since_last_connection_change_(false),
|
| + fastest_rtt_since_last_connection_change_(base::TimeDelta::Max()),
|
| peak_kbps_since_last_connection_change_(0) {
|
| static_assert(kMinRequestDurationMicroseconds > 0,
|
| "Minimum request duration must be > 0");
|
| @@ -36,10 +44,13 @@ NetworkQualityEstimator::~NetworkQualityEstimator() {
|
| NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
|
| }
|
|
|
| -void NetworkQualityEstimator::NotifyDataReceived(const URLRequest& request,
|
| - int64_t prefilter_bytes_read) {
|
| +void NetworkQualityEstimator::NotifyDataReceived(
|
| + const URLRequest& request,
|
| + int64_t cumulative_prefilter_bytes_read,
|
| + int64_t prefiltered_bytes_read) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| - DCHECK_GT(prefilter_bytes_read, 0);
|
| + DCHECK_GT(cumulative_prefilter_bytes_read, 0);
|
| + DCHECK_GT(prefiltered_bytes_read, 0);
|
|
|
| if (!request.url().is_valid() ||
|
| (!allow_localhost_requests_ && IsLocalhost(request.url().host())) ||
|
| @@ -54,61 +65,77 @@ void NetworkQualityEstimator::NotifyDataReceived(const URLRequest& request,
|
| base::TimeTicks now = base::TimeTicks::Now();
|
| base::TimeDelta request_duration = now - request.creation_time();
|
| DCHECK_GE(request_duration, base::TimeDelta());
|
| - if (!bytes_read_since_last_connection_change_)
|
| - fastest_RTT_since_last_connection_change_ = request_duration;
|
|
|
| - bytes_read_since_last_connection_change_ = true;
|
| - if (request_duration < fastest_RTT_since_last_connection_change_)
|
| - fastest_RTT_since_last_connection_change_ = request_duration;
|
| + // Only add RTT observation if this is the first read for this response.
|
| + if (cumulative_prefilter_bytes_read == prefiltered_bytes_read) {
|
| + if (request_duration < fastest_rtt_since_last_connection_change_)
|
| + fastest_rtt_since_last_connection_change_ = request_duration;
|
| +
|
| + rtt_msec_observations_.AddObservation(
|
| + Observation(request_duration.InMilliseconds(), now));
|
| + }
|
|
|
| // Ignore tiny transfers which will not produce accurate rates.
|
| // Ignore short duration transfers.
|
| - if (prefilter_bytes_read >= kMinTransferSizeInBytes &&
|
| + if (cumulative_prefilter_bytes_read >= kMinTransferSizeInBytes &&
|
| request_duration >=
|
| base::TimeDelta::FromMicroseconds(kMinRequestDurationMicroseconds)) {
|
| - uint64_t kbps = static_cast<uint64_t>(prefilter_bytes_read * 8 * 1000 /
|
| - request_duration.InMicroseconds());
|
| - if (kbps > peak_kbps_since_last_connection_change_)
|
| - peak_kbps_since_last_connection_change_ = kbps;
|
| + double kbps_f = cumulative_prefilter_bytes_read * 8.0 / 1000.0 /
|
| + request_duration.InSecondsF();
|
| + DCHECK_GE(kbps_f, 0.0);
|
| +
|
| + // Check overflow errors. This may happen if the kbpsF is more than
|
| + // 2 * 10^9 (= 2000 Gbps).
|
| + if (kbps_f >= std::numeric_limits<int32_t>::max())
|
| + kbps_f = std::numeric_limits<int32_t>::max() - 1;
|
| +
|
| + int32_t kbps = static_cast<int32_t>(kbps_f);
|
| +
|
| + if (kbps > 0) {
|
| + if (kbps > peak_kbps_since_last_connection_change_)
|
| + peak_kbps_since_last_connection_change_ = kbps;
|
| +
|
| + kbps_observations_.AddObservation(Observation(kbps, now));
|
| + }
|
| }
|
| }
|
|
|
| void NetworkQualityEstimator::OnConnectionTypeChanged(
|
| NetworkChangeNotifier::ConnectionType type) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| - if (bytes_read_since_last_connection_change_) {
|
| + if (fastest_rtt_since_last_connection_change_ != base::TimeDelta::Max()) {
|
| switch (current_connection_type_) {
|
| case NetworkChangeNotifier::CONNECTION_UNKNOWN:
|
| UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Unknown",
|
| - fastest_RTT_since_last_connection_change_);
|
| + fastest_rtt_since_last_connection_change_);
|
| break;
|
| case NetworkChangeNotifier::CONNECTION_ETHERNET:
|
| UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Ethernet",
|
| - fastest_RTT_since_last_connection_change_);
|
| + fastest_rtt_since_last_connection_change_);
|
| break;
|
| case NetworkChangeNotifier::CONNECTION_WIFI:
|
| UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Wifi",
|
| - fastest_RTT_since_last_connection_change_);
|
| + fastest_rtt_since_last_connection_change_);
|
| break;
|
| case NetworkChangeNotifier::CONNECTION_2G:
|
| UMA_HISTOGRAM_TIMES("NQE.FastestRTT.2G",
|
| - fastest_RTT_since_last_connection_change_);
|
| + fastest_rtt_since_last_connection_change_);
|
| break;
|
| case NetworkChangeNotifier::CONNECTION_3G:
|
| UMA_HISTOGRAM_TIMES("NQE.FastestRTT.3G",
|
| - fastest_RTT_since_last_connection_change_);
|
| + fastest_rtt_since_last_connection_change_);
|
| break;
|
| case NetworkChangeNotifier::CONNECTION_4G:
|
| UMA_HISTOGRAM_TIMES("NQE.FastestRTT.4G",
|
| - fastest_RTT_since_last_connection_change_);
|
| + fastest_rtt_since_last_connection_change_);
|
| break;
|
| case NetworkChangeNotifier::CONNECTION_NONE:
|
| UMA_HISTOGRAM_TIMES("NQE.FastestRTT.None",
|
| - fastest_RTT_since_last_connection_change_);
|
| + fastest_rtt_since_last_connection_change_);
|
| break;
|
| case NetworkChangeNotifier::CONNECTION_BLUETOOTH:
|
| UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Bluetooth",
|
| - fastest_RTT_since_last_connection_change_);
|
| + fastest_rtt_since_last_connection_change_);
|
| break;
|
| default:
|
| NOTREACHED();
|
| @@ -157,24 +184,67 @@ void NetworkQualityEstimator::OnConnectionTypeChanged(
|
| }
|
|
|
| last_connection_change_ = base::TimeTicks::Now();
|
| - bytes_read_since_last_connection_change_ = false;
|
| peak_kbps_since_last_connection_change_ = 0;
|
| + fastest_rtt_since_last_connection_change_ = base::TimeDelta::Max();
|
| + kbps_observations_.Clear();
|
| + rtt_msec_observations_.Clear();
|
| current_connection_type_ = type;
|
| }
|
|
|
| -NetworkQuality NetworkQualityEstimator::GetEstimate() const {
|
| +NetworkQuality NetworkQualityEstimator::GetPeakEstimate() const {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
|
|
| - if (!bytes_read_since_last_connection_change_) {
|
| - return NetworkQuality(fastest_RTT_since_last_connection_change_, 0,
|
| - peak_kbps_since_last_connection_change_, 0);
|
| - }
|
| - if (!peak_kbps_since_last_connection_change_) {
|
| - return NetworkQuality(fastest_RTT_since_last_connection_change_, 0.1,
|
| - peak_kbps_since_last_connection_change_, 0);
|
| - }
|
| - return NetworkQuality(fastest_RTT_since_last_connection_change_, 0.1,
|
| - peak_kbps_since_last_connection_change_, 0.1);
|
| + return NetworkQuality(fastest_rtt_since_last_connection_change_,
|
| + peak_kbps_since_last_connection_change_);
|
| +}
|
| +
|
| +size_t NetworkQualityEstimator::GetMaximumObservationBufferSizeForTests()
|
| + const {
|
| + return kMaximumObservationsBufferSize;
|
| +}
|
| +
|
| +bool NetworkQualityEstimator::VerifyBufferSizeForTests(
|
| + size_t expected_size) const {
|
| + return kbps_observations_.Size() == expected_size &&
|
| + rtt_msec_observations_.Size() == expected_size;
|
| +}
|
| +
|
| +NetworkQualityEstimator::Observation::Observation(int32_t value,
|
| + base::TimeTicks timestamp)
|
| + : value(value), timestamp(timestamp) {
|
| + DCHECK_GE(value, 0);
|
| + DCHECK(!timestamp.is_null());
|
| +}
|
| +
|
| +NetworkQualityEstimator::Observation::~Observation() {
|
| +}
|
| +
|
| +NetworkQualityEstimator::ObservationBuffer::ObservationBuffer() {
|
| + static_assert(kMaximumObservationsBufferSize > 0U,
|
| + "Minimum size of observation buffer must be > 0");
|
| +}
|
| +
|
| +NetworkQualityEstimator::ObservationBuffer::~ObservationBuffer() {
|
| +}
|
| +
|
| +void NetworkQualityEstimator::ObservationBuffer::AddObservation(
|
| + const Observation& observation) {
|
| + DCHECK_LE(observations_.size(), kMaximumObservationsBufferSize);
|
| + // Evict the oldest element if the buffer is already full.
|
| + if (observations_.size() == kMaximumObservationsBufferSize)
|
| + observations_.pop_front();
|
| +
|
| + observations_.push_back(observation);
|
| + DCHECK_LE(observations_.size(), kMaximumObservationsBufferSize);
|
| +}
|
| +
|
| +size_t NetworkQualityEstimator::ObservationBuffer::Size() const {
|
| + return observations_.size();
|
| +}
|
| +
|
| +void NetworkQualityEstimator::ObservationBuffer::Clear() {
|
| + observations_.clear();
|
| + DCHECK(observations_.empty());
|
| }
|
|
|
| } // namespace net
|
|
|