Index: net/nqe/network_quality_estimator.cc |
diff --git a/net/nqe/network_quality_estimator.cc b/net/nqe/network_quality_estimator.cc |
index 256722a179b707ab1a3c37adc65e94bbe6b36e32..1d3642aa9ea64bd95e6abd9798b42c4a2ffa81c9 100644 |
--- a/net/nqe/network_quality_estimator.cc |
+++ b/net/nqe/network_quality_estimator.cc |
@@ -15,6 +15,8 @@ |
#include "base/logging.h" |
#include "base/metrics/histogram.h" |
#include "base/metrics/histogram_base.h" |
+#include "base/metrics/sparse_histogram.h" |
+#include "base/rand_util.h" |
#include "base/single_thread_task_runner.h" |
#include "base/strings/string_number_conversions.h" |
#include "base/threading/thread_task_runner_handle.h" |
@@ -25,9 +27,11 @@ |
#include "net/base/load_timing_info.h" |
#include "net/base/network_interfaces.h" |
#include "net/base/url_util.h" |
+#include "net/http/http_status_code.h" |
#include "net/nqe/socket_watcher_factory.h" |
#include "net/nqe/throughput_analyzer.h" |
#include "net/url_request/url_request.h" |
+#include "net/url_request/url_request_status.h" |
#include "url/gurl.h" |
#if defined(OS_ANDROID) |
@@ -141,6 +145,22 @@ bool GetValueForVariationParam( |
base::StringToInt(it->second, variations_value); |
} |
+// Returns the variation value for |parameter_name|. If the value is |
+// unavailable, |default_value| is returned. |
+double GetDoubleValueForVariationParamWithDefaultValue( |
+ const std::map<std::string, std::string>& variation_params, |
+ const std::string& parameter_name, |
+ double default_value) { |
+ const auto it = variation_params.find(parameter_name); |
+ if (it == variation_params.end()) |
+ return default_value; |
+ |
+ double variations_value = default_value; |
+ if (!base::StringToDouble(it->second, &variations_value)) |
+ return default_value; |
+ return variations_value; |
+} |
+ |
// Returns the algorithm that should be used for computing effective connection |
// type based on field trial params. Returns an empty string if a valid |
// algorithm paramter is not present in the field trial params. |
@@ -188,6 +208,27 @@ std::string GetHistogramSuffixObservedRTT(const base::TimeDelta& observed_rtt) { |
return kSuffixes[arraysize(kSuffixes) - 1]; |
} |
+// The least significant kTrimBits of the metric will be discarded. Next, it |
+// will be rounded down so it fits within kBitsPerMetric bits. This implies |
+// that if the metric's value is more than 2^(kTrimBits + kBitsPerMetric), |
+// then it will be rounded down. |
Not at Google. Contact bengr
2016/06/30 17:49:44
This is confusing. Can you please rephrase it. How
tbansal1
2016/07/01 00:16:00
Done.
|
+const int32_t kTrimBits = 5; |
+const int32_t kBitsPerMetric = 7; |
Not at Google. Contact bengr
2016/06/30 17:49:44
Add:
static_assert(31 > kBitsPerMetric * 4, "4 met
tbansal1
2016/07/01 00:16:00
Done.
|
+ |
+// Trims the |metric| by removing the last kTrimBits, and then rounding down |
+// the |metric| such that the |metric| fits in kBitsPerMetric. |
+int32_t TrimAndRoundDown(int32_t metric) { |
Not at Google. Contact bengr
2016/06/30 17:49:44
Rename method to FitInKBitsPerMetricBits?
tbansal1
2016/07/01 00:16:00
Done.
|
+ // Remove the last kTrimBits. This will allow the metric to fit within |
+ // kBitsPerMetric while losing only the least significant bits. |
+ metric = metric >> kTrimBits; |
+ if (metric >= (1 << kBitsPerMetric)) { |
+ // Fit |metric| in kBitsPerMetric by rounding it down. |
+ metric = (1 << kBitsPerMetric) - 1; |
Not at Google. Contact bengr
2016/06/30 17:49:44
Possible Refactor:
int32_t largest_value_using_kBi
tbansal1
2016/07/01 00:16:01
Done.
|
+ } |
+ DCHECK_EQ(0, metric >> kBitsPerMetric); |
+ return metric; |
+} |
+ |
} // namespace |
namespace net { |
@@ -230,6 +271,11 @@ NetworkQualityEstimator::NetworkQualityEstimator( |
rtt_observations_(weight_multiplier_per_second_), |
external_estimate_provider_(std::move(external_estimates_provider)), |
effective_connection_type_(EFFECTIVE_CONNECTION_TYPE_UNKNOWN), |
+ correlation_logging_probability_( |
+ GetDoubleValueForVariationParamWithDefaultValue( |
+ variation_params, |
+ "correlation_logging_probability", |
+ 0.0)), |
weak_ptr_factory_(this) { |
static_assert(kDefaultHalfLifeSeconds > 0, |
"Default half life duration must be > 0"); |
@@ -249,6 +295,8 @@ NetworkQualityEstimator::NetworkQualityEstimator( |
DCHECK_NE(EffectiveConnectionTypeAlgorithm:: |
EFFECTIVE_CONNECTION_TYPE_ALGORITHM_LAST, |
effective_connection_type_algorithm_); |
+ DCHECK_LE(0.0, correlation_logging_probability_); |
+ DCHECK_GE(1.0, correlation_logging_probability_); |
ObtainOperatingParams(variation_params); |
ObtainEffectiveConnectionTypeModelParams(variation_params); |
@@ -490,6 +538,7 @@ void NetworkQualityEstimator::NotifyHeadersReceived(const URLRequest& request) { |
load_timing_info.receive_headers_end.is_null()) { |
return; |
} |
+ DCHECK(!request.response_info().was_cached); |
// Duration between when the resource was requested and when the response |
// headers were received. |
@@ -584,6 +633,84 @@ void NetworkQualityEstimator::NotifyRequestCompleted( |
return; |
throughput_analyzer_->NotifyRequestCompleted(request); |
+ RecordCorrelationMetric(request); |
+} |
+ |
+void NetworkQualityEstimator::RecordCorrelationMetric( |
+ const URLRequest& request) const { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ // The histogram is recorded with probability |
+ // |correlation_logging_probability_| to reduce overhead. |
+ if (base::RandDouble() >= correlation_logging_probability_) |
Not at Google. Contact bengr
2016/06/30 17:49:44
Shouldn't this be base::RandDouble() <= correlatio
tbansal1
2016/07/01 00:16:00
No. Say correlation_logging_probability_ is 1.0. T
Not at Google. Contact bengr
2016/07/01 18:26:26
Misread as condition to execute below. You are rig
|
+ return; |
+ |
+ if (request.response_info().was_cached) |
+ return; |
+ LoadTimingInfo load_timing_info; |
+ request.GetLoadTimingInfo(&load_timing_info); |
+ |
+ // If the load timing info is unavailable, it probably means that the request |
+ // did not go over the network. |
Not at Google. Contact bengr
2016/06/30 17:49:44
Could this be replaced with request->response_info
tbansal1
2016/07/01 00:16:01
Done.
|
+ if (load_timing_info.send_start.is_null() || |
+ load_timing_info.receive_headers_end.is_null()) { |
+ return; |
+ } |
+ |
+ // Record UMA only for successful requests that have completed. |
+ if (!request.status().is_success() || request.status().is_io_pending()) |
+ return; |
+ if (request.GetResponseCode() != HTTP_OK) |
+ return; |
+ if (load_timing_info.receive_headers_end < last_main_frame_request_) |
+ return; |
Not at Google. Contact bengr
2016/06/30 17:49:44
Nit: Add new line.
tbansal1
2016/07/01 00:16:00
Done.
|
+ const base::TimeTicks now = tick_clock_->NowTicks(); |
+ // Record UMA only for requests that started recently. |
+ if (now - last_main_frame_request_ > base::TimeDelta::FromSeconds(15)) |
Not at Google. Contact bengr
2016/06/30 17:49:44
Why ignore older requests?
tbansal1
2016/07/01 00:16:00
It is possible that network quality was recorded a
Not at Google. Contact bengr
2016/07/01 18:26:26
Acknowledged.
|
+ return; |
+ |
+ DCHECK_GE(now, load_timing_info.send_start); |
Not at Google. Contact bengr
2016/06/30 17:49:44
Not sure this is necessary.
tbansal1
2016/07/01 00:16:01
It checks that we are not adding negative values t
Not at Google. Contact bengr
2016/07/01 18:26:26
Acknowledged.
|
+ |
+ // Histogram samples are 32-bit in size with first bit reserved for sign. |
+ // Four metrics will be recorded per sample. |
+ DCHECK_GE(31, kBitsPerMetric * 4); |
Not at Google. Contact bengr
2016/06/30 17:49:44
Prefer replacing with static assert above where kB
tbansal1
2016/07/01 00:16:01
Done.
|
+ |
+ const int32_t transport_rtt_milliseconds = |
Not at Google. Contact bengr
2016/06/30 17:49:44
Does it help to extract estimated_quality_at_last_
tbansal1
2016/07/01 00:16:00
I am not sure. I wanted to declare it as a const v
|
+ estimated_quality_at_last_main_frame_.transport_rtt() != |
+ nqe::internal::InvalidRTT() |
+ ? TrimAndRoundDown( |
+ estimated_quality_at_last_main_frame_.transport_rtt() |
+ .InMilliseconds()) |
+ : 0; |
+ |
+ const int32_t http_rtt_milliseconds = |
+ estimated_quality_at_last_main_frame_.http_rtt() != |
+ nqe::internal::InvalidRTT() |
+ ? TrimAndRoundDown(estimated_quality_at_last_main_frame_.http_rtt() |
+ .InMilliseconds()) |
+ : 0; |
+ |
+ const int32_t downstream_throughput_kbps = |
+ estimated_quality_at_last_main_frame_.downstream_throughput_kbps() != |
+ nqe::internal::kInvalidThroughput |
+ ? TrimAndRoundDown(estimated_quality_at_last_main_frame_ |
+ .downstream_throughput_kbps()) |
+ : 0; |
+ |
+ const int32_t resource_load_time_milliseconds = |
+ TrimAndRoundDown((now - load_timing_info.send_start).InMilliseconds()); |
+ |
+ // First 32 - (4* kBitsPerMetric) of the sample are unset. Next |
+ // kBitsPerMetric of the sample contain |transport_rtt_milliseconds|. |
+ // Next kBitsPerMetric contain |http_rtt_milliseconds|. Next kBitsPerMetric |
+ // contain |downstream_throughput_kbps|. And, the last kBitsPerMetric |
+ // contain |resource_load_time_milliseconds|. |
+ int32_t sample = transport_rtt_milliseconds; |
Not at Google. Contact bengr
2016/06/30 17:49:44
Suggest adding DCHECK_EQ(0, transport_rtt_millisec
tbansal1
2016/07/01 00:16:00
Done.
|
+ sample = (sample << kBitsPerMetric) + http_rtt_milliseconds; |
Not at Google. Contact bengr
2016/06/30 17:49:44
Minor: | seems prefereable to +.
tbansal1
2016/07/01 00:16:00
Done.
|
+ sample = (sample << kBitsPerMetric) + downstream_throughput_kbps; |
+ sample = (sample << kBitsPerMetric) + resource_load_time_milliseconds; |
+ |
+ UMA_HISTOGRAM_SPARSE_SLOWLY("NQE.Correlation.ResourceLoadTime", sample); |
} |
void NetworkQualityEstimator::NotifyURLRequestDestroyed( |