Observation(int32_t value,
base::TimeTicks timestamp,
int32_t signal_strength,
NetworkQualityObservationSource source,
const absl::optional<IPHash>& host);
NetworkQuality(const base::TimeDelta& http_rtt,
const base::TimeDelta& transport_rtt,
int32_t downstream_throughput_kbps);
CachedNetworkQuality(base::TimeTicks last_update_time,
const NetworkQuality& network_quality,
EffectiveConnectionType effective_connection_type);
class NetworkQualityStore {
typedef std::map<nqe::internal::NetworkID,
nqe::internal::CachedNetworkQuality> CachedNetworkQualities;
static const size_t kMaximumNetworkQualityCacheSize = 20;
}
default_observations[NetworkChangeNotifier::CONNECTION_WIFI] =
nqe::internal::NetworkQuality(base::Milliseconds(116),
base::Milliseconds(66), 2658);
NetworkID(NetworkChangeNotifier::ConnectionType type,
const std::string& id,
int32_t signal_strength);
enum EffectiveConnectionType {
EFFECTIVE_CONNECTION_TYPE_UNKNOWN = 0,
EFFECTIVE_CONNECTION_TYPE_OFFLINE,
EFFECTIVE_CONNECTION_TYPE_SLOW_2G,
EFFECTIVE_CONNECTION_TYPE_2G,
EFFECTIVE_CONNECTION_TYPE_3G,
EFFECTIVE_CONNECTION_TYPE_4G,
EFFECTIVE_CONNECTION_TYPE_LAST,
};
double GetWeightMultiplierPerSecond(
const std::map<std::string, std::string>& params) {
int half_life_seconds = 60;
return pow(0.5, 1.0 / half_life_seconds);
}
void ObservationBuffer::ComputeWeightedObservations(
const base::TimeTicks& begin_timestamp,
int32_t current_signal_strength,
std::vector<WeightedObservation>* weighted_observations,
double* total_weight) const {
for (const auto& observation : observations_) {
if (observation.timestamp() < begin_timestamp)
continue;
base::TimeDelta time_since_sample_taken = now - observation.timestamp();
double time_weight =
pow(weight_multiplier_per_second_, time_since_sample_taken.InSeconds());
double signal_strength_weight = 1.0;
if (current_signal_strength >= 0 && observation.signal_strength() >= 0) {
int32_t signal_strength_weight_diff =
std::abs(current_signal_strength - observation.signal_strength());
signal_strength_weight =
pow(weight_multiplier_per_signal_level_, signal_strength_weight_diff);
}
double weight = time_weight * signal_strength_weight;
weight = std::clamp(weight, DBL_MIN, 1.0);
weighted_observations->push_back(
WeightedObservation(observation.value(), weight));
total_weight_observations += weight;
}
}
absl::optional<int32_t> ObservationBuffer::GetPercentile(
base::TimeTicks begin_timestamp,
int32_t current_signal_strength,
int percentile,
size_t* observations_count) const {
std::vector<WeightedObservation> weighted_observations;
double total_weight = 0.0;
ComputeWeightedObservations(begin_timestamp, current_signal_strength,
&weighted_observations, &total_weight);
double desired_weight = percentile / 100.0 * total_weight;
double cumulative_weight_seen_so_far = 0.0;
for (const auto& weighted_observation : weighted_observations) {
cumulative_weight_seen_so_far += weighted_observation.weight;
if (cumulative_weight_seen_so_far >= desired_weight)
return weighted_observation.value;
}
}
virtual base::TimeDelta GetRTTEstimateInternal(
base::TimeTicks start_time,
nqe::internal::ObservationCategory observation_category,
int percentile,
size_t* observations_count) const {
return base::Milliseconds(
rtt_ms_observations_[observation_category]
.GetPercentile(start_time, current_network_id_.signal_strength,
percentile, observations_count)
.value_or(nqe::internal::INVALID_RTT_THROUGHPUT));
}
int32_t NetworkQualityEstimator::GetDownlinkThroughputKbpsEstimateInternal(
const base::TimeTicks& start_time,
int percentile) const {
return http_downstream_throughput_kbps_observations_
.GetPercentile(start_time, current_network_id_.signal_strength,
100 - percentile, nullptr)
.value_or(nqe::internal::INVALID_RTT_THROUGHPUT);
}
bool NetworkQualityEstimator::GetRecentRTT(
nqe::internal::ObservationCategory observation_category,
const base::TimeTicks& start_time,
base::TimeDelta* rtt,
size_t* observations_count) const {
*rtt = GetRTTEstimateInternal(start_time, observation_category, 50,
observations_count);
return (*rtt != nqe::internal::InvalidRTT());
}
EffectiveConnectionType
NetworkQualityEstimator::GetRecentEffectiveConnectionTypeUsingMetrics(
base::TimeDelta* http_rtt,
base::TimeDelta* transport_rtt,
base::TimeDelta* end_to_end_rtt,
int32_t* downstream_throughput_kbps,
size_t* transport_rtt_observation_count,
size_t* end_to_end_rtt_observation_count) const {
GetRecentRTT(nqe::internal::OBSERVATION_CATEGORY_HTTP, base::TimeTicks(),
http_rtt, nullptr));
GetRecentRTT(nqe::internal::OBSERVATION_CATEGORY_TRANSPORT,
base::TimeTicks(), transport_rtt,
transport_rtt_observation_count));
iGetRecentRTT(nqe::internal::OBSERVATION_CATEGORY_END_TO_END,
base::TimeTicks(), end_to_end_rtt,
end_to_end_rtt_observation_count));
UpdateHttpRttUsingAllRttValues(http_rtt, *transport_rtt, *end_to_end_rtt);
GetRecentDownlinkThroughputKbps(base::TimeTicks(),
downstream_throughput_kbps));
for (size_t i = 0; i < EFFECTIVE_CONNECTION_TYPE_LAST; ++i) {
EffectiveConnectionType type = static_cast<EffectiveConnectionType>(i);
const bool estimated_http_rtt_is_higher_than_threshold =
*http_rtt >= params_->ConnectionThreshold(type).http_rtt();
if (estimated_http_rtt_is_higher_than_threshold)
return type;
}
}