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 |