Skip to content
This repository has been archived by the owner on Apr 3, 2020. It is now read-only.

Commit

Permalink
Expose median transport layer RTT from NQE
Browse files Browse the repository at this point in the history
NetworkQualityEstimator (NQE) exposes median transport
layer RTT. It also records the median transport layer RTT
as UMA metric.

BUG=498380

Review-Url: https://codereview.chromium.org/1926733004
Cr-Commit-Position: refs/heads/master@{#394841}
  • Loading branch information
tbansal authored and Commit bot committed May 19, 2016
1 parent 903e2b8 commit c2e2b46
Show file tree
Hide file tree
Showing 4 changed files with 223 additions and 65 deletions.
159 changes: 118 additions & 41 deletions net/nqe/network_quality_estimator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,18 @@ bool GetValueForVariationParam(
base::StringToInt(it->second, variations_value);
}

net::NetworkQualityObservationSource ProtocolSourceToObservationSource(
net::SocketPerformanceWatcherFactory::Protocol protocol) {
switch (protocol) {
case net::SocketPerformanceWatcherFactory::PROTOCOL_TCP:
return net::NETWORK_QUALITY_OBSERVATION_SOURCE_TCP;
case net::SocketPerformanceWatcherFactory::PROTOCOL_QUIC:
return net::NETWORK_QUALITY_OBSERVATION_SOURCE_QUIC;
}
NOTREACHED();
return net::NETWORK_QUALITY_OBSERVATION_SOURCE_TCP;
}

} // namespace

namespace net {
Expand Down Expand Up @@ -447,8 +459,9 @@ void NetworkQualityEstimator::NotifyHeadersReceived(const URLRequest& request) {

// Compare the RTT observation with the estimated value and record it.
if (estimated_median_network_quality_.rtt() != nqe::internal::InvalidRTT()) {
RecordRTTUMA(estimated_median_network_quality_.rtt().InMilliseconds(),
observed_rtt.InMilliseconds());
RecordURLRequestRTTUMA(
estimated_median_network_quality_.rtt().InMilliseconds(),
observed_rtt.InMilliseconds());
}
}

Expand Down Expand Up @@ -549,8 +562,9 @@ NetworkQualityEstimator::GetSocketPerformanceWatcherFactory() {
return watcher_factory_.get();
}

void NetworkQualityEstimator::RecordRTTUMA(int32_t estimated_value_msec,
int32_t actual_value_msec) const {
void NetworkQualityEstimator::RecordURLRequestRTTUMA(
int32_t estimated_value_msec,
int32_t actual_value_msec) const {
DCHECK(thread_checker_.CalledOnValidThread());

// Record the difference between the actual and the estimated value.
Expand Down Expand Up @@ -605,6 +619,30 @@ void NetworkQualityEstimator::RecordExternalEstimateProviderMetrics(
void NetworkQualityEstimator::OnConnectionTypeChanged(
NetworkChangeNotifier::ConnectionType type) {
DCHECK(thread_checker_.CalledOnValidThread());

RecordMetricsOnConnectionTypeChanged();

// Write the estimates of the previous network to the cache.
CacheNetworkQualityEstimate();

// Clear the local state.
last_connection_change_ = base::TimeTicks::Now();
peak_network_quality_ = nqe::internal::NetworkQuality();
downstream_throughput_kbps_observations_.Clear();
rtt_observations_.Clear();
current_network_id_ = GetCurrentNetworkID();

QueryExternalEstimateProvider();

// Read any cached estimates for the new network. If cached estimates are
// unavailable, add the default estimates.
if (!ReadCachedNetworkQualityEstimate())
AddDefaultEstimates();
estimated_median_network_quality_ = nqe::internal::NetworkQuality();
}

void NetworkQualityEstimator::RecordMetricsOnConnectionTypeChanged() {
DCHECK(thread_checker_.CalledOnValidThread());
if (peak_network_quality_.rtt() != nqe::internal::InvalidRTT()) {
base::HistogramBase* rtt_histogram =
GetHistogram("FastestRTT.", current_network_id_.type, 10 * 1000);
Expand Down Expand Up @@ -644,23 +682,34 @@ void NetworkQualityEstimator::OnConnectionTypeChanged(
}
}

// Write the estimates of the previous network to the cache.
CacheNetworkQualityEstimate();

// Clear the local state.
last_connection_change_ = base::TimeTicks::Now();
peak_network_quality_ = nqe::internal::NetworkQuality();
downstream_throughput_kbps_observations_.Clear();
rtt_observations_.Clear();
current_network_id_ = GetCurrentNetworkID();
if (GetTransportRTTEstimate(&rtt)) {
// Add the 50th percentile value.
base::HistogramBase* transport_rtt_percentile = GetHistogram(
"TransportRTT.Percentile50.", current_network_id_.type, 10 * 1000);
transport_rtt_percentile->Add(rtt.InMilliseconds());

QueryExternalEstimateProvider();
// Add the remaining percentile values.
static const int kPercentiles[] = {0, 10, 90, 100};
std::vector<NetworkQualityObservationSource> disallowed_observation_sources;
disallowed_observation_sources.push_back(
NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST);
// Disallow external estimate provider since it provides RTT at HTTP layer.
disallowed_observation_sources.push_back(
NETWORK_QUALITY_OBSERVATION_SOURCE_EXTERNAL_ESTIMATE);
disallowed_observation_sources.push_back(
NETWORK_QUALITY_OBSERVATION_SOURCE_CACHED_ESTIMATE);
disallowed_observation_sources.push_back(
NETWORK_QUALITY_OBSERVATION_SOURCE_DEFAULT_FROM_PLATFORM);
for (size_t i = 0; i < arraysize(kPercentiles); ++i) {
rtt = GetRTTEstimateInternal(disallowed_observation_sources,
base::TimeTicks(), kPercentiles[i]);

// Read any cached estimates for the new network. If cached estimates are
// unavailable, add the default estimates.
if (!ReadCachedNetworkQualityEstimate())
AddDefaultEstimates();
estimated_median_network_quality_ = nqe::internal::NetworkQuality();
transport_rtt_percentile = GetHistogram(
"TransportRTT.Percentile" + base::IntToString(kPercentiles[i]) + ".",
current_network_id_.type, 10 * 1000); // 10 seconds
transport_rtt_percentile->Add(rtt.InMilliseconds());
}
}
}

NetworkQualityEstimator::EffectiveConnectionType
Expand Down Expand Up @@ -723,6 +772,25 @@ bool NetworkQualityEstimator::GetURLRequestRTTEstimate(
return (*rtt != nqe::internal::InvalidRTT());
}

bool NetworkQualityEstimator::GetTransportRTTEstimate(
base::TimeDelta* rtt) const {
DCHECK(thread_checker_.CalledOnValidThread());
std::vector<NetworkQualityObservationSource> disallowed_observation_sources;
disallowed_observation_sources.push_back(
NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST);
// Disallow external estimate provider since it provides RTT at HTTP layer.
disallowed_observation_sources.push_back(
NETWORK_QUALITY_OBSERVATION_SOURCE_EXTERNAL_ESTIMATE);
disallowed_observation_sources.push_back(
NETWORK_QUALITY_OBSERVATION_SOURCE_CACHED_ESTIMATE);
disallowed_observation_sources.push_back(
NETWORK_QUALITY_OBSERVATION_SOURCE_DEFAULT_FROM_PLATFORM);

*rtt = GetRTTEstimateInternal(disallowed_observation_sources,
base::TimeTicks(), 50);
return (*rtt != nqe::internal::InvalidRTT());
}

bool NetworkQualityEstimator::GetDownlinkThroughputKbpsEstimate(
int32_t* kbps) const {
DCHECK(thread_checker_.CalledOnValidThread());
Expand All @@ -731,54 +799,72 @@ bool NetworkQualityEstimator::GetDownlinkThroughputKbpsEstimate(
}

bool NetworkQualityEstimator::GetRecentURLRequestRTTMedian(
const base::TimeTicks& begin_timestamp,
const base::TimeTicks& start_time,
base::TimeDelta* rtt) const {
DCHECK(thread_checker_.CalledOnValidThread());
std::vector<NetworkQualityObservationSource> disallowed_observation_sources;
disallowed_observation_sources.push_back(
NETWORK_QUALITY_OBSERVATION_SOURCE_TCP);
disallowed_observation_sources.push_back(
NETWORK_QUALITY_OBSERVATION_SOURCE_QUIC);
*rtt = GetRTTEstimateInternal(disallowed_observation_sources, begin_timestamp,
50);
*rtt = GetRTTEstimateInternal(disallowed_observation_sources, start_time, 50);
return (*rtt != nqe::internal::InvalidRTT());
}

bool NetworkQualityEstimator::GetRecentTransportRTTMedian(
const base::TimeTicks& start_time,
base::TimeDelta* rtt) const {
DCHECK(thread_checker_.CalledOnValidThread());
std::vector<NetworkQualityObservationSource> disallowed_observation_sources;
disallowed_observation_sources.push_back(
NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST);
// Disallow external estimate provider since it provides RTT at HTTP layer.
disallowed_observation_sources.push_back(
NETWORK_QUALITY_OBSERVATION_SOURCE_EXTERNAL_ESTIMATE);
disallowed_observation_sources.push_back(
NETWORK_QUALITY_OBSERVATION_SOURCE_CACHED_ESTIMATE);
disallowed_observation_sources.push_back(
NETWORK_QUALITY_OBSERVATION_SOURCE_DEFAULT_FROM_PLATFORM);

*rtt = GetRTTEstimateInternal(disallowed_observation_sources, start_time, 50);
return (*rtt != nqe::internal::InvalidRTT());
}

bool NetworkQualityEstimator::GetRecentMedianDownlinkThroughputKbps(
const base::TimeTicks& begin_timestamp,
const base::TimeTicks& start_time,
int32_t* kbps) const {
DCHECK(thread_checker_.CalledOnValidThread());
*kbps = GetDownlinkThroughputKbpsEstimateInternal(begin_timestamp, 50);
*kbps = GetDownlinkThroughputKbpsEstimateInternal(start_time, 50);
return (*kbps != nqe::internal::kInvalidThroughput);
}

base::TimeDelta NetworkQualityEstimator::GetRTTEstimateInternal(
const std::vector<NetworkQualityObservationSource>&
disallowed_observation_sources,
const base::TimeTicks& begin_timestamp,
const base::TimeTicks& start_time,
int percentile) const {
DCHECK(thread_checker_.CalledOnValidThread());

// RTT observations are sorted by duration from shortest to longest, thus
// a higher percentile RTT will have a longer RTT than a lower percentile.
base::TimeDelta rtt = nqe::internal::InvalidRTT();
if (!rtt_observations_.GetPercentile(begin_timestamp, &rtt, percentile,
if (!rtt_observations_.GetPercentile(start_time, &rtt, percentile,
disallowed_observation_sources)) {
return nqe::internal::InvalidRTT();
}
return rtt;
}

int32_t NetworkQualityEstimator::GetDownlinkThroughputKbpsEstimateInternal(
const base::TimeTicks& begin_timestamp,
const base::TimeTicks& start_time,
int percentile) const {
DCHECK(thread_checker_.CalledOnValidThread());

// Throughput observations are sorted by kbps from slowest to fastest,
// thus a higher percentile throughput will be faster than a lower one.
int32_t kbps = nqe::internal::kInvalidThroughput;
if (!downstream_throughput_kbps_observations_.GetPercentile(
begin_timestamp, &kbps, 100 - percentile,
start_time, &kbps, 100 - percentile,
std::vector<NetworkQualityObservationSource>())) {
return nqe::internal::kInvalidThroughput;
}
Expand Down Expand Up @@ -998,19 +1084,10 @@ void NetworkQualityEstimator::OnUpdatedRTTAvailable(
const base::TimeDelta& rtt) {
DCHECK(thread_checker_.CalledOnValidThread());

switch (protocol) {
case SocketPerformanceWatcherFactory::PROTOCOL_TCP:
NotifyObserversOfRTT(RttObservation(
rtt, base::TimeTicks::Now(), NETWORK_QUALITY_OBSERVATION_SOURCE_TCP));
return;
case SocketPerformanceWatcherFactory::PROTOCOL_QUIC:
NotifyObserversOfRTT(
RttObservation(rtt, base::TimeTicks::Now(),
NETWORK_QUALITY_OBSERVATION_SOURCE_QUIC));
return;
default:
NOTREACHED();
}
RttObservation observation(rtt, base::TimeTicks::Now(),
ProtocolSourceToObservationSource(protocol));
NotifyObserversOfRTT(observation);
rtt_observations_.AddObservation(observation);
}

void NetworkQualityEstimator::NotifyObserversOfRTT(
Expand Down
44 changes: 29 additions & 15 deletions net/nqe/network_quality_estimator.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,14 +140,18 @@ class NET_EXPORT_PRIVATE NetworkQualityEstimator
// testing.
virtual EffectiveConnectionType GetEffectiveConnectionType() const;

// Returns true if RTT is available and sets |rtt| to estimated RTT at the
// HTTP layer. Virtualized for testing. |rtt| should not be null. The RTT at
// the HTTP layer measures the time from when the request was sent (this
// Returns true if the RTT is available and sets |rtt| to the RTT estimated at
// the HTTP layer. Virtualized for testing. |rtt| should not be null. The RTT
// at the HTTP layer measures the time from when the request was sent (this
// happens after the connection is established) to the time when the response
// headers were received.
virtual bool GetURLRequestRTTEstimate(base::TimeDelta* rtt) const
WARN_UNUSED_RESULT;

// Returns true if the RTT is available and sets |rtt| to the RTT estimated at
// the transport layer. |rtt| should not be null.
bool GetTransportRTTEstimate(base::TimeDelta* rtt) const WARN_UNUSED_RESULT;

// Returns true if downlink throughput is available and sets |kbps| to
// estimated downlink throughput (in kilobits per second).
// Virtualized for testing. |kbps| should not be null.
Expand All @@ -162,21 +166,28 @@ class NET_EXPORT_PRIVATE NetworkQualityEstimator
void NotifyRequestCompleted(const URLRequest& request);

// Returns true if median RTT at the HTTP layer is available and sets |rtt|
// to the median of RTT observations since |begin_timestamp|.
// to the median of RTT observations since |start_time|.
// Virtualized for testing. |rtt| should not be null. The RTT at the HTTP
// layer measures the time from when the request was sent (this happens after
// the connection is established) to the time when the response headers were
// received.
virtual bool GetRecentURLRequestRTTMedian(
const base::TimeTicks& begin_timestamp,
base::TimeDelta* rtt) const WARN_UNUSED_RESULT;
virtual bool GetRecentURLRequestRTTMedian(const base::TimeTicks& start_time,
base::TimeDelta* rtt) const
WARN_UNUSED_RESULT;

// Returns true if the median RTT at the transport layer is available and sets
// |rtt| to the median of transport layer RTT observations since
// |start_time|. |rtt| should not be null.
bool GetRecentTransportRTTMedian(const base::TimeTicks& start_time,
base::TimeDelta* rtt) const
WARN_UNUSED_RESULT;

// Returns true if median downstream throughput is available and sets |kbps|
// to the median of downstream throughput (in kilobits per second)
// observations since |begin_timestamp|. Virtualized for testing. |kbps|
// observations since |start_time|. Virtualized for testing. |kbps|
// should not be null.
virtual bool GetRecentMedianDownlinkThroughputKbps(
const base::TimeTicks& begin_timestamp,
const base::TimeTicks& start_time,
int32_t* kbps) const WARN_UNUSED_RESULT;

// Adds |rtt_observer| to the list of round trip time observers. Must be
Expand Down Expand Up @@ -310,6 +321,9 @@ class NET_EXPORT_PRIVATE NetworkQualityEstimator
// should discard RTT if it is set to the value returned by |InvalidRTT()|.
static const base::TimeDelta InvalidRTT();

// Records UMA when there is a change in connection type.
void RecordMetricsOnConnectionTypeChanged();

// Notifies |this| of a new transport layer RTT.
void OnUpdatedRTTAvailable(SocketPerformanceWatcherFactory::Protocol protocol,
const base::TimeDelta& rtt);
Expand All @@ -336,7 +350,7 @@ class NET_EXPORT_PRIVATE NetworkQualityEstimator
// Returns an estimate of network quality at the specified |percentile|.
// |disallowed_observation_sources| is the list of observation sources that
// should be excluded when computing the percentile.
// Only the observations later than |begin_timestamp| are taken into account.
// Only the observations later than |start_time| are taken into account.
// |percentile| must be between 0 and 100 (both inclusive) with higher
// percentiles indicating less performant networks. For example, if
// |percentile| is 90, then the network is expected to be faster than the
Expand All @@ -345,10 +359,10 @@ class NET_EXPORT_PRIVATE NetworkQualityEstimator
base::TimeDelta GetRTTEstimateInternal(
const std::vector<NetworkQualityObservationSource>&
disallowed_observation_sources,
const base::TimeTicks& begin_timestamp,
const base::TimeTicks& start_time,
int percentile) const;
int32_t GetDownlinkThroughputKbpsEstimateInternal(
const base::TimeTicks& begin_timestamp,
const base::TimeTicks& start_time,
int percentile) const;

// Returns the current network ID checking by calling the platform APIs.
Expand All @@ -362,9 +376,9 @@ class NET_EXPORT_PRIVATE NetworkQualityEstimator

void NotifyObserversOfThroughput(const ThroughputObservation& observation);

// Records the UMA related to RTT.
void RecordRTTUMA(int32_t estimated_value_msec,
int32_t actual_value_msec) const;
// Records the UMA related to the RTT at the URLRequest layer.
void RecordURLRequestRTTUMA(int32_t estimated_value_msec,
int32_t actual_value_msec) const;

// Returns true only if |request| can be used for network quality estimation.
// Only the requests that go over network are considered to provide useful
Expand Down
Loading

0 comments on commit c2e2b46

Please sign in to comment.