| Index: net/base/network_quality_estimator.cc
|
| diff --git a/net/base/network_quality_estimator.cc b/net/base/network_quality_estimator.cc
|
| index 37cbcc0efe08f40589c770b2a89a0cdd1507ef7e..3e68cca806dea7001dc194c5f14726864a347b73 100644
|
| --- a/net/base/network_quality_estimator.cc
|
| +++ b/net/base/network_quality_estimator.cc
|
| @@ -141,6 +141,8 @@ NetworkQualityEstimator::NetworkQualityEstimator(
|
| downstream_throughput_kbps_observations_(
|
| GetWeightMultiplierPerSecond(variation_params)),
|
| rtt_msec_observations_(GetWeightMultiplierPerSecond(variation_params)),
|
| + packet_loss_rate_observations_(
|
| + GetWeightMultiplierPerSecond(variation_params)),
|
| external_estimate_provider_(std::move(external_estimates_provider)) {
|
| static_assert(kMinRequestDurationMicroseconds > 0,
|
| "Minimum request duration must be > 0");
|
| @@ -250,6 +252,17 @@ void NetworkQualityEstimator::NotifyHeadersReceived(const URLRequest& request) {
|
| estimated_median_network_quality_ = NetworkQuality(
|
| GetRTTEstimateInternal(base::TimeTicks(), 50),
|
| GetDownlinkThroughputKbpsEstimateInternal(base::TimeTicks(), 50));
|
| +
|
| + float packet_loss_rate;
|
| + if (GetPacketLossRateEstimate(&packet_loss_rate)) {
|
| + DCHECK_LE(0.0f, packet_loss_rate);
|
| + DCHECK_GE(1.0f, packet_loss_rate);
|
| +
|
| + // Largest bucket is 101.
|
| + base::HistogramBase* packet_loss_histogram =
|
| + GetHistogram("PacketLossRate.", current_network_id_.type, 101);
|
| + packet_loss_histogram->Add(packet_loss_rate * 100.0f);
|
| + }
|
| }
|
|
|
| base::TimeTicks now = base::TimeTicks::Now();
|
| @@ -376,6 +389,18 @@ void NetworkQualityEstimator::RemoveThroughputObserver(
|
| throughput_observer_list_.RemoveObserver(throughput_observer);
|
| }
|
|
|
| +void NetworkQualityEstimator::AddPacketLossObserver(
|
| + PacketLossObserver* packet_loss_observer) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + packet_loss_observer_list_.AddObserver(packet_loss_observer);
|
| +}
|
| +
|
| +void NetworkQualityEstimator::RemovePacketLossObserver(
|
| + PacketLossObserver* packet_loss_observer) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + packet_loss_observer_list_.RemoveObserver(packet_loss_observer);
|
| +}
|
| +
|
| void NetworkQualityEstimator::RecordRTTUMA(int32_t estimated_value_msec,
|
| int32_t actual_value_msec) const {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| @@ -429,6 +454,22 @@ void NetworkQualityEstimator::RecordExternalEstimateProviderMetrics(
|
| EXTERNAL_ESTIMATE_PROVIDER_STATUS_BOUNDARY);
|
| }
|
|
|
| +bool NetworkQualityEstimator::GetObservationSourceForProtocol(
|
| + Protocol protocol,
|
| + NetworkQualityEstimator::ObservationSource* observation_source) const {
|
| + switch (protocol) {
|
| + case PROTOCOL_TCP:
|
| + *observation_source = TCP;
|
| + return true;
|
| + case PROTOCOL_QUIC:
|
| + *observation_source = QUIC;
|
| + return true;
|
| + default:
|
| + NOTREACHED();
|
| + return false;
|
| + }
|
| +}
|
| +
|
| void NetworkQualityEstimator::OnConnectionTypeChanged(
|
| NetworkChangeNotifier::ConnectionType type) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| @@ -546,6 +587,7 @@ void NetworkQualityEstimator::OnConnectionTypeChanged(
|
| peak_network_quality_ = NetworkQuality();
|
| downstream_throughput_kbps_observations_.Clear();
|
| rtt_msec_observations_.Clear();
|
| + packet_loss_rate_observations_.Clear();
|
| current_network_id_ = GetCurrentNetworkID();
|
|
|
| QueryExternalEstimateProvider();
|
| @@ -580,6 +622,17 @@ bool NetworkQualityEstimator::GetDownlinkThroughputKbpsEstimate(
|
| return (*kbps != kInvalidThroughput);
|
| }
|
|
|
| +bool NetworkQualityEstimator::GetPacketLossRateEstimate(
|
| + float* packet_loss_rate_estimate) const {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| + float estimate = GetPacketLossRateEstimateInternal(base::TimeTicks());
|
| + if (estimate < 0.0f || estimate > 1.0f)
|
| + return false;
|
| + *packet_loss_rate_estimate = estimate;
|
| + return true;
|
| +}
|
| +
|
| bool NetworkQualityEstimator::GetRecentMedianRTT(
|
| const base::TimeTicks& begin_timestamp,
|
| base::TimeDelta* rtt) const {
|
| @@ -644,6 +697,23 @@ int32_t NetworkQualityEstimator::GetDownlinkThroughputKbpsEstimateInternal(
|
| return kbps;
|
| }
|
|
|
| +float NetworkQualityEstimator::GetPacketLossRateEstimateInternal(
|
| + const base::TimeTicks& begin_timestamp) const {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| + if (packet_loss_rate_observations_.Size() == 0)
|
| + return -1.0f;
|
| +
|
| + float packet_loss_rate;
|
| + if (!packet_loss_rate_observations_.GetWeightedAverage(begin_timestamp,
|
| + &packet_loss_rate)) {
|
| + return -1.0f;
|
| + }
|
| + DCHECK_LE(0.0f, packet_loss_rate);
|
| + DCHECK_GE(1.0f, packet_loss_rate);
|
| + return packet_loss_rate;
|
| +}
|
| +
|
| template <typename ValueType>
|
| void NetworkQualityEstimator::ObservationBuffer<ValueType>::
|
| ComputeWeightedObservations(
|
| @@ -717,6 +787,39 @@ bool NetworkQualityEstimator::ObservationBuffer<ValueType>::GetPercentile(
|
| return true;
|
| }
|
|
|
| +template <typename ValueType>
|
| +bool NetworkQualityEstimator::ObservationBuffer<ValueType>::GetWeightedAverage(
|
| + const base::TimeTicks& begin_timestamp,
|
| + ValueType* result) const {
|
| + DCHECK(result);
|
| +
|
| + // Stores |weighted_observations| in the increasing order of value with lower
|
| + // values at the front of the vector.
|
| + std::vector<WeightedObservation<ValueType>> weighted_observations;
|
| +
|
| + // The sum of the weights of all observations in |weighted_observations|.
|
| + double total_weight = 0.0;
|
| +
|
| + ComputeWeightedObservations(begin_timestamp, weighted_observations,
|
| + &total_weight);
|
| + if (weighted_observations.empty())
|
| + return false;
|
| +
|
| + DCHECK_GT(total_weight, 0.0);
|
| +
|
| + // |weighted_observations| may have a smaller size than |observations_| since
|
| + // the former only contains the observations later than |begin_timestamp|.
|
| + DCHECK_GE(observations_.size(), weighted_observations.size());
|
| +
|
| + double total_weight_times_value = 0.0;
|
| + for (const auto& weighted_observation : weighted_observations) {
|
| + total_weight_times_value +=
|
| + (weighted_observation.weight * weighted_observation.value);
|
| + }
|
| + *result = total_weight_times_value / total_weight;
|
| + return true;
|
| +}
|
| +
|
| NetworkQualityEstimator::NetworkID
|
| NetworkQualityEstimator::GetCurrentNetworkID() const {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| @@ -900,20 +1003,47 @@ void NetworkQualityEstimator::OnUpdatedRTTAvailable(
|
| const base::TimeDelta& rtt) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
|
|
| - switch (protocol) {
|
| - case PROTOCOL_TCP:
|
| - NotifyObserversOfRTT(RttObservation(rtt, base::TimeTicks::Now(), TCP));
|
| - return;
|
| - case PROTOCOL_QUIC:
|
| - NotifyObserversOfRTT(RttObservation(rtt, base::TimeTicks::Now(), QUIC));
|
| - return;
|
| - default:
|
| - NOTREACHED();
|
| + ObservationSource observation_source;
|
| + if (!GetObservationSourceForProtocol(protocol, &observation_source))
|
| + return;
|
| +
|
| + NotifyObserversOfRTT(
|
| + RttObservation(rtt, base::TimeTicks::Now(), observation_source));
|
| +}
|
| +
|
| +void NetworkQualityEstimator::OnUpdatedPacketCountAvailable(
|
| + Protocol protocol,
|
| + size_t packets_lost,
|
| + size_t packets_received_in_order,
|
| + size_t packets_received_out_of_order) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| + const base::TimeTicks now = base::TimeTicks::Now();
|
| +
|
| + ObservationSource observation_source;
|
| + if (!GetObservationSourceForProtocol(protocol, &observation_source))
|
| + return;
|
| +
|
| + for (size_t i = 0; i < packets_lost; ++i) {
|
| + packet_loss_rate_observations_.AddObservation(
|
| + PacketLossRateObservation(1.0, now, observation_source));
|
| }
|
| + for (size_t i = 0; i < packets_received_in_order; ++i) {
|
| + packet_loss_rate_observations_.AddObservation(
|
| + PacketLossRateObservation(0.0, now, observation_source));
|
| + }
|
| + // For packet loss estimation, we neglect the packets that were previously
|
| + // marked as lost but are later received out-of-order.
|
| + NotifyObserversOfPacketLoss(packets_lost, packets_received_in_order,
|
| + packets_received_out_of_order, now,
|
| + observation_source);
|
| }
|
|
|
| void NetworkQualityEstimator::NotifyObserversOfRTT(
|
| const RttObservation& observation) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + DCHECK_NE(EXTERNAL_ESTIMATE, observation.source);
|
| +
|
| FOR_EACH_OBSERVER(
|
| RTTObserver, rtt_observer_list_,
|
| OnRTTObservation(observation.value.InMilliseconds(),
|
| @@ -922,12 +1052,30 @@ void NetworkQualityEstimator::NotifyObserversOfRTT(
|
|
|
| void NetworkQualityEstimator::NotifyObserversOfThroughput(
|
| const ThroughputObservation& observation) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + DCHECK_NE(EXTERNAL_ESTIMATE, observation.source);
|
| +
|
| FOR_EACH_OBSERVER(
|
| ThroughputObserver, throughput_observer_list_,
|
| OnThroughputObservation(observation.value, observation.timestamp,
|
| observation.source));
|
| }
|
|
|
| +void NetworkQualityEstimator::NotifyObserversOfPacketLoss(
|
| + size_t packets_lost,
|
| + size_t packets_received_in_order,
|
| + size_t packets_received_out_of_order,
|
| + const base::TimeTicks& timestamp,
|
| + ObservationSource source) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + DCHECK_NE(EXTERNAL_ESTIMATE, source);
|
| +
|
| + FOR_EACH_OBSERVER(PacketLossObserver, packet_loss_observer_list_,
|
| + OnPacketLossObservation(
|
| + packets_lost, packets_received_in_order,
|
| + packets_received_out_of_order, timestamp, source));
|
| +}
|
| +
|
| NetworkQualityEstimator::CachedNetworkQuality::CachedNetworkQuality(
|
| const NetworkQuality& network_quality)
|
| : last_update_time_(base::TimeTicks::Now()),
|
|
|