Chromium Code Reviews| Index: net/nqe/network_quality_estimator_params.cc |
| diff --git a/net/nqe/network_quality_estimator_params.cc b/net/nqe/network_quality_estimator_params.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..5ae29fa7f36a7153db3a887eedf608056f544cab |
| --- /dev/null |
| +++ b/net/nqe/network_quality_estimator_params.cc |
| @@ -0,0 +1,330 @@ |
| +// Copyright 2016 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "net/nqe/network_quality_estimator_params.h" |
| + |
| +#include "base/strings/string_number_conversions.h" |
| +#include "base/time/time.h" |
| + |
| +namespace { |
| + |
| +// Default value of the half life (in seconds) for computing time weighted |
| +// percentiles. Every half life, the weight of all observations reduces by |
| +// half. Lowering the half life would reduce the weight of older values faster. |
| +const int kDefaultHalfLifeSeconds = 60; |
| + |
| +// Name of the variation parameter that holds the value of the half life (in |
| +// seconds) of the observations. |
| +const char kHalfLifeSecondsParamName[] = "HalfLifeSeconds"; |
| + |
| +// Suffix of the name of the variation parameter that contains the default RTT |
| +// observation (in milliseconds). Complete name of the variation parameter |
| +// would be |ConnectionType|.|kDefaultRTTMsecObservationSuffix| where |
| +// |ConnectionType| is from |kConnectionTypeNames|. For example, variation |
| +// parameter for Wi-Fi would be "WiFi.DefaultMedianRTTMsec". |
| +const char kDefaultRTTMsecObservationSuffix[] = ".DefaultMedianRTTMsec"; |
| + |
| +// Suffix of the name of the variation parameter that contains the default |
| +// downstream throughput observation (in Kbps). Complete name of the variation |
| +// parameter would be |ConnectionType|.|kDefaultKbpsObservationSuffix| where |
| +// |ConnectionType| is from |kConnectionTypeNames|. For example, variation |
| +// parameter for Wi-Fi would be "WiFi.DefaultMedianKbps". |
| +const char kDefaultKbpsObservationSuffix[] = ".DefaultMedianKbps"; |
| + |
| +// Suffix of the name of the variation parameter that contains the threshold |
| +// HTTP RTTs (in milliseconds) for different effective connection types. |
| +// Complete name of the variation parameter would be |
| +// |EffectiveConnectionType|.|kThresholdURLRTTMsecSuffix|. |
| +const char kThresholdURLRTTMsecSuffix[] = ".ThresholdMedianHttpRTTMsec"; |
| + |
| +// Suffix of the name of the variation parameter that contains the threshold |
| +// transport RTTs (in milliseconds) for different effective connection types. |
| +// Complete name of the variation parameter would be |
| +// |EffectiveConnectionType|.|kThresholdTransportRTTMsecSuffix|. |
| +const char kThresholdTransportRTTMsecSuffix[] = |
| + ".ThresholdMedianTransportRTTMsec"; |
| + |
| +// Suffix of the name of the variation parameter that contains the threshold |
| +// downlink throughput (in kbps) for different effective connection types. |
| +// Complete name of the variation parameter would be |
| +// |EffectiveConnectionType|.|kThresholdKbpsSuffix|. |
| +const char kThresholdKbpsSuffix[] = ".ThresholdMedianKbps"; |
| + |
| +// Minimum valid value of the variation parameter that holds RTT (in |
| +// milliseconds) values. |
| +static const int kMinimumRTTVariationParameterMsec = 1; |
| + |
| +// Minimum valid value of the variation parameter that holds throughput (in |
| +// kilobits per second) values. |
| +static const int kMinimumThroughputVariationParameterKbps = 1; |
| + |
| +// Sets |variations_value| to the value of |parameter_name| read from |
| +// |variation_params|. If the value is unavailable from |variation_params|, then |
| +// |variations_value| is set to |default_value|. |
| +void GetValueForVariationParam( |
|
RyanSturm
2016/10/18 23:29:04
Return an int64_t instead of void and an out param
tbansal1
2016/10/20 01:02:15
Done.
|
| + const std::map<std::string, std::string>& variation_params, |
| + const std::string& parameter_name, |
| + int64_t default_value, |
| + int64_t* variations_value) { |
| + const auto it = variation_params.find(parameter_name); |
| + if (it != variation_params.end() && |
| + base::StringToInt64(it->second, variations_value)) { |
| + return; |
| + } |
| + *variations_value = default_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; |
|
RyanSturm
2016/10/18 23:29:04
why define this as default_value?
tbansal1
2016/10/20 01:02:15
Done.
RyanSturm
2016/10/20 17:29:59
I guess I was asking why variations_value = defaul
tbansal1
2016/10/20 17:32:14
Windows compiler complains otherwise. Look at the
RyanSturm
2016/10/20 17:40:21
If you're feeling curious, I bet that switching th
|
| + if (!base::StringToDouble(it->second, &variations_value)) |
| + return default_value; |
| + return variations_value; |
| +} |
| + |
| +// Returns the variation value for |parameter_name|. If the value is |
| +// unavailable, |default_value| is returned. |
| +std::string GetStringValueForVariationParamWithDefaultValue( |
| + const std::map<std::string, std::string>& variation_params, |
| + const std::string& parameter_name, |
| + const std::string& default_value) { |
| + const auto it = variation_params.find(parameter_name); |
| + if (it == variation_params.end()) |
| + return default_value; |
| + return it->second; |
| +} |
| + |
| +} // namespace |
| + |
| +namespace net { |
| + |
| +namespace nqe { |
| + |
| +namespace internal { |
| + |
| +std::string GetEffectiveConnectionTypeAlgorithm( |
| + const std::map<std::string, std::string>& variation_params) { |
| + const auto it = variation_params.find("effective_connection_type_algorithm"); |
| + if (it == variation_params.end()) |
| + return std::string(); |
| + return it->second; |
| +} |
| + |
| +double GetWeightMultiplierPerSecond( |
| + const std::map<std::string, std::string>& variation_params) { |
| + static_assert(kDefaultHalfLifeSeconds > 0, |
| + "Default half life duration must be > 0"); |
| + |
| + int half_life_seconds = kDefaultHalfLifeSeconds; |
| + int32_t variations_value = 0; |
| + auto it = variation_params.find(kHalfLifeSecondsParamName); |
| + if (it != variation_params.end() && |
| + base::StringToInt(it->second, &variations_value) && |
| + variations_value >= 1) { |
| + half_life_seconds = variations_value; |
| + } |
| + DCHECK_GT(half_life_seconds, 0); |
| + return exp(log(0.5) / half_life_seconds); |
|
RyanSturm
2016/10/18 23:29:04
nit: I think this would be more readable as pow(.5
tbansal1
2016/10/20 01:02:15
Done.
|
| +} |
| + |
| +const char* GetNameForConnectionType( |
| + net::NetworkChangeNotifier::ConnectionType connection_type) { |
| + switch (connection_type) { |
| + case net::NetworkChangeNotifier::CONNECTION_UNKNOWN: |
| + return "Unknown"; |
| + case net::NetworkChangeNotifier::CONNECTION_ETHERNET: |
| + return "Ethernet"; |
| + case net::NetworkChangeNotifier::CONNECTION_WIFI: |
| + return "WiFi"; |
| + case net::NetworkChangeNotifier::CONNECTION_2G: |
| + return "2G"; |
| + case net::NetworkChangeNotifier::CONNECTION_3G: |
| + return "3G"; |
| + case net::NetworkChangeNotifier::CONNECTION_4G: |
| + return "4G"; |
| + case net::NetworkChangeNotifier::CONNECTION_NONE: |
| + return "None"; |
| + case net::NetworkChangeNotifier::CONNECTION_BLUETOOTH: |
| + return "Bluetooth"; |
| + default: |
| + NOTREACHED(); |
| + break; |
| + } |
| + return ""; |
| +} |
| + |
| +void ObtainDefaultObservations( |
| + const std::map<std::string, std::string>& variation_params, |
| + nqe::internal::NetworkQuality default_observations[]) { |
|
RyanSturm
2016/10/18 23:29:04
I don't think you should pass this as an array, bu
tbansal1
2016/10/20 01:02:15
The size of the array has to always match the numb
RyanSturm
2016/10/20 17:29:59
Acknowledged.
|
| + for (size_t i = 0; i <= NetworkChangeNotifier::CONNECTION_LAST; ++i) { |
| + NetworkChangeNotifier::ConnectionType type = |
| + static_cast<NetworkChangeNotifier::ConnectionType>(i); |
| + DCHECK_EQ(nqe::internal::InvalidRTT(), default_observations[i].http_rtt()); |
| + DCHECK_EQ(nqe::internal::InvalidRTT(), |
| + default_observations[i].transport_rtt()); |
| + DCHECK_EQ(nqe::internal::kInvalidThroughput, |
| + default_observations[i].downstream_throughput_kbps()); |
| + |
| + base::TimeDelta default_rtt = net::nqe::internal::InvalidRTT(); |
| + int32_t variations_value = kMinimumRTTVariationParameterMsec - 1; |
| + std::string parameter_name = std::string(GetNameForConnectionType(type)) |
| + .append(kDefaultRTTMsecObservationSuffix); |
| + auto it = variation_params.find(parameter_name); |
| + |
| + if (it != variation_params.end() && |
| + base::StringToInt(it->second, &variations_value) && |
| + variations_value >= kMinimumRTTVariationParameterMsec) { |
| + default_rtt = base::TimeDelta::FromMilliseconds(variations_value); |
| + } |
| + |
| + int32_t downstream_throughput_kbps = net::nqe::internal::kInvalidThroughput; |
| + variations_value = kMinimumThroughputVariationParameterKbps - 1; |
| + parameter_name = std::string(GetNameForConnectionType(type)) |
| + .append(kDefaultKbpsObservationSuffix); |
| + it = variation_params.find(parameter_name); |
| + |
| + if (it != variation_params.end() && |
| + base::StringToInt(it->second, &variations_value) && |
| + variations_value >= kMinimumThroughputVariationParameterKbps) { |
| + downstream_throughput_kbps = variations_value; |
| + } |
| + |
| + default_observations[i] = nqe::internal::NetworkQuality( |
| + default_rtt, default_observations[i].transport_rtt(), |
| + downstream_throughput_kbps); |
| + } |
| +} |
| + |
| +void ObtainEffectiveConnectionTypeModelParams( |
| + const std::map<std::string, std::string>& variation_params, |
| + nqe::internal::NetworkQuality connection_thresholds[]) { |
|
RyanSturm
2016/10/18 23:29:04
same as comment above.
tbansal1
2016/10/20 01:02:15
See the reply above.
|
| + // First set the default thresholds. |
| + nqe::internal::NetworkQuality default_effective_connection_type_thresholds |
| + [EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_LAST]; |
| + |
| + default_effective_connection_type_thresholds |
| + [EFFECTIVE_CONNECTION_TYPE_SLOW_2G] = nqe::internal::NetworkQuality( |
| + // Set to 2010 milliseconds, which corresponds to the 33rd percentile |
| + // of 2G HTTP RTT observations on Android. |
| + base::TimeDelta::FromMilliseconds(2010), |
| + // Set to 1870 milliseconds, which corresponds to the 33rd percentile |
| + // of 2G transport RTT observations on Android. |
| + base::TimeDelta::FromMilliseconds(1870), |
| + nqe::internal::kInvalidThroughput); |
| + |
| + default_effective_connection_type_thresholds[EFFECTIVE_CONNECTION_TYPE_2G] = |
| + nqe::internal::NetworkQuality( |
| + // Set to 1420 milliseconds, which corresponds to 50th percentile of |
| + // 2G |
| + // HTTP RTT observations on Android. |
| + base::TimeDelta::FromMilliseconds(1420), |
| + // Set to 1280 milliseconds, which corresponds to 50th percentile of |
| + // 2G |
| + // transport RTT observations on Android. |
| + base::TimeDelta::FromMilliseconds(1280), |
| + nqe::internal::kInvalidThroughput); |
| + |
| + default_effective_connection_type_thresholds[EFFECTIVE_CONNECTION_TYPE_3G] = |
| + nqe::internal::NetworkQuality( |
| + // Set to 273 milliseconds, which corresponds to 50th percentile of |
| + // 3G HTTP RTT observations on Android. |
| + base::TimeDelta::FromMilliseconds(273), |
| + // Set to 204 milliseconds, which corresponds to 50th percentile of |
| + // 3G transport RTT observations on Android. |
| + base::TimeDelta::FromMilliseconds(204), |
| + nqe::internal::kInvalidThroughput); |
| + |
| + for (size_t i = 0; i < EFFECTIVE_CONNECTION_TYPE_LAST; ++i) { |
| + EffectiveConnectionType effective_connection_type = |
| + static_cast<EffectiveConnectionType>(i); |
| + DCHECK_EQ(nqe::internal::InvalidRTT(), connection_thresholds[i].http_rtt()); |
| + DCHECK_EQ(nqe::internal::InvalidRTT(), |
| + connection_thresholds[i].transport_rtt()); |
| + DCHECK_EQ(nqe::internal::kInvalidThroughput, |
| + connection_thresholds[i].downstream_throughput_kbps()); |
| + if (effective_connection_type == EFFECTIVE_CONNECTION_TYPE_UNKNOWN) |
| + continue; |
| + |
| + std::string connection_type_name = std::string( |
| + GetNameForEffectiveConnectionType(effective_connection_type)); |
| + |
| + int64_t variations_value; |
| + GetValueForVariationParam(variation_params, |
| + connection_type_name + kThresholdURLRTTMsecSuffix, |
| + default_effective_connection_type_thresholds[i] |
| + .http_rtt() |
| + .InMilliseconds(), |
| + &variations_value); |
| + connection_thresholds[i].set_http_rtt( |
| + base::TimeDelta::FromMilliseconds(variations_value)); |
| + |
| + GetValueForVariationParam( |
| + variation_params, |
| + connection_type_name + kThresholdTransportRTTMsecSuffix, |
| + default_effective_connection_type_thresholds[i] |
| + .transport_rtt() |
| + .InMilliseconds(), |
| + &variations_value); |
| + connection_thresholds[i].set_transport_rtt( |
| + base::TimeDelta::FromMilliseconds(variations_value)); |
| + |
| + GetValueForVariationParam(variation_params, |
| + connection_type_name + kThresholdKbpsSuffix, |
| + default_effective_connection_type_thresholds[i] |
| + .downstream_throughput_kbps(), |
| + &variations_value); |
| + connection_thresholds[i].set_downstream_throughput_kbps(variations_value); |
| + DCHECK(i == 0 || |
| + connection_thresholds[i].IsFaster(connection_thresholds[i - 1])); |
| + } |
| +} |
| + |
| +double correlation_uma_logging_probability( |
| + const std::map<std::string, std::string>& variation_params) { |
| + double correlation_uma_logging_probability = |
| + GetDoubleValueForVariationParamWithDefaultValue( |
| + variation_params, "correlation_logging_probability", 0.0); |
| + DCHECK_LE(0.0, correlation_uma_logging_probability); |
| + DCHECK_GE(1.0, correlation_uma_logging_probability); |
| + return correlation_uma_logging_probability; |
| +} |
| + |
| +bool forced_effective_connection_type_set( |
| + const std::map<std::string, std::string>& variation_params) { |
| + return !GetStringValueForVariationParamWithDefaultValue( |
| + variation_params, "force_effective_connection_type", "") |
| + .empty(); |
| +} |
| + |
| +EffectiveConnectionType forced_effective_connection_type( |
| + const std::map<std::string, std::string>& variation_params) { |
| + EffectiveConnectionType forced_effective_connection_type = |
| + EFFECTIVE_CONNECTION_TYPE_UNKNOWN; |
| + std::string forced_value = GetStringValueForVariationParamWithDefaultValue( |
| + variation_params, "force_effective_connection_type", |
| + GetNameForEffectiveConnectionType(EFFECTIVE_CONNECTION_TYPE_UNKNOWN)); |
| + DCHECK(!forced_value.empty()); |
| + bool effective_connection_type_available = GetEffectiveConnectionTypeForName( |
| + forced_value, &forced_effective_connection_type); |
| + DCHECK(effective_connection_type_available); |
| + |
| + // Silence unused variable warning in release builds. |
| + (void)effective_connection_type_available; |
| + |
| + return forced_effective_connection_type; |
| +} |
| + |
| +} // namespace internal |
| + |
| +} // namespace nqe |
| + |
| +} // namespace net |