Chromium Code Reviews| Index: components/data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats.cc |
| diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..0ba22234b90db5aaefa2098703f24254f24807ac |
| --- /dev/null |
| +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats.cc |
| @@ -0,0 +1,287 @@ |
| +// Copyright 2015 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 "components/data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats.h" |
| + |
| +#include "base/logging.h" |
| +#include "base/metrics/field_trial.h" |
| +#include "base/metrics/histogram_macros.h" |
| +#include "base/prefs/pref_service.h" |
| +#include "base/strings/string_number_conversions.h" |
| +#include "base/strings/string_piece.h" |
| +#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h" |
| +#include "components/variations/variations_associated_data.h" |
| +#include "net/url_request/url_request.h" |
| + |
| +namespace { |
| + |
| +// The trial group prefix for which an experiment is considered enabled. |
| +const char kEnabled[] = "Enabled"; |
| + |
| +// The number of config fetch variations supported. Must match the number of |
| +// suffixes in histograms.xml. |
| +const int kConfigFetchGroups = 10; |
| + |
| +// The minimum interval (in seconds) at which the config retrieval can occur. |
| +const int kConfigFetchMinimumIntervalSeconds = 300; |
| + |
| +// The default latency base for retrieving the config. |
| +const int kConfigFetchDefaultRoundtripMillisecondsBase = 100; |
| + |
| +// The default latency base for retrieving the config. |
| +const double kConfigFetchDefaultRoundtripMultiplier = 1.0; |
| + |
| +// The default latency base for retrieving the config. |
| +const int kConfigFetchDefaultRoundtripMillisecondsIncrement = 100; |
| + |
| +// The simulated default expiration for retrieving the config. |
| +const int kConfigFetchDefaultExpirationSeconds = 24 * 60 * 60; |
| + |
| +base::HistogramBase* GetHistogramWithSuffix(const char* histogram, int suffix) { |
| + std::string full_histogram_name = histogram + base::IntToString(suffix); |
| + return base::Histogram::FactoryGet( |
| + full_histogram_name, 1, 1000000, 50, |
| + base::HistogramBase::kUmaTargetedHistogramFlag); |
| +} |
| + |
| +} // namespace |
| + |
| +namespace data_reduction_proxy { |
| + |
| +namespace experiments { |
| + |
| +const char kConfigFetchTrialGroup[] = "DataReductionProxyConfigFetchBytes"; |
| + |
| +const char kConfigRoundtripMillisecondsBaseParam[] = |
| + "config_roundtrip_milliseconds_base"; |
| + |
| +const char kConfigRoundtripMultiplierParam[] = "config_roundtrip_multiplier"; |
| + |
| +const char kConfigRoundtripMillisecondsIncrementParam[] = |
| + "config_roundtrip_milliseconds_increment"; |
| + |
| +const char kConfigExpirationSecondsParam[] = "config_expiration_seconds"; |
| + |
| +const char kConfigAlwaysStaleParam[] = "always_stale"; |
| + |
| +const int kConfigFetchBufferSeconds = 300; |
| + |
| +} // namespace experiments |
| + |
| +// static |
| +scoped_ptr<DataReductionProxyExperimentsStats::ConfigRetrievalParams> |
| +DataReductionProxyExperimentsStats::ConfigRetrievalParams::Create( |
| + PrefService* pref_service) { |
| + base::StringPiece group = |
| + base::FieldTrialList::FindFullName(experiments::kConfigFetchTrialGroup); |
| + if (!group.starts_with(kEnabled)) |
| + return scoped_ptr< |
| + DataReductionProxyExperimentsStats::ConfigRetrievalParams>(); |
| + |
| + std::string config_always_stale_value = |
| + variations::GetVariationParamValue(experiments::kConfigFetchTrialGroup, |
| + experiments::kConfigAlwaysStaleParam); |
| + int config_always_stale; |
| + int64 config_update_time; |
| + if (!config_always_stale_value.empty() && |
| + base::StringToInt(config_always_stale_value, &config_always_stale) && |
| + config_always_stale == 1) { |
| + config_update_time = 0; |
| + } else { |
| + config_update_time = |
| + pref_service->GetInt64(prefs::kSimulatedConfigExpireTime); |
| + } |
| + |
| + std::string config_expiration_seconds_value = |
| + variations::GetVariationParamValue( |
| + experiments::kConfigFetchTrialGroup, |
| + experiments::kConfigExpirationSecondsParam); |
| + int64 config_expiration_interval_seconds; |
| + if (config_expiration_seconds_value.empty() || |
| + !base::StringToInt64(config_expiration_seconds_value, |
| + &config_expiration_interval_seconds)) |
| + config_expiration_interval_seconds = kConfigFetchDefaultExpirationSeconds; |
| + base::TimeDelta config_expiration_interval = |
| + base::TimeDelta::FromSeconds(config_expiration_interval_seconds); |
| + |
| + std::vector<Variation> variations; |
| + base::Time now = base::Time::Now(); |
| + base::Time config_expiration = |
| + base::Time::FromInternalValue(config_update_time); |
| + if (now > config_expiration) { |
|
sclittle
2015/05/12 19:32:25
Could some of this be pulled out into helper funct
jeremyim
2015/05/12 20:38:29
Done.
|
| + config_expiration = now + config_expiration_interval; |
| + std::string roundtrip_milliseconds_base = |
| + variations::GetVariationParamValue( |
| + experiments::kConfigFetchTrialGroup, |
| + experiments::kConfigRoundtripMillisecondsBaseParam); |
| + int64 config_roundtrip_milliseconds; |
| + if (roundtrip_milliseconds_base.empty() || |
| + !base::StringToInt64(roundtrip_milliseconds_base, |
| + &config_roundtrip_milliseconds) || |
| + config_roundtrip_milliseconds < 0) |
| + config_roundtrip_milliseconds = |
| + kConfigFetchDefaultRoundtripMillisecondsBase; |
| + std::string roundtrip_multiplier_value; |
| + double config_roundtrip_multiplier; |
| + if (roundtrip_multiplier_value.empty() || |
|
sclittle
2015/05/12 19:32:25
|roundtrip_multiplier_value| doesn't appear to be
jeremyim
2015/05/12 20:38:29
Done.
|
| + !base::StringToDouble(roundtrip_multiplier_value, |
| + &config_roundtrip_multiplier) || |
| + config_roundtrip_multiplier < 1.0) { |
| + config_roundtrip_multiplier = kConfigFetchDefaultRoundtripMultiplier; |
| + } |
| + std::string roundtrip_milliseconds_increment_value; |
|
sclittle
2015/05/12 19:32:25
Same here, this variable doesn't get assigned anyw
jeremyim
2015/05/12 20:38:29
Done.
|
| + int64 roundtrip_milliseconds_increment; |
| + if (roundtrip_milliseconds_increment_value.empty() || |
| + !base::StringToInt64(roundtrip_milliseconds_increment_value, |
| + &roundtrip_milliseconds_increment) || |
| + roundtrip_milliseconds_increment < 0) { |
| + roundtrip_milliseconds_increment = |
| + kConfigFetchDefaultRoundtripMillisecondsIncrement; |
| + } |
| + |
| + int params_index = 0; |
| + do { |
| + base::Time config_retrieved = now + base::TimeDelta::FromMilliseconds( |
| + config_roundtrip_milliseconds); |
| + variations.push_back(Variation(params_index, config_retrieved)); |
| + config_roundtrip_milliseconds *= config_roundtrip_multiplier; |
| + config_roundtrip_milliseconds += roundtrip_milliseconds_increment; |
| + } while (++params_index < kConfigFetchGroups); |
|
sclittle
2015/05/12 19:32:25
Could this be done as a for loop instead for clari
jeremyim
2015/05/12 20:38:29
Done.
|
| + } |
| + |
| + return scoped_ptr<DataReductionProxyExperimentsStats::ConfigRetrievalParams>( |
| + new DataReductionProxyExperimentsStats::ConfigRetrievalParams( |
| + variations, config_expiration, config_expiration_interval)); |
| +} |
| + |
| +DataReductionProxyExperimentsStats::ConfigRetrievalParams::Variation::Variation( |
| + int index, |
| + const base::Time& simulated_config_retrieved) |
| + : simulated_config_retrieved_(simulated_config_retrieved) { |
| + lost_bytes_ocl_ = GetHistogramWithSuffix( |
| + "DataReductionProxy.ConfigFetchLostBytesOCL_", index); |
| + lost_bytes_rcl_ = GetHistogramWithSuffix( |
| + "DataReductionProxy.ConfigFetchLostBytesCL_", index); |
| + lost_bytes_diff_ = GetHistogramWithSuffix( |
| + "DataReductionProxy.ConfigFetchLostBytesDiff_", index); |
| +} |
| + |
| +DataReductionProxyExperimentsStats::ConfigState |
| +DataReductionProxyExperimentsStats::ConfigRetrievalParams::Variation::GetState( |
| + const base::Time& request_time, |
| + const base::Time& config_expiration) const { |
| + if (!simulated_config_retrieved_.is_null() && |
| + request_time < simulated_config_retrieved_) { |
| + return DataReductionProxyExperimentsStats::RETRIEVING; |
| + } else if (request_time < config_expiration) { |
| + return DataReductionProxyExperimentsStats::VALID; |
| + } |
| + |
| + return DataReductionProxyExperimentsStats::EXPIRED; |
| +} |
| + |
| +void DataReductionProxyExperimentsStats::ConfigRetrievalParams::Variation:: |
| + RecordStats(int64 received_content_length, |
| + int64 original_content_length) const { |
| + lost_bytes_rcl_->Add(received_content_length); |
| + lost_bytes_ocl_->Add(original_content_length); |
| + lost_bytes_diff_->Add(original_content_length - received_content_length); |
| +} |
| + |
| +DataReductionProxyExperimentsStats::ConfigRetrievalParams:: |
| + ConfigRetrievalParams(const std::vector<Variation>& variations, |
| + const base::Time& config_expiration, |
| + const base::TimeDelta& config_expiration_interval) |
| + : config_expiration_(config_expiration), |
| + config_expiration_interval_(config_expiration_interval), |
| + variations_(variations) { |
| + config_refresh_interval_ = |
| + config_expiration_interval_ - |
| + base::TimeDelta::FromSeconds(experiments::kConfigFetchBufferSeconds); |
| + if (config_refresh_interval_.InSeconds() < |
| + kConfigFetchMinimumIntervalSeconds) { |
| + config_refresh_interval_ = |
| + base::TimeDelta::FromSeconds(kConfigFetchMinimumIntervalSeconds); |
| + } |
| +} |
| + |
| +DataReductionProxyExperimentsStats::ConfigRetrievalParams:: |
| + ~ConfigRetrievalParams() { |
| +} |
| + |
| +void DataReductionProxyExperimentsStats::ConfigRetrievalParams::RecordStats( |
| + const base::Time& request_time, |
| + int64 received_content_length, |
| + int64 original_content_length) const { |
| + for (const auto& variation : variations_) { |
| + switch (variation.GetState(request_time, config_expiration_)) { |
| + case VALID: |
| + break; |
| + case RETRIEVING: |
| + case EXPIRED: |
| + variation.RecordStats(received_content_length, original_content_length); |
| + break; |
| + default: |
| + NOTREACHED(); |
| + } |
| + } |
| +} |
| + |
| +void DataReductionProxyExperimentsStats::ConfigRetrievalParams:: |
| + RefreshConfig() { |
| + config_expiration_ = base::Time::Now() + config_expiration_interval_; |
| +} |
| + |
| +DataReductionProxyExperimentsStats::DataReductionProxyExperimentsStats( |
| + Int64ValueSetter value_setter) |
| + : value_setter_(value_setter) { |
| + // Constructed on the UI thread, but should be checked on the IO thread. |
| + thread_checker_.DetachFromThread(); |
| +} |
| + |
| +DataReductionProxyExperimentsStats::~DataReductionProxyExperimentsStats() { |
| +} |
| + |
| +void DataReductionProxyExperimentsStats::InitializeOnUIThread( |
| + scoped_ptr<ConfigRetrievalParams> config_retrieval_params) { |
| + config_retrieval_params_ = config_retrieval_params.Pass(); |
| + |
| + // This method may be called from the UI thread, but should be checked on the |
| + // IO thread. |
| + thread_checker_.DetachFromThread(); |
| +} |
| + |
| +void DataReductionProxyExperimentsStats::InitializeOnIOThread() { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + if (config_retrieval_params_) { |
| + config_refresh_time_.Start( |
| + FROM_HERE, config_retrieval_params_->refresh_interval(), this, |
| + &DataReductionProxyExperimentsStats::UpdateSimulatedConfig); |
| + } |
| +} |
| + |
| +void DataReductionProxyExperimentsStats::RecordBytes( |
| + const base::Time& request_time, |
| + DataReductionProxyRequestType request_type, |
| + int64 received_content_length, |
| + int64 original_content_length) { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + if (config_retrieval_params_) { |
| + // Only measure requests which flowed through the Data Reduction Proxy. |
| + if (request_type == VIA_DATA_REDUCTION_PROXY) { |
| + config_retrieval_params_->RecordStats( |
| + request_time, received_content_length, original_content_length); |
| + } |
| + } |
| +} |
| + |
| +void DataReductionProxyExperimentsStats::UpdateSimulatedConfig() { |
| + if (config_retrieval_params_) { |
| + value_setter_.Run( |
| + prefs::kSimulatedConfigExpireTime, |
| + config_retrieval_params_->config_expiration().ToInternalValue()); |
| + } |
| +} |
| + |
| +} // namespace data_reduction_proxy |