Commit 07a33c8c authored by tbansal's avatar tbansal Committed by Commit bot

NQE: Record correlation metric in UMA

The 32-bit metric is recorded as a sparse histogram. Each
sample contains information on transport RTT, HTTP RTT,
bandwidth, and time taken to download the resource. Each
metric occupies 7 bits with first 4 bits left unset.

BUG=624597

Review-Url: https://codereview.chromium.org/2107243003
Cr-Commit-Position: refs/heads/master@{#407072}
parent 6b49e38a
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
#include "base/logging.h" #include "base/logging.h"
#include "base/metrics/histogram.h" #include "base/metrics/histogram.h"
#include "base/metrics/histogram_base.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/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
...@@ -25,9 +27,11 @@ ...@@ -25,9 +27,11 @@
#include "net/base/load_timing_info.h" #include "net/base/load_timing_info.h"
#include "net/base/network_interfaces.h" #include "net/base/network_interfaces.h"
#include "net/base/url_util.h" #include "net/base/url_util.h"
#include "net/http/http_status_code.h"
#include "net/nqe/socket_watcher_factory.h" #include "net/nqe/socket_watcher_factory.h"
#include "net/nqe/throughput_analyzer.h" #include "net/nqe/throughput_analyzer.h"
#include "net/url_request/url_request.h" #include "net/url_request/url_request.h"
#include "net/url_request/url_request_status.h"
#include "url/gurl.h" #include "url/gurl.h"
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
...@@ -149,6 +153,22 @@ bool GetValueForVariationParam( ...@@ -149,6 +153,22 @@ bool GetValueForVariationParam(
base::StringToInt(it->second, variations_value); 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 // Returns the algorithm that should be used for computing effective connection
// type based on field trial params. Returns an empty string if a valid // type based on field trial params. Returns an empty string if a valid
// algorithm paramter is not present in the field trial params. // algorithm paramter is not present in the field trial params.
...@@ -216,6 +236,39 @@ std::string GetHistogramSuffixObservedThroughput( ...@@ -216,6 +236,39 @@ std::string GetHistogramSuffixObservedThroughput(
return kSuffixes[arraysize(kSuffixes) - 1]; return kSuffixes[arraysize(kSuffixes) - 1];
} }
// The least significant kTrimBits of the metric will be discarded. If the
// trimmed metric value is greater than what can be fit in kBitsPerMetric bits,
// then the largest value that can be represented in kBitsPerMetric bits is
// returned.
const int32_t kTrimBits = 5;
// Maximum number of bits in which one metric should fit. Restricting the amount
// of space allocated to a single metric makes it possile to fit multiple
// metrics in a single histogram sample, and ensures that all those metrics
// are recorded together as a single tuple.
const int32_t kBitsPerMetric = 7;
static_assert(32 >= kBitsPerMetric * 4,
"Four metrics would not fit in a 32-bit int");
// Trims the |metric| by removing the last kTrimBits, and then rounding down
// the |metric| such that the |metric| fits in kBitsPerMetric.
int32_t FitInKBitsPerMetricBits(int32_t metric) {
// Remove the last kTrimBits. This will allow the metric to fit within
// kBitsPerMetric while losing only the least significant bits.
metric = metric >> kTrimBits;
// kLargestValuePossible is the largest value that can be recorded using
// kBitsPerMetric.
static const int32_t kLargestValuePossible = (1 << kBitsPerMetric) - 1;
if (metric > kLargestValuePossible) {
// Fit |metric| in kBitsPerMetric by clamping it down.
metric = kLargestValuePossible;
}
DCHECK_EQ(0, metric >> kBitsPerMetric);
return metric;
}
} // namespace } // namespace
namespace net { namespace net {
...@@ -265,6 +318,11 @@ NetworkQualityEstimator::NetworkQualityEstimator( ...@@ -265,6 +318,11 @@ NetworkQualityEstimator::NetworkQualityEstimator(
effective_connection_type_(EFFECTIVE_CONNECTION_TYPE_UNKNOWN), effective_connection_type_(EFFECTIVE_CONNECTION_TYPE_UNKNOWN),
min_signal_strength_since_connection_change_(INT32_MAX), min_signal_strength_since_connection_change_(INT32_MAX),
max_signal_strength_since_connection_change_(INT32_MIN), max_signal_strength_since_connection_change_(INT32_MIN),
correlation_uma_logging_probability_(
GetDoubleValueForVariationParamWithDefaultValue(
variation_params,
"correlation_logging_probability",
0.0)),
weak_ptr_factory_(this) { weak_ptr_factory_(this) {
static_assert(kDefaultHalfLifeSeconds > 0, static_assert(kDefaultHalfLifeSeconds > 0,
"Default half life duration must be > 0"); "Default half life duration must be > 0");
...@@ -284,6 +342,8 @@ NetworkQualityEstimator::NetworkQualityEstimator( ...@@ -284,6 +342,8 @@ NetworkQualityEstimator::NetworkQualityEstimator(
DCHECK_NE(EffectiveConnectionTypeAlgorithm:: DCHECK_NE(EffectiveConnectionTypeAlgorithm::
EFFECTIVE_CONNECTION_TYPE_ALGORITHM_LAST, EFFECTIVE_CONNECTION_TYPE_ALGORITHM_LAST,
effective_connection_type_algorithm_); effective_connection_type_algorithm_);
DCHECK_LE(0.0, correlation_uma_logging_probability_);
DCHECK_GE(1.0, correlation_uma_logging_probability_);
ObtainOperatingParams(variation_params); ObtainOperatingParams(variation_params);
ObtainEffectiveConnectionTypeModelParams(variation_params); ObtainEffectiveConnectionTypeModelParams(variation_params);
...@@ -543,6 +603,7 @@ void NetworkQualityEstimator::NotifyHeadersReceived(const URLRequest& request) { ...@@ -543,6 +603,7 @@ void NetworkQualityEstimator::NotifyHeadersReceived(const URLRequest& request) {
load_timing_info.receive_headers_end.is_null()) { load_timing_info.receive_headers_end.is_null()) {
return; return;
} }
DCHECK(!request.response_info().was_cached);
// Duration between when the resource was requested and when the response // Duration between when the resource was requested and when the response
// headers were received. // headers were received.
...@@ -684,13 +745,105 @@ void NetworkQualityEstimator::NotifyRequestCompleted( ...@@ -684,13 +745,105 @@ void NetworkQualityEstimator::NotifyRequestCompleted(
return; return;
throughput_analyzer_->NotifyRequestCompleted(request); throughput_analyzer_->NotifyRequestCompleted(request);
RecordCorrelationMetric(request);
}
void NetworkQualityEstimator::RecordCorrelationMetric(
const URLRequest& request) const {
DCHECK(thread_checker_.CalledOnValidThread());
// The histogram is recorded with probability
// |correlation_uma_logging_probability_| to reduce overhead involved with
// sparse histograms. Also, recording the correlation on each request is
// unnecessary.
if (RandDouble() >= correlation_uma_logging_probability_)
return;
if (request.response_info().was_cached ||
!request.response_info().network_accessed) {
return;
}
LoadTimingInfo load_timing_info;
request.GetLoadTimingInfo(&load_timing_info);
DCHECK(!load_timing_info.send_start.is_null() &&
!load_timing_info.receive_headers_end.is_null());
// 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;
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))
return;
DCHECK_GE(now, load_timing_info.send_start);
int32_t rtt = 0;
if (UseTransportRTT()) {
rtt = estimated_quality_at_last_main_frame_.transport_rtt() !=
nqe::internal::InvalidRTT()
? FitInKBitsPerMetricBits(
estimated_quality_at_last_main_frame_.transport_rtt()
.InMilliseconds())
: 0;
} else {
rtt = estimated_quality_at_last_main_frame_.http_rtt() !=
nqe::internal::InvalidRTT()
? FitInKBitsPerMetricBits(
estimated_quality_at_last_main_frame_.http_rtt()
.InMilliseconds())
: 0;
}
const int32_t downstream_throughput =
estimated_quality_at_last_main_frame_.downstream_throughput_kbps() !=
nqe::internal::kInvalidThroughput
? FitInKBitsPerMetricBits(estimated_quality_at_last_main_frame_
.downstream_throughput_kbps())
: 0;
const int32_t resource_load_time = FitInKBitsPerMetricBits(
(now - load_timing_info.send_start).InMilliseconds());
int64_t resource_size = (request.GetTotalReceivedBytes() * 8) / 1024;
if (resource_size >= (1 << kBitsPerMetric)) {
// Too large resource size (at least 128 Kb).
return;
}
DCHECK_EQ(
0, (rtt | downstream_throughput | resource_load_time | resource_size) >>
kBitsPerMetric);
// First 32 - (4* kBitsPerMetric) of the sample are unset. Next
// kBitsPerMetric of the sample contain |rtt|. Next
// kBitsPerMetric contain |downstream_throughput|. Next kBitsPerMetric
// contain |resource_load_time|. And, the last kBitsPerMetric
// contain |resource_size|.
int32_t sample = rtt;
sample = (sample << kBitsPerMetric) | downstream_throughput;
sample = (sample << kBitsPerMetric) | resource_load_time;
sample = (sample << kBitsPerMetric) | resource_size;
UMA_HISTOGRAM_SPARSE_SLOWLY("NQE.Correlation.ResourceLoadTime.0Kb_128Kb",
sample);
} }
void NetworkQualityEstimator::NotifyURLRequestDestroyed( void NetworkQualityEstimator::NotifyURLRequestDestroyed(
const URLRequest& request) { const URLRequest& request) {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
NotifyRequestCompleted(request); if (!RequestSchemeIsHTTPOrHTTPS(request))
return;
throughput_analyzer_->NotifyRequestCompleted(request);
} }
void NetworkQualityEstimator::AddRTTObserver(RTTObserver* rtt_observer) { void NetworkQualityEstimator::AddRTTObserver(RTTObserver* rtt_observer) {
...@@ -989,6 +1142,23 @@ NetworkQualityEstimator::GetRecentEffectiveConnectionType( ...@@ -989,6 +1142,23 @@ NetworkQualityEstimator::GetRecentEffectiveConnectionType(
return EFFECTIVE_CONNECTION_TYPE_UNKNOWN; return EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
} }
bool NetworkQualityEstimator::UseTransportRTT() const {
DCHECK(thread_checker_.CalledOnValidThread());
if (effective_connection_type_algorithm_ ==
EffectiveConnectionTypeAlgorithm::HTTP_RTT_AND_DOWNSTREAM_THROUGHOUT) {
return false;
}
if (effective_connection_type_algorithm_ ==
EffectiveConnectionTypeAlgorithm::
TRANSPORT_RTT_OR_DOWNSTREAM_THROUGHOUT) {
return true;
}
// Add additional algorithms here.
NOTREACHED();
return false;
}
NetworkQualityEstimator::EffectiveConnectionType NetworkQualityEstimator::EffectiveConnectionType
NetworkQualityEstimator::GetRecentEffectiveConnectionTypeUsingMetrics( NetworkQualityEstimator::GetRecentEffectiveConnectionTypeUsingMetrics(
const base::TimeTicks& start_time, const base::TimeTicks& start_time,
...@@ -1357,6 +1527,10 @@ void NetworkQualityEstimator::SetTickClockForTesting( ...@@ -1357,6 +1527,10 @@ void NetworkQualityEstimator::SetTickClockForTesting(
tick_clock_ = std::move(tick_clock); tick_clock_ = std::move(tick_clock);
} }
double NetworkQualityEstimator::RandDouble() const {
return base::RandDouble();
}
void NetworkQualityEstimator::CacheNetworkQualityEstimate() { void NetworkQualityEstimator::CacheNetworkQualityEstimate() {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
DCHECK_LE(cached_network_qualities_.size(), DCHECK_LE(cached_network_qualities_.size(),
......
...@@ -349,6 +349,9 @@ class NET_EXPORT NetworkQualityEstimator ...@@ -349,6 +349,9 @@ class NET_EXPORT NetworkQualityEstimator
// Overrides the tick clock used by |this| for testing. // Overrides the tick clock used by |this| for testing.
void SetTickClockForTesting(std::unique_ptr<base::TickClock> tick_clock); void SetTickClockForTesting(std::unique_ptr<base::TickClock> tick_clock);
// Returns a random double in the range [0.0, 1.0). Virtualized for testing.
virtual double RandDouble() const;
private: private:
FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, StoreObservations); FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, StoreObservations);
FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, TestAddObservation); FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, TestAddObservation);
...@@ -543,6 +546,15 @@ class NET_EXPORT NetworkQualityEstimator ...@@ -543,6 +546,15 @@ class NET_EXPORT NetworkQualityEstimator
void RecordExternalEstimateProviderMetrics( void RecordExternalEstimateProviderMetrics(
NQEExternalEstimateProviderStatus status) const; NQEExternalEstimateProviderStatus status) const;
// Records a correlation metric that can be used for computing the correlation
// between HTTP-layer RTT, transport-layer RTT, throughput and the time
// taken to complete |request|.
void RecordCorrelationMetric(const URLRequest& request) const;
// Returns true if transport RTT should be used for computing the effective
// connection type.
bool UseTransportRTT() const;
// Determines if the requests to local host can be used in estimating the // Determines if the requests to local host can be used in estimating the
// network quality. Set to true only for tests. // network quality. Set to true only for tests.
bool use_localhost_requests_; bool use_localhost_requests_;
...@@ -651,6 +663,13 @@ class NET_EXPORT NetworkQualityEstimator ...@@ -651,6 +663,13 @@ class NET_EXPORT NetworkQualityEstimator
int32_t min_signal_strength_since_connection_change_; int32_t min_signal_strength_since_connection_change_;
int32_t max_signal_strength_since_connection_change_; int32_t max_signal_strength_since_connection_change_;
// It is costlier to add values to a sparse histogram. So, the correlation UMA
// is recorded with |correlation_uma_logging_probability_| since recording it
// in a sparse histogram for each request is unnecessary and cost-prohibitive.
// e.g., if it is 0.0, then the UMA will never be recorded. On the other hand,
// if it is 1.0, then it will be recorded for all valid HTTP requests.
const double correlation_uma_logging_probability_;
base::ThreadChecker thread_checker_; base::ThreadChecker thread_checker_;
base::WeakPtrFactory<NetworkQualityEstimator> weak_ptr_factory_; base::WeakPtrFactory<NetworkQualityEstimator> weak_ptr_factory_;
......
...@@ -77,7 +77,8 @@ class TestNetworkQualityEstimator : public NetworkQualityEstimator { ...@@ -77,7 +77,8 @@ class TestNetworkQualityEstimator : public NetworkQualityEstimator {
transport_rtt_set_(false), transport_rtt_set_(false),
recent_transport_rtt_set_(false), recent_transport_rtt_set_(false),
downlink_throughput_kbps_set_(false), downlink_throughput_kbps_set_(false),
recent_downlink_throughput_kbps_set_(false) { recent_downlink_throughput_kbps_set_(false),
rand_double_(0.0) {
// Set up embedded test server. // Set up embedded test server.
embedded_test_server_.ServeFilesFromDirectory( embedded_test_server_.ServeFilesFromDirectory(
base::FilePath(FILE_PATH_LITERAL("net/data/url_request_unittest"))); base::FilePath(FILE_PATH_LITERAL("net/data/url_request_unittest")));
...@@ -263,6 +264,10 @@ class TestNetworkQualityEstimator : public NetworkQualityEstimator { ...@@ -263,6 +264,10 @@ class TestNetworkQualityEstimator : public NetworkQualityEstimator {
return NetworkQualityEstimator::GetAccuracyRecordingIntervals(); return NetworkQualityEstimator::GetAccuracyRecordingIntervals();
} }
void set_rand_double(double rand_double) { rand_double_ = rand_double; }
double RandDouble() const override { return rand_double_; }
using NetworkQualityEstimator::SetTickClockForTesting; using NetworkQualityEstimator::SetTickClockForTesting;
using NetworkQualityEstimator::ReadCachedNetworkQualityEstimate; using NetworkQualityEstimator::ReadCachedNetworkQualityEstimate;
using NetworkQualityEstimator::OnConnectionTypeChanged; using NetworkQualityEstimator::OnConnectionTypeChanged;
...@@ -306,6 +311,8 @@ class TestNetworkQualityEstimator : public NetworkQualityEstimator { ...@@ -306,6 +311,8 @@ class TestNetworkQualityEstimator : public NetworkQualityEstimator {
bool recent_downlink_throughput_kbps_set_; bool recent_downlink_throughput_kbps_set_;
int32_t recent_downlink_throughput_kbps_; int32_t recent_downlink_throughput_kbps_;
double rand_double_;
// Embedded server used for testing. // Embedded server used for testing.
EmbeddedTestServer embedded_test_server_; EmbeddedTestServer embedded_test_server_;
...@@ -1984,4 +1991,142 @@ TEST(NetworkQualityEstimatorTest, TestRecordNetworkIDAvailability) { ...@@ -1984,4 +1991,142 @@ TEST(NetworkQualityEstimatorTest, TestRecordNetworkIDAvailability) {
histogram_tester.ExpectTotalCount("NQE.NetworkIdAvailable", 4); histogram_tester.ExpectTotalCount("NQE.NetworkIdAvailable", 4);
} }
// Tests that the correlation histogram is recorded correctly based on
// correlation logging probability set in the variation params.
TEST(NetworkQualityEstimatorTest, CorrelationHistogram) {
// Match the values set in network_quality_estimator.cc.
static const int32_t kTrimBits = 5;
static const int32_t kBitsPerMetric = 7;
const struct {
bool use_transport_rtt;
double rand_double;
double correlation_logging_probability;
base::TimeDelta transport_rtt;
int32_t expected_transport_rtt_milliseconds;
base::TimeDelta http_rtt;
int32_t expected_http_rtt_milliseconds;
int32_t downstream_throughput_kbps;
int32_t expected_downstream_throughput_kbps;
} tests[] = {
{
// Verify that the metric is not recorded if the logging probability
// is set to 0.0.
false, 0.5, 0.0, base::TimeDelta::FromSeconds(1), 1000 >> kTrimBits,
base::TimeDelta::FromSeconds(2), 2000 >> kTrimBits, 3000,
3000 >> kTrimBits,
},
{
// Verify that the metric is not recorded if the logging probability
// is lower than the value returned by the random number generator.
false, 0.3, 0.1, base::TimeDelta::FromSeconds(1), 1000 >> kTrimBits,
base::TimeDelta::FromSeconds(2), 2000 >> kTrimBits, 3000,
3000 >> kTrimBits,
},
{
// Verify that the metric is recorded if the logging probability is
// higher than the value returned by the random number generator.
false, 0.3, 0.4, base::TimeDelta::FromSeconds(1), 1000 >> kTrimBits,
base::TimeDelta::FromSeconds(2), 2000 >> kTrimBits, 3000,
3000 >> kTrimBits,
},
{
// Verify that the metric is recorded if the logging probability is
// set to 1.0.
false, 0.5, 1.0, base::TimeDelta::FromSeconds(1), 1000 >> kTrimBits,
base::TimeDelta::FromSeconds(2), 2000 >> kTrimBits, 3000,
3000 >> kTrimBits,
},
{
// Verify that the metric is recorded if the logging probability is
// set to 1.0.
true, 0.5, 1.0, base::TimeDelta::FromSeconds(1), 1000 >> kTrimBits,
base::TimeDelta::FromSeconds(2), 2000 >> kTrimBits, 3000,
3000 >> kTrimBits,
},
{
// Verify that if the metric is larger than
// 2^(kBitsPerMetric + kTrimBits), it is rounded down to
// (2^(kBitsPerMetric + kTrimBits) - 1) >> kTrimBits.
false, 0.5, 1.0, base::TimeDelta::FromSeconds(10), 4095 >> kTrimBits,
base::TimeDelta::FromSeconds(20), 4095 >> kTrimBits, 30000,
4095 >> kTrimBits,
},
};
for (const auto& test : tests) {
base::HistogramTester histogram_tester;
std::map<std::string, std::string> variation_params;
variation_params["correlation_logging_probability"] =
base::DoubleToString(test.correlation_logging_probability);
if (test.use_transport_rtt) {
variation_params["effective_connection_type_algorithm"] =
"TransportRTTOrDownstreamThroughput";
}
TestNetworkQualityEstimator estimator(variation_params);
estimator.set_transport_rtt(test.transport_rtt);
estimator.set_recent_transport_rtt(test.transport_rtt);
estimator.set_http_rtt(test.http_rtt);
estimator.set_recent_http_rtt(test.http_rtt);
estimator.set_downlink_throughput_kbps(test.downstream_throughput_kbps);
estimator.set_rand_double(test.rand_double);
TestDelegate test_delegate;
TestURLRequestContext context(true);
context.set_network_quality_estimator(&estimator);
context.Init();
// Start a main-frame request that should cause network quality estimator to
// record the network quality at the last main frame request.
std::unique_ptr<URLRequest> request_1(context.CreateRequest(
estimator.GetEchoURL(), DEFAULT_PRIORITY, &test_delegate));
request_1->SetLoadFlags(request_1->load_flags() | LOAD_MAIN_FRAME);
request_1->Start();
base::RunLoop().Run();
histogram_tester.ExpectTotalCount(
"NQE.Correlation.ResourceLoadTime.0Kb_128Kb", 0);
// Start another main-frame request which should cause network quality
// estimator to record the correlation UMA.
std::unique_ptr<URLRequest> request_2(context.CreateRequest(
estimator.GetEchoURL(), DEFAULT_PRIORITY, &test_delegate));
request_2->Start();
base::RunLoop().Run();
if (test.rand_double >= test.correlation_logging_probability) {
histogram_tester.ExpectTotalCount(
"NQE.Correlation.ResourceLoadTime.0Kb_128Kb", 0);
continue;
}
histogram_tester.ExpectTotalCount(
"NQE.Correlation.ResourceLoadTime.0Kb_128Kb", 1);
std::vector<base::Bucket> buckets = histogram_tester.GetAllSamples(
"NQE.Correlation.ResourceLoadTime.0Kb_128Kb");
// Get the bits at index 0-10 which contain the RTT.
// 128 is 2^kBitsPerMetric.
if (test.use_transport_rtt) {
EXPECT_EQ(test.expected_transport_rtt_milliseconds,
buckets.at(0).min >> kBitsPerMetric >> kBitsPerMetric >>
kBitsPerMetric);
} else {
EXPECT_EQ(test.expected_http_rtt_milliseconds,
buckets.at(0).min >> kBitsPerMetric >> kBitsPerMetric >>
kBitsPerMetric);
}
// Get the bits at index 11-17 which contain the downstream throughput.
EXPECT_EQ(test.expected_downstream_throughput_kbps,
(buckets.at(0).min >> kBitsPerMetric >> kBitsPerMetric) % 128);
// Get the bits at index 18-24 which contain the resource fetch time.
EXPECT_LE(0, (buckets.at(0).min >> kBitsPerMetric) % 128);
// Get the bits at index 25-31 which contain the resource load size.
EXPECT_LE(0, (buckets.at(0).min) % 128);
}
}
} // namespace net } // namespace net
...@@ -35766,6 +35766,20 @@ http://cs/file:chrome/histograms.xml - but prefer this file for new entries. ...@@ -35766,6 +35766,20 @@ http://cs/file:chrome/histograms.xml - but prefer this file for new entries.
</summary> </summary>
</histogram> </histogram>
<histogram name="NQE.Correlation.ResourceLoadTime.0Kb_128Kb">
<owner>tbansal@chromium.org</owner>
<owner>bengr@chromium.org</owner>
<summary>
Records estimated network quality (estimated RTT, estimated downlink
bandwidth), resource load size, and the resource load time in a single UMA
sample. This metric is recorded randomly when a resource load finishes. Each
sample in this sparse histogram consists of multiple metrics (each occupying
few bits in the sample). The data in the histogram would be analyzed using
custom scripts. A sample is recorded only when the resource size is between
0 Kilobits (inclusive) and 128 Kilobits (exclusive).
</summary>
</histogram>
<histogram name="NQE.DifferenceRTTActualAndEstimated" units="ms"> <histogram name="NQE.DifferenceRTTActualAndEstimated" units="ms">
<obsolete> <obsolete>
Replaced in June 2016 by NQE.Accuracy.HttpRTT.* metrics. Replaced in June 2016 by NQE.Accuracy.HttpRTT.* metrics.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment