summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjoi@chromium.org <joi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-05-05 02:22:11 +0000
committerjoi@chromium.org <joi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-05-05 02:22:11 +0000
commit780702c2aac603a5ca09c22e34d3f913a375627d (patch)
tree9eec20da47f64859a072a8ca2ca03823953e5d52
parent8dc0234a8d2cec8bb1979ec8dec05bf23a79a42a (diff)
downloadchromium_src-780702c2aac603a5ca09c22e34d3f913a375627d.zip
chromium_src-780702c2aac603a5ca09c22e34d3f913a375627d.tar.gz
chromium_src-780702c2aac603a5ca09c22e34d3f913a375627d.tar.bz2
Add one-time randomization support for FieldTrial, and the ability to
disable field trials. I am going to have a need for both soon. Cleaning up some comments about empty trial names, adding static method TrialExists() and simplifying many call sites by using this method. While I'm in there and needing base/OWNERS approval, add an OWNERS file for base/metrics that adds jar@chromium.org as an owner for that directory. BUG=none TEST=base_unittests TBR=jam@chromium.org git-svn-id: svn://svn.chromium.org/chrome/trunk/src@84197 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--base/metrics/OWNERS1
-rw-r--r--base/metrics/field_trial.cc98
-rw-r--r--base/metrics/field_trial.h115
-rw-r--r--base/metrics/field_trial_unittest.cc125
-rw-r--r--base/rand_util.cc6
-rw-r--r--base/rand_util.h4
-rw-r--r--chrome/browser/browser_main.cc141
-rw-r--r--chrome/browser/browser_main.h26
-rw-r--r--chrome/browser/metrics/metrics_service.cc4
-rw-r--r--chrome/browser/metrics/metrics_service.h4
-rw-r--r--chrome/renderer/page_load_histograms.cc49
-rw-r--r--chrome/renderer/prerender/prerender_helper.cc3
-rw-r--r--content/renderer/renderer_main.cc6
-rw-r--r--net/base/host_resolver_impl.cc10
-rw-r--r--net/http/http_cache_transaction.cc3
-rw-r--r--net/http/http_network_transaction.cc9
-rw-r--r--net/socket/client_socket_pool_histograms.cc8
-rw-r--r--net/socket/ssl_client_socket_pool.cc5
-rw-r--r--net/socket/stream_socket.cc5
-rw-r--r--net/url_request/url_request_http_job.cc3
20 files changed, 453 insertions, 172 deletions
diff --git a/base/metrics/OWNERS b/base/metrics/OWNERS
new file mode 100644
index 0000000..844a032
--- /dev/null
+++ b/base/metrics/OWNERS
@@ -0,0 +1 @@
+jar@chromium.org
diff --git a/base/metrics/field_trial.cc b/base/metrics/field_trial.cc
index 03e5809..b86b9cc 100644
--- a/base/metrics/field_trial.cc
+++ b/base/metrics/field_trial.cc
@@ -6,6 +6,8 @@
#include "base/logging.h"
#include "base/rand_util.h"
+#include "base/sha1.h"
+#include "base/string_util.h"
#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
@@ -41,11 +43,13 @@ FieldTrial::FieldTrial(const std::string& name,
: name_(name),
divisor_(total_probability),
default_group_name_(default_group_name),
- random_(static_cast<Probability>(divisor_ * base::RandDouble())),
+ random_(static_cast<Probability>(divisor_ * RandDouble())),
accumulated_group_probability_(0),
- next_group_number_(kDefaultGroupNumber+1),
- group_(kNotFinalized) {
+ next_group_number_(kDefaultGroupNumber + 1),
+ group_(kNotFinalized),
+ enable_field_trial_(true) {
DCHECK_GT(total_probability, 0);
+ DCHECK(!name_.empty());
DCHECK(!default_group_name_.empty());
FieldTrialList::Register(this);
@@ -55,7 +59,7 @@ FieldTrial::FieldTrial(const std::string& name,
DCHECK_GT(day_of_month, 0);
DCHECK_LT(day_of_month, 32);
- base::Time::Exploded exploded;
+ Time::Exploded exploded;
exploded.year = year;
exploded.month = month;
exploded.day_of_week = 0; // Should be unused.
@@ -65,8 +69,33 @@ FieldTrial::FieldTrial(const std::string& name,
exploded.second = 0;
exploded.millisecond = 0;
- base::Time expiration_time = Time::FromLocalExploded(exploded);
- disable_field_trial_ = (GetBuildTime() > expiration_time) ? true : false;
+ Time expiration_time = Time::FromLocalExploded(exploded);
+ if (GetBuildTime() > expiration_time)
+ Disable();
+}
+
+void FieldTrial::UseOneTimeRandomization() {
+ DCHECK_EQ(group_, kNotFinalized);
+ DCHECK_EQ(kDefaultGroupNumber + 1, next_group_number_);
+ if (!FieldTrialList::IsOneTimeRandomizationEnabled()) {
+ NOTREACHED();
+ Disable();
+ return;
+ }
+
+ random_ = static_cast<Probability>(
+ divisor_ * HashClientId(FieldTrialList::client_id(), name_));
+}
+
+void FieldTrial::Disable() {
+ enable_field_trial_ = false;
+
+ // In case we are disabled after initialization, we need to switch
+ // the trial to the default group.
+ if (group_ != kNotFinalized) {
+ group_ = kDefaultGroupNumber;
+ group_name_ = default_group_name_;
+ }
}
int FieldTrial::AppendGroup(const std::string& name,
@@ -74,7 +103,7 @@ int FieldTrial::AppendGroup(const std::string& name,
DCHECK_LE(group_probability, divisor_);
DCHECK_GE(group_probability, 0);
- if (enable_benchmarking_ || disable_field_trial_)
+ if (enable_benchmarking_ || !enable_field_trial_)
group_probability = 0;
accumulated_group_probability_ += group_probability;
@@ -84,7 +113,7 @@ int FieldTrial::AppendGroup(const std::string& name,
// This is the group that crossed the random line, so we do the assignment.
group_ = next_group_number_;
if (name.empty())
- base::StringAppendF(&group_name_, "%d", group_);
+ StringAppendF(&group_name_, "%d", group_);
else
group_name_ = name;
FieldTrialList::NotifyFieldTrialGroupSelection(name_, group_name_);
@@ -103,7 +132,8 @@ int FieldTrial::group() {
}
std::string FieldTrial::group_name() {
- group(); // call group() to make group assignment was done.
+ group(); // call group() to make sure group assignment was done.
+ DCHECK(!group_name_.empty());
return group_name_;
}
@@ -133,6 +163,25 @@ Time FieldTrial::GetBuildTime() {
return integral_build_time;
}
+// static
+double FieldTrial::HashClientId(const std::string& client_id,
+ const std::string& trial_name) {
+ // SHA-1 is designed to produce a uniformly random spread in its output space,
+ // even for nearly-identical inputs, so it helps massage whatever client_id
+ // and trial_name we get into something with a uniform distribution, which
+ // is desirable so that we don't skew any part of the 0-100% spectrum.
+ std::string input(client_id + trial_name);
+ unsigned char sha1_hash[SHA1_LENGTH];
+ SHA1HashBytes(reinterpret_cast<const unsigned char*>(input.c_str()),
+ input.size(),
+ sha1_hash);
+
+ COMPILE_ASSERT(sizeof(uint64) < sizeof(sha1_hash), need_more_data);
+ uint64* bits = reinterpret_cast<uint64*>(&sha1_hash[0]);
+
+ return BitsToOpenEndedUnitInterval(*bits);
+}
+
//------------------------------------------------------------------------------
// FieldTrialList methods and members.
@@ -142,8 +191,9 @@ FieldTrialList* FieldTrialList::global_ = NULL;
// static
bool FieldTrialList::register_without_global_ = false;
-FieldTrialList::FieldTrialList()
+FieldTrialList::FieldTrialList(const std::string& client_id)
: application_start_time_(TimeTicks::Now()),
+ client_id_(client_id),
observer_list_(ObserverList<Observer>::NOTIFY_EXISTING_ONLY) {
DCHECK(!global_);
DCHECK(!register_without_global_);
@@ -204,19 +254,23 @@ std::string FieldTrialList::FindFullName(const std::string& name) {
}
// static
+bool FieldTrialList::TrialExists(const std::string& name) {
+ return Find(name) != NULL;
+}
+
+// static
void FieldTrialList::StatesToString(std::string* output) {
if (!global_)
return;
DCHECK(output->empty());
AutoLock auto_lock(global_->lock_);
+
for (RegistrationList::iterator it = global_->registered_.begin();
it != global_->registered_.end(); ++it) {
const std::string name = it->first;
std::string group_name = it->second->group_name_internal();
if (group_name.empty())
- // No definitive winner in this trial, use default_group_name as the
- // group_name.
- group_name = it->second->default_group_name();
+ continue; // Should not include uninitialized trials.
DCHECK_EQ(name.find(kPersistentStringSeparator), std::string::npos);
DCHECK_EQ(group_name.find(kPersistentStringSeparator), std::string::npos);
output->append(name);
@@ -313,6 +367,24 @@ size_t FieldTrialList::GetFieldTrialCount() {
return global_->registered_.size();
}
+// static
+bool FieldTrialList::IsOneTimeRandomizationEnabled() {
+ DCHECK(global_);
+ if (!global_)
+ return false;
+
+ return !global_->client_id_.empty();
+}
+
+// static
+const std::string& FieldTrialList::client_id() {
+ DCHECK(global_);
+ if (!global_)
+ return EmptyString();
+
+ return global_->client_id_;
+}
+
FieldTrial* FieldTrialList::PreLockedFind(const std::string& name) {
RegistrationList::iterator it = registered_.find(name);
if (registered_.end() == it)
diff --git a/base/metrics/field_trial.h b/base/metrics/field_trial.h
index b8ab0c5..4e89ccf 100644
--- a/base/metrics/field_trial.h
+++ b/base/metrics/field_trial.h
@@ -13,12 +13,13 @@
// pseudo-randomly selected).
//
// States are typically generated randomly, either based on a one time
-// randomization (generated randomly once, and then persistently reused in the
-// client during each future run of the program), or by a startup randomization
-// (generated each time the application starts up, but held constant during the
-// duration of the process), or by continuous randomization across a run (where
-// the state can be recalculated again and again, many times during a process).
-// Only startup randomization is implemented thus far.
+// randomization (which will yield the same results, in terms of selecting
+// the client for a field trial or not, for every run of the program on a
+// given machine), or by a startup randomization (generated each time the
+// application starts up, but held constant during the duration of the
+// process), or by continuous randomization across a run (where the state
+// can be recalculated again and again, many times during a process).
+// Continuous randomization is not yet implemented.
//------------------------------------------------------------------------------
// Example: Suppose we have an experiment involving memory, such as determining
@@ -52,10 +53,9 @@
// to randomly be assigned:
// HISTOGRAM_COUNTS("Memory.RendererTotal", count); // The original histogram.
-// static bool use_memoryexperiment_histogram(
-// base::FieldTrialList::Find("MemoryExperiment") &&
-// !base::FieldTrialList::Find("MemoryExperiment")->group_name().empty());
-// if (use_memoryexperiment_histogram) {
+// static const bool memory_renderer_total_trial_exists =
+// FieldTrialList::TrialExists("Memory.RendererTotal");
+// if (memory_renderer_total_trial_exists) {
// HISTOGRAM_COUNTS(FieldTrial::MakeName("Memory.RendererTotal",
// "MemoryExperiment"), count);
// }
@@ -103,15 +103,35 @@ class BASE_API FieldTrial : public RefCounted<FieldTrial> {
// The name is used to register the instance with the FieldTrialList class,
// and can be used to find the trial (only one trial can be present for each
- // name).
+ // name). |name| and |default_group_name| may not be empty.
+ //
// Group probabilities that are later supplied must sum to less than or equal
// to the total_probability. Arguments year, month and day_of_month specify
// the expiration time. If the build time is after the expiration time then
// the field trial reverts to the 'default' group.
+ //
+ // Using this constructor creates a startup-randomized FieldTrial. If you
+ // want a one-time randomized trial, call UseOneTimeRandomization() right
+ // after construction.
FieldTrial(const std::string& name, Probability total_probability,
const std::string& default_group_name, const int year,
const int month, const int day_of_month);
+ // Changes the field trial to use one-time randomization, i.e. produce the
+ // same result for the current trial on every run of this client. Must be
+ // called right after construction.
+ //
+ // Before using this method, |FieldTrialList::EnableOneTimeRandomization()|
+ // must be called exactly once.
+ void UseOneTimeRandomization();
+
+ // Disables this trial, meaning it always determines the default group
+ // has been selected. May be called immediately after construction, or
+ // at any time after initialization (should not be interleaved with
+ // AppendGroup calls). Once disabled, there is no way to re-enable a
+ // trial.
+ void Disable();
+
// Establish the name and probability of the next group in this trial.
// Sometimes, based on construction randomization, this call may cause the
// provided group to be *THE* group selected for use in this instance.
@@ -124,18 +144,17 @@ class BASE_API FieldTrial : public RefCounted<FieldTrial> {
// Return the randomly selected group number that was assigned.
// Return kDefaultGroupNumber if the instance is in the 'default' group.
// Note that this will force an instance to participate, and make it illegal
- // to attempt to probabalistically add any other groups to the trial.
+ // to attempt to probabilistically add any other groups to the trial.
int group();
- // If the field trial is not in an experiment, this returns the empty string.
- // if the group's name is empty, a name of "_" concatenated with the group
+ // If the group's name is empty, a string version containing the group
// number is used as the group name.
std::string group_name();
// Return the default group name of the FieldTrial.
std::string default_group_name() const { return default_group_name_; }
- // Helper function for the most common use: as an argument to specifiy the
+ // Helper function for the most common use: as an argument to specify the
// name of a HISTOGRAM. Use the original histogram name as the name_prefix.
static std::string MakeName(const std::string& name_prefix,
const std::string& trial_name);
@@ -155,6 +174,9 @@ class BASE_API FieldTrial : public RefCounted<FieldTrial> {
FRIEND_TEST(FieldTrialTest, Save);
FRIEND_TEST(FieldTrialTest, DuplicateRestore);
FRIEND_TEST(FieldTrialTest, MakeName);
+ FRIEND_TEST(FieldTrialTest, HashClientId);
+ FRIEND_TEST(FieldTrialTest, HashClientIdIsUniform);
+ FRIEND_TEST(FieldTrialTest, UseOneTimeRandomization);
friend class base::FieldTrialList;
@@ -168,8 +190,13 @@ class BASE_API FieldTrial : public RefCounted<FieldTrial> {
// Get build time.
static Time GetBuildTime();
+ // Calculates a uniformly-distributed double between [0.0, 1.0) given
+ // a |client_id| and a |trial_name| (the latter is used as salt to avoid
+ // separate one-time randomized trials from all having the same results).
+ static double HashClientId(const std::string& client_id,
+ const std::string& trial_name);
+
// The name of the field trial, as can be found via the FieldTrialList.
- // This is empty of the trial is not in the experiment.
const std::string name_;
// The maximum sum of all probabilities supplied, which corresponds to 100%.
@@ -182,7 +209,7 @@ class BASE_API FieldTrial : public RefCounted<FieldTrial> {
// The randomly selected probability that is used to select a group (or have
// the instance not participate). It is the product of divisor_ and a random
// number between [0, 1).
- const Probability random_;
+ Probability random_;
// Sum of the probabilities of all appended groups.
Probability accumulated_group_probability_;
@@ -193,13 +220,13 @@ class BASE_API FieldTrial : public RefCounted<FieldTrial> {
// This is kNotFinalized if no group has been assigned.
int group_;
- // A textual name for the randomly selected group. If this Trial is not a
- // member of an group, this string is empty.
+ // A textual name for the randomly selected group. Valid after |group()|
+ // has been called.
std::string group_name_;
- // When disable_field_trial_ is true, field trial reverts to the 'default'
+ // When enable_field_trial_ is false, field trial reverts to the 'default'
// group.
- bool disable_field_trial_;
+ bool enable_field_trial_;
// When benchmarking is enabled, field trials all revert to the 'default'
// group.
@@ -234,7 +261,12 @@ class BASE_API FieldTrialList {
};
// This singleton holds the global list of registered FieldTrials.
- FieldTrialList();
+ //
+ // |client_id| should be an opaque, diverse ID for this client that does not
+ // change between sessions, to enable one-time randomized trials. The empty
+ // string may be provided, in which case one-time randomized trials will
+ // not be available.
+ explicit FieldTrialList(const std::string& client_id);
// Destructor Release()'s references to all registered FieldTrial instances.
~FieldTrialList();
@@ -246,15 +278,22 @@ class BASE_API FieldTrialList {
// registered, or to retrieve a pointer to it from the global map.
static FieldTrial* Find(const std::string& name);
+ // Returns the group number chosen for the named trial, or
+ // FieldTrial::kNotFinalized if the trial does not exist.
static int FindValue(const std::string& name);
+ // Returns the group name chosen for the named trial, or the
+ // empty string if the trial does not exist.
static std::string FindFullName(const std::string& name);
- // Create a persistent representation of all FieldTrial instances for
- // resurrection in another process. This allows randomization to be done in
- // one process, and secondary processes can by synchronized on the result.
- // The resulting string contains only the names, the trial name, and a "/"
- // separator.
+ // Returns true if the named trial has been registered.
+ static bool TrialExists(const std::string& name);
+
+ // Create a persistent representation of all FieldTrial instances and the
+ // |client_id()| state for resurrection in another process. This allows
+ // randomization to be done in one process, and secondary processes can by
+ // synchronized on the result. The resulting string contains the
+ // |client_id()|, the names, the trial name, and a "/" separator.
static void StatesToString(std::string* output);
// Use a previously generated state string (re: StatesToString()) augment the
@@ -263,7 +302,9 @@ class BASE_API FieldTrialList {
// is commonly used in a non-browser process, to carry randomly selected state
// in a browser process into this non-browser process. This method calls
// CreateFieldTrial to create the FieldTrial in the non-browser process.
- // Currently only the group_name_ and name_ are restored.
+ // Currently only the group_name_ and name_ are restored, as well as the
+ // |client_id()| state, that could be used for one-time randomized trials
+ // set up only in child processes.
static bool CreateTrialsInChildProcess(const std::string& prior_trials);
// Create a FieldTrial with the given |name| and using 100% probability for
@@ -303,6 +344,17 @@ class BASE_API FieldTrialList {
// Return the number of active field trials.
static size_t GetFieldTrialCount();
+ // Returns true if you can call |FieldTrial::UseOneTimeRandomization()|
+ // without error, i.e. if a non-empty string was provided as the client_id
+ // when constructing the FieldTrialList singleton.
+ static bool IsOneTimeRandomizationEnabled();
+
+ // Returns an opaque, diverse ID for this client that does not change
+ // between sessions.
+ //
+ // Returns the empty string if one-time randomization is not enabled.
+ static const std::string& client_id();
+
private:
// A map from FieldTrial names to the actual instances.
typedef std::map<std::string, FieldTrial*> RegistrationList;
@@ -317,7 +369,7 @@ class BASE_API FieldTrialList {
// is created after that.
static bool register_without_global_;
- // A helper value made availabel to users, that shows when the FieldTrialList
+ // A helper value made available to users, that shows when the FieldTrialList
// was initialized. Note that this is a singleton instance, and hence is a
// good approximation to the start of the process.
TimeTicks application_start_time_;
@@ -326,6 +378,10 @@ class BASE_API FieldTrialList {
base::Lock lock_;
RegistrationList registered_;
+ // An opaque, diverse ID for this client that does not change
+ // between sessions, or the empty string if not initialized.
+ std::string client_id_;
+
// List of observers to be notified when a group is selected for a FieldTrial.
ObserverList<Observer> observer_list_;
@@ -335,4 +391,3 @@ class BASE_API FieldTrialList {
} // namespace base
#endif // BASE_METRICS_FIELD_TRIAL_H_
-
diff --git a/base/metrics/field_trial_unittest.cc b/base/metrics/field_trial_unittest.cc
index 3357085..a790add 100644
--- a/base/metrics/field_trial_unittest.cc
+++ b/base/metrics/field_trial_unittest.cc
@@ -6,14 +6,18 @@
#include "base/metrics/field_trial.h"
+#include "base/rand_util.h"
#include "base/stringprintf.h"
+#include "base/string_number_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include <limits>
+
namespace base {
class FieldTrialTest : public testing::Test {
public:
- FieldTrialTest() : trial_list_() {
+ FieldTrialTest() : trial_list_("client_id") {
Time now = Time::NowFromSystemTime();
TimeDelta oneYear = TimeDelta::FromDays(365);
Time::Exploded exploded;
@@ -224,9 +228,10 @@ TEST_F(FieldTrialTest, Save) {
new FieldTrial(
"Some name", 10, "Default some name", next_year_, 12, 31);
// There is no winner yet, so no textual group name is associated with trial.
+ // In this case, the trial should not be included.
EXPECT_EQ("", trial->group_name_internal());
FieldTrialList::StatesToString(&save_string);
- EXPECT_EQ("Some name/Default some name/", save_string);
+ EXPECT_EQ("", save_string);
save_string.clear();
// Create a winning group.
@@ -265,10 +270,10 @@ TEST_F(FieldTrialTest, Restore) {
TEST_F(FieldTrialTest, BogusRestore) {
EXPECT_FALSE(FieldTrialList::CreateTrialsInChildProcess("MissingSlash"));
EXPECT_FALSE(FieldTrialList::CreateTrialsInChildProcess("MissingGroupName/"));
- EXPECT_FALSE(
- FieldTrialList::CreateTrialsInChildProcess("MissingFinalSlash/gname"));
- EXPECT_FALSE(
- FieldTrialList::CreateTrialsInChildProcess("/noname, only group/"));
+ EXPECT_FALSE(FieldTrialList::CreateTrialsInChildProcess(
+ "MissingFinalSlash/gname"));
+ EXPECT_FALSE(FieldTrialList::CreateTrialsInChildProcess(
+ "noname, only group/"));
}
TEST_F(FieldTrialTest, DuplicateRestore) {
@@ -284,7 +289,8 @@ TEST_F(FieldTrialTest, DuplicateRestore) {
EXPECT_TRUE(FieldTrialList::CreateTrialsInChildProcess(save_string));
// But it is an error to try to change to a different winner.
- EXPECT_FALSE(FieldTrialList::CreateTrialsInChildProcess("Some name/Loser/"));
+ EXPECT_FALSE(FieldTrialList::CreateTrialsInChildProcess(
+ "Some name/Loser/"));
}
TEST_F(FieldTrialTest, CreateFieldTrial) {
@@ -321,4 +327,109 @@ TEST_F(FieldTrialTest, MakeName) {
FieldTrial::MakeName("Histogram", "Field Trial"));
}
+TEST_F(FieldTrialTest, HashClientId) {
+ double results[] = {
+ FieldTrial::HashClientId("hi", "1"),
+ FieldTrial::HashClientId("there", "1"),
+ };
+ ASSERT_NE(results[0], results[1]);
+ for (size_t i = 0; i < arraysize(results); ++i) {
+ ASSERT_LE(0.0, results[i]);
+ ASSERT_GT(1.0, results[i]);
+ }
+
+ ASSERT_EQ(FieldTrial::HashClientId("yo", "1"),
+ FieldTrial::HashClientId("yo", "1"));
+ ASSERT_NE(FieldTrial::HashClientId("yo", "something"),
+ FieldTrial::HashClientId("yo", "else"));
+}
+
+TEST_F(FieldTrialTest, HashClientIdIsUniform) {
+ // Choose a random start number but go sequentially from there, so
+ // that each test tries a different range but we never provide uniformly
+ // distributed input data.
+ int current_number = RandInt(0, std::numeric_limits<int>::max());
+
+ // The expected value of a random distribution is the average over all
+ // samples as the number of samples approaches infinity. For a uniform
+ // distribution from [0.0, 1.0) this would be 0.5.
+ //
+ // We do kSamplesBetweenChecks at a time and check if the value has converged
+ // to a narrow interval around 0.5. A non-uniform distribution would likely
+ // converge at something different, or not converge consistently within this
+ // range (i.e. the test would start timing out occasionally).
+ int kSamplesBetweenChecks = 300;
+ int num_samples = 0;
+ double total_value = 0.0;
+ while (true) {
+ for (int i = 0; i < kSamplesBetweenChecks; ++i) {
+ total_value += FieldTrial::HashClientId(
+ IntToString(current_number++), "salt");
+ num_samples++;
+ }
+
+ double average = total_value / num_samples;
+ double kExpectedMin = 0.48;
+ double kExpectedMax = 0.52;
+
+ if (num_samples > 1000 &&
+ (average < kExpectedMin || average > kExpectedMax)) {
+ // Only printed once we have enough samples that it's very unlikely
+ // things haven't converged.
+ printf("After %d samples, the average was %f, outside the expected\n"
+ "range (%f, %f). We will add more samples and check after every\n"
+ "%d samples. If the average does not converge, something\n"
+ "is broken. If it does converge, the test will pass.\n",
+ num_samples, average,
+ kExpectedMin, kExpectedMax, kSamplesBetweenChecks);
+ } else {
+ // Success.
+ break;
+ }
+ }
+}
+
+TEST_F(FieldTrialTest, UseOneTimeRandomization) {
+ // Simply asserts that two trials using one-time randomization
+ // that have different names, normally generate different results.
+ //
+ // Note that depending on the one-time random initialization, they
+ // _might_ actually give the same result, but we know that given
+ // the particular client_id we use for unit tests they won't.
+ scoped_refptr<FieldTrial> trials[] = {
+ new FieldTrial("one", 100, "default", next_year_, 1, 1),
+ new FieldTrial("two", 100, "default", next_year_, 1, 1),
+ };
+
+ for (size_t i = 0; i < arraysize(trials); ++i) {
+ trials[i]->UseOneTimeRandomization();
+
+ for (int j = 0; j < 100; ++j) {
+ trials[i]->AppendGroup("", 1);
+ }
+ }
+
+ // The trials are most likely to give different results since they have
+ // different names.
+ ASSERT_NE(trials[0]->group(), trials[1]->group());
+ ASSERT_NE(trials[0]->group_name(), trials[1]->group_name());
+}
+
+TEST_F(FieldTrialTest, DisableImmediately) {
+ FieldTrial* trial =
+ new FieldTrial("trial", 100, "default", next_year_, 12, 31);
+ trial->Disable();
+ ASSERT_EQ("default", trial->group_name());
+ ASSERT_EQ(FieldTrial::kDefaultGroupNumber, trial->group());
+}
+
+TEST_F(FieldTrialTest, DisableAfterInitialization) {
+ FieldTrial* trial =
+ new FieldTrial("trial", 100, "default", next_year_, 12, 31);
+ trial->AppendGroup("non_default", 100);
+ ASSERT_EQ("non_default", trial->group_name());
+ trial->Disable();
+ ASSERT_EQ("default", trial->group_name());
+}
+
} // namespace base
diff --git a/base/rand_util.cc b/base/rand_util.cc
index a71bb0c..b823fa0 100644
--- a/base/rand_util.cc
+++ b/base/rand_util.cc
@@ -24,6 +24,10 @@ int RandInt(int min, int max) {
}
double RandDouble() {
+ return BitsToOpenEndedUnitInterval(base::RandUint64());
+}
+
+double BitsToOpenEndedUnitInterval(uint64 bits) {
// We try to get maximum precision by masking out as many bits as will fit
// in the target type's mantissa, and raising it to an appropriate power to
// produce output in the range [0, 1). For IEEE 754 doubles, the mantissa
@@ -31,7 +35,7 @@ double RandDouble() {
COMPILE_ASSERT(std::numeric_limits<double>::radix == 2, otherwise_use_scalbn);
static const int kBits = std::numeric_limits<double>::digits;
- uint64 random_bits = base::RandUint64() & ((GG_UINT64_C(1) << kBits) - 1);
+ uint64 random_bits = bits & ((GG_UINT64_C(1) << kBits) - 1);
double result = ldexp(static_cast<double>(random_bits), -1 * kBits);
DCHECK_GE(result, 0.0);
DCHECK_LT(result, 1.0);
diff --git a/base/rand_util.h b/base/rand_util.h
index 4e902da..d10cc8b 100644
--- a/base/rand_util.h
+++ b/base/rand_util.h
@@ -29,6 +29,10 @@ BASE_API uint64 RandGenerator(uint64 max);
// Returns a random double in range [0, 1). Thread-safe.
BASE_API double RandDouble();
+// Given input |bits|, convert with maximum precision to a double in
+// the range [0, 1). Thread-safe.
+BASE_API double BitsToOpenEndedUnitInterval(uint64 bits);
+
// Returns a random string of the specified length.
BASE_API std::string RandBytesAsString(size_t length);
diff --git a/chrome/browser/browser_main.cc b/chrome/browser/browser_main.cc
index 8b28a2c..6224df9 100644
--- a/chrome/browser/browser_main.cc
+++ b/chrome/browser/browser_main.cc
@@ -243,16 +243,28 @@ void BrowserMainParts::EarlyInitialization() {
}
// This will be called after the command-line has been mutated by about:flags
-void BrowserMainParts::SetupFieldTrials() {
- // Note: make sure to call ConnectionFieldTrial() before
- // ProxyConnectionsFieldTrial().
- ConnectionFieldTrial();
- SocketTimeoutFieldTrial();
- ProxyConnectionsFieldTrial();
- prerender::ConfigurePrefetchAndPrerender(parsed_command_line());
- SpdyFieldTrial();
- ConnectBackupJobsFieldTrial();
- SSLFalseStartFieldTrial();
+MetricsService* BrowserMainParts::SetupMetricsAndFieldTrials(
+ const CommandLine& parsed_command_line,
+ PrefService* local_state) {
+ // Must initialize metrics after labs have been converted into switches,
+ // but before field trials are set up (so that client ID is available for
+ // one-time randomized field trials).
+ MetricsService* metrics = InitializeMetrics(parsed_command_line, local_state);
+
+ // Initialize FieldTrialList to support FieldTrials that use one-time
+ // randomization. The client ID will be empty if the user has not opted
+ // to send metrics.
+ field_trial_list_.reset(new base::FieldTrialList(metrics->GetClientId()));
+
+ SetupFieldTrials();
+
+ // Initialize FieldTrialSynchronizer system. This is a singleton and is used
+ // for posting tasks via NewRunnableMethod. Its deleted when it goes out of
+ // scope. Even though NewRunnableMethod does AddRef and Release, the object
+ // will not be deleted after the Task is executed.
+ field_trial_synchronizer_ = new FieldTrialSynchronizer();
+
+ return metrics;
}
// This is an A/B test for the maximum number of persistent connections per
@@ -535,6 +547,61 @@ void BrowserMainParts::InitializeMainThread() {
MessageLoop::current()));
}
+// BrowserMainParts: |SetupMetricsAndFieldTrials()| related --------------------
+
+// Initializes the metrics service with the configuration for this process,
+// returning the created service (guaranteed non-NULL).
+MetricsService* BrowserMainParts::InitializeMetrics(
+ const CommandLine& parsed_command_line,
+ const PrefService* local_state) {
+#if defined(OS_WIN)
+ if (parsed_command_line.HasSwitch(switches::kChromeFrame))
+ MetricsLog::set_version_extension("-F");
+#elif defined(ARCH_CPU_64_BITS)
+ MetricsLog::set_version_extension("-64");
+#endif // defined(OS_WIN)
+
+ MetricsService* metrics = g_browser_process->metrics_service();
+
+ if (parsed_command_line.HasSwitch(switches::kMetricsRecordingOnly) ||
+ parsed_command_line.HasSwitch(switches::kEnableBenchmarking)) {
+ // If we're testing then we don't care what the user preference is, we turn
+ // on recording, but not reporting, otherwise tests fail.
+ metrics->StartRecordingOnly();
+ return metrics;
+ }
+
+ // If the user permits metrics reporting with the checkbox in the
+ // prefs, we turn on recording. We disable metrics completely for
+ // non-official builds.
+#if defined(GOOGLE_CHROME_BUILD)
+#if defined(OS_CHROMEOS)
+ bool enabled = chromeos::MetricsCrosSettingsProvider::GetMetricsStatus();
+#else
+ bool enabled = local_state->GetBoolean(prefs::kMetricsReportingEnabled);
+#endif // #if defined(OS_CHROMEOS)
+ if (enabled) {
+ metrics->Start();
+ chrome_browser_net_websocket_experiment::
+ WebSocketExperimentRunner::Start();
+ }
+#endif // defined(GOOGLE_CHROME_BUILD)
+
+ return metrics;
+}
+
+void BrowserMainParts::SetupFieldTrials() {
+ // Note: make sure to call ConnectionFieldTrial() before
+ // ProxyConnectionsFieldTrial().
+ ConnectionFieldTrial();
+ SocketTimeoutFieldTrial();
+ ProxyConnectionsFieldTrial();
+ prerender::ConfigurePrefetchAndPrerender(parsed_command_line());
+ SpdyFieldTrial();
+ ConnectBackupJobsFieldTrial();
+ SSLFalseStartFieldTrial();
+}
+
// -----------------------------------------------------------------------------
// TODO(viettrungluu): move more/rest of BrowserMain() into above structure
@@ -763,45 +830,6 @@ void InitializeBrokerServices(const MainFunctionParams& parameters,
#endif
}
-// Initializes the metrics service with the configuration for this process,
-// returning the created service (guaranteed non-NULL).
-MetricsService* InitializeMetrics(const CommandLine& parsed_command_line,
- const PrefService* local_state) {
-#if defined(OS_WIN)
- if (parsed_command_line.HasSwitch(switches::kChromeFrame))
- MetricsLog::set_version_extension("-F");
-#elif defined(ARCH_CPU_64_BITS)
- MetricsLog::set_version_extension("-64");
-#endif // defined(OS_WIN)
-
- MetricsService* metrics = g_browser_process->metrics_service();
-
- if (parsed_command_line.HasSwitch(switches::kMetricsRecordingOnly) ||
- parsed_command_line.HasSwitch(switches::kEnableBenchmarking)) {
- // If we're testing then we don't care what the user preference is, we turn
- // on recording, but not reporting, otherwise tests fail.
- metrics->StartRecordingOnly();
- } else {
- // If the user permits metrics reporting with the checkbox in the
- // prefs, we turn on recording. We disable metrics completely for
- // non-official builds.
-#if defined(GOOGLE_CHROME_BUILD)
-#if defined(OS_CHROMEOS)
- bool enabled = chromeos::MetricsCrosSettingsProvider::GetMetricsStatus();
-#else
- bool enabled = local_state->GetBoolean(prefs::kMetricsReportingEnabled);
-#endif // #if defined(OS_CHROMEOS)
- if (enabled) {
- metrics->Start();
- chrome_browser_net_websocket_experiment::
- WebSocketExperimentRunner::Start();
- }
-#endif
- }
-
- return metrics;
-}
-
// Initializes the profile, possibly doing some user prompting to pick a
// fallback profile. Returns the newly created profile, or NULL if startup
// should not continue.
@@ -1327,16 +1355,10 @@ int BrowserMain(const MainFunctionParams& parameters) {
about_flags::ConvertFlagsToSwitches(local_state,
CommandLine::ForCurrentProcess());
- // Now the command line has been mutated based on about:flags, we can run some
- // field trials
- parts->SetupFieldTrials();
-
- // Initialize FieldTrialSynchronizer system. This is a singleton and is used
- // for posting tasks via NewRunnableMethod. Its deleted when it goes out of
- // scope. Even though NewRunnableMethod does AddRef and Release, the object
- // will not be deleted after the Task is executed.
- scoped_refptr<FieldTrialSynchronizer> field_trial_synchronizer(
- new FieldTrialSynchronizer());
+ // Now the command line has been mutated based on about:flags, we can
+ // set up metrics and initialize field trials.
+ MetricsService* metrics = parts->SetupMetricsAndFieldTrials(
+ parsed_command_line, local_state);
// Now that all preferences have been registered, set the install date
// for the uninstall metrics if this is our first run. This only actually
@@ -1680,7 +1702,6 @@ int BrowserMain(const MainFunctionParams& parameters) {
sdch_manager.set_sdch_fetcher(new SdchDictionaryFetcher);
sdch_manager.EnableSdchSupport(sdch_supported_domain);
- MetricsService* metrics = InitializeMetrics(parsed_command_line, local_state);
InstallJankometer(parsed_command_line);
#if defined(OS_WIN) && !defined(GOOGLE_CHROME_BUILD)
diff --git a/chrome/browser/browser_main.h b/chrome/browser/browser_main.h
index 41e6f95..749d823 100644
--- a/chrome/browser/browser_main.h
+++ b/chrome/browser/browser_main.h
@@ -13,10 +13,12 @@
class BrowserThread;
class CommandLine;
+class FieldTrialSynchronizer;
class HighResolutionTimerManager;
struct MainFunctionParams;
class MessageLoop;
class MetricsService;
+class PrefService;
namespace net {
class NetworkChangeNotifier;
@@ -80,7 +82,12 @@ class BrowserMainParts {
void EarlyInitialization();
void MainMessageLoopStart();
- void SetupFieldTrials();
+ // Constructs metrics service and does related initialization, including
+ // creation of field trials. Call only after labs have been converted to
+ // switches.
+ MetricsService* SetupMetricsAndFieldTrials(
+ const CommandLine& parsed_command_line,
+ PrefService* local_state);
protected:
explicit BrowserMainParts(const MainFunctionParams& parameters);
@@ -132,6 +139,15 @@ class BrowserMainParts {
void InitializeMainThread();
+ // Methods for |SetupMetricsAndFieldTrials()| --------------------------------
+
+ static MetricsService* InitializeMetrics(
+ const CommandLine& parsed_command_line,
+ const PrefService* local_state);
+
+ // Add an invocation of your field trial init function to this method.
+ void SetupFieldTrials();
+
// Members initialized on construction ---------------------------------------
const MainFunctionParams& parameters_;
@@ -144,8 +160,9 @@ class BrowserMainParts {
tracked_objects::AutoTracking tracking_objects_;
#endif
- // Statistical testing infrastructure for the entire browser.
- base::FieldTrialList field_trial_;
+ // Statistical testing infrastructure for the entire browser. NULL until
+ // SetupMetricsAndFieldTrials is called.
+ scoped_ptr<base::FieldTrialList> field_trial_list_;
// Members initialized in |MainMessageLoopStart()| ---------------------------
scoped_ptr<MessageLoop> main_message_loop_;
@@ -154,6 +171,9 @@ class BrowserMainParts {
scoped_ptr<net::NetworkChangeNotifier> network_change_notifier_;
scoped_ptr<BrowserThread> main_thread_;
+ // Initialized in SetupMetricsAndFieldTrials.
+ scoped_refptr<FieldTrialSynchronizer> field_trial_synchronizer_;
+
DISALLOW_COPY_AND_ASSIGN(BrowserMainParts);
};
diff --git a/chrome/browser/metrics/metrics_service.cc b/chrome/browser/metrics/metrics_service.cc
index 11f61bc..2e3ccd8 100644
--- a/chrome/browser/metrics/metrics_service.cc
+++ b/chrome/browser/metrics/metrics_service.cc
@@ -471,6 +471,10 @@ void MetricsService::Stop() {
SetRecording(false);
}
+std::string MetricsService::GetClientId() {
+ return client_id_;
+}
+
void MetricsService::SetRecording(bool enabled) {
DCHECK(IsSingleThreaded());
diff --git a/chrome/browser/metrics/metrics_service.h b/chrome/browser/metrics/metrics_service.h
index 6acb6a2..b2b4ac3 100644
--- a/chrome/browser/metrics/metrics_service.h
+++ b/chrome/browser/metrics/metrics_service.h
@@ -82,6 +82,10 @@ class MetricsService : public NotificationObserver,
void StartRecordingOnly();
void Stop();
+ // Returns the client ID for this client, or the empty string if metrics
+ // recording is not currently running.
+ std::string GetClientId();
+
// At startup, prefs needs to be called with a list of all the pref names and
// types we'll be using.
static void RegisterPrefs(PrefService* local_state);
diff --git a/chrome/renderer/page_load_histograms.cc b/chrome/renderer/page_load_histograms.cc
index 3ae1498..6bd2c85 100644
--- a/chrome/renderer/page_load_histograms.cc
+++ b/chrome/renderer/page_load_histograms.cc
@@ -270,8 +270,8 @@ void PageLoadHistograms::Dump(WebFrame* frame) {
}
// Histograms to determine if DNS prefetching has an impact on PLT.
- static bool use_dns_histogram(base::FieldTrialList::Find("DnsImpact") &&
- !base::FieldTrialList::Find("DnsImpact")->group_name().empty());
+ static const bool use_dns_histogram =
+ base::FieldTrialList::TrialExists("DnsImpact");
if (use_dns_histogram) {
UMA_HISTOGRAM_ENUMERATION(
base::FieldTrial::MakeName("PLT.Abandoned", "DnsImpact"),
@@ -307,8 +307,7 @@ void PageLoadHistograms::Dump(WebFrame* frame) {
// Histograms to determine if content prefetching has an impact on PLT.
static const bool prefetching_fieldtrial =
- base::FieldTrialList::Find("Prefetch") &&
- !base::FieldTrialList::Find("Prefetch")->group_name().empty();
+ base::FieldTrialList::TrialExists("Prefetch");
if (prefetching_fieldtrial) {
if (navigation_state->was_prefetcher()) {
PLT_HISTOGRAM(base::FieldTrial::MakeName(
@@ -338,9 +337,8 @@ void PageLoadHistograms::Dump(WebFrame* frame) {
}
// Histograms to determine if backup connection jobs have an impact on PLT.
- static const bool connect_backup_jobs_fieldtrial(
- base::FieldTrialList::Find("ConnnectBackupJobs") &&
- !base::FieldTrialList::Find("ConnnectBackupJobs")->group_name().empty());
+ static const bool connect_backup_jobs_fieldtrial =
+ base::FieldTrialList::TrialExists("ConnnectBackupJobs");
if (connect_backup_jobs_fieldtrial) {
UMA_HISTOGRAM_ENUMERATION(
base::FieldTrial::MakeName("PLT.Abandoned", "ConnnectBackupJobs"),
@@ -378,9 +376,8 @@ void PageLoadHistograms::Dump(WebFrame* frame) {
// impact on PLT.
// TODO(jar): Consider removing the per-link-type versions. We
// really only need LINK_LOAD_NORMAL and NORMAL_LOAD.
- static bool use_connection_impact_histogram(
- base::FieldTrialList::Find("ConnCountImpact") &&
- !base::FieldTrialList::Find("ConnCountImpact")->group_name().empty());
+ static const bool use_connection_impact_histogram =
+ base::FieldTrialList::TrialExists("ConnCountImpact");
if (use_connection_impact_histogram) {
UMA_HISTOGRAM_ENUMERATION(
base::FieldTrial::MakeName("PLT.Abandoned", "ConnCountImpact"),
@@ -412,9 +409,8 @@ void PageLoadHistograms::Dump(WebFrame* frame) {
}
// Histograms to determine effect of idle socket timeout.
- static bool use_idle_socket_timeout_histogram(
- base::FieldTrialList::Find("IdleSktToImpact") &&
- !base::FieldTrialList::Find("IdleSktToImpact")->group_name().empty());
+ static const bool use_idle_socket_timeout_histogram =
+ base::FieldTrialList::TrialExists("IdleSktToImpact");
if (use_idle_socket_timeout_histogram) {
UMA_HISTOGRAM_ENUMERATION(
base::FieldTrial::MakeName("PLT.Abandoned", "IdleSktToImpact"),
@@ -446,10 +442,8 @@ void PageLoadHistograms::Dump(WebFrame* frame) {
}
// Histograms to determine effect of number of connections per proxy.
- static bool use_proxy_connection_impact_histogram(
- base::FieldTrialList::Find("ProxyConnectionImpact") &&
- !base::FieldTrialList::Find(
- "ProxyConnectionImpact")->group_name().empty());
+ static const bool use_proxy_connection_impact_histogram =
+ base::FieldTrialList::TrialExists("ProxyConnectionImpact");
if (use_proxy_connection_impact_histogram) {
UMA_HISTOGRAM_ENUMERATION(
base::FieldTrial::MakeName("PLT.Abandoned", "ProxyConnectionImpact"),
@@ -482,8 +476,8 @@ void PageLoadHistograms::Dump(WebFrame* frame) {
// Histograms to determine if SDCH has an impact.
// TODO(jar): Consider removing per-link load types and the enumeration.
- static bool use_sdch_histogram(base::FieldTrialList::Find("GlobalSdch") &&
- !base::FieldTrialList::Find("GlobalSdch")->group_name().empty());
+ static const bool use_sdch_histogram =
+ base::FieldTrialList::TrialExists("GlobalSdch");
if (use_sdch_histogram) {
UMA_HISTOGRAM_ENUMERATION(
base::FieldTrial::MakeName("PLT.LoadType", "GlobalSdch"),
@@ -520,8 +514,8 @@ void PageLoadHistograms::Dump(WebFrame* frame) {
}
// Histograms to determine if cache size has an impact on PLT.
- static bool use_cache_histogram1(base::FieldTrialList::Find("CacheSize") &&
- !base::FieldTrialList::Find("CacheSize")->group_name().empty());
+ static const bool use_cache_histogram1 =
+ base::FieldTrialList::TrialExists("CacheSize");
if (use_cache_histogram1 && NavigationState::LINK_LOAD_NORMAL <= load_type &&
NavigationState::LINK_LOAD_CACHE_ONLY >= load_type) {
// TODO(mbelshe): Do we really want BeginToFinishDoc here? It seems like
@@ -531,9 +525,8 @@ void PageLoadHistograms::Dump(WebFrame* frame) {
}
// Histograms to determine if cache throttling has an impact on PLT.
- static bool use_cache_histogram2(
- base::FieldTrialList::Find("CacheThrottle") &&
- !base::FieldTrialList::Find("CacheThrottle")->group_name().empty());
+ static const bool use_cache_histogram2 =
+ base::FieldTrialList::TrialExists("CacheThrottle");
if (use_cache_histogram2) {
UMA_HISTOGRAM_ENUMERATION(
base::FieldTrial::MakeName("PLT.Abandoned", "CacheThrottle"),
@@ -591,8 +584,8 @@ void PageLoadHistograms::Dump(WebFrame* frame) {
// if we asked for a HTTP request, we got a HTTP request
// Due to spdy version mismatches, it is possible that we ask for SPDY
// but didn't get SPDY.
- static bool use_spdy_histogram(base::FieldTrialList::Find("SpdyImpact") &&
- !base::FieldTrialList::Find("SpdyImpact")->group_name().empty());
+ static const bool use_spdy_histogram =
+ base::FieldTrialList::TrialExists("SpdyImpact");
if (use_spdy_histogram) {
// We take extra effort to only compute these once.
static bool in_spdy_trial = base::FieldTrialList::Find(
@@ -749,8 +742,8 @@ void PageLoadHistograms::Dump(WebFrame* frame) {
}
}
- static bool false_start_trial(base::FieldTrialList::Find("SSLFalseStart") &&
- !base::FieldTrialList::Find("SSLFalseStart")->group_name().empty());
+ static const bool false_start_trial =
+ base::FieldTrialList::TrialExists("SSLFalseStart");
if (false_start_trial) {
if (scheme_type == URLPattern::SCHEME_HTTPS) {
switch (load_type) {
diff --git a/chrome/renderer/prerender/prerender_helper.cc b/chrome/renderer/prerender/prerender_helper.cc
index 09efc71..47b1d70 100644
--- a/chrome/renderer/prerender/prerender_helper.cc
+++ b/chrome/renderer/prerender/prerender_helper.cc
@@ -45,8 +45,7 @@ void PrerenderHelper::RecordHistograms(
const base::Time& finish_all_loads,
const base::TimeDelta& begin_to_finish_all_loads) {
static bool use_prerender_histogram =
- base::FieldTrialList::Find("Prefetch") &&
- !base::FieldTrialList::Find("Prefetch")->group_name().empty();
+ base::FieldTrialList::TrialExists("Prefetch");
if (!use_prerender_histogram)
return;
diff --git a/content/renderer/renderer_main.cc b/content/renderer/renderer_main.cc
index dbb0e34..440ef77 100644
--- a/content/renderer/renderer_main.cc
+++ b/content/renderer/renderer_main.cc
@@ -191,8 +191,10 @@ int RendererMain(const MainFunctionParams& parameters) {
statistics.reset(new base::StatisticsRecorder());
}
- // Initialize statistical testing infrastructure.
- base::FieldTrialList field_trial;
+ // Initialize statistical testing infrastructure. We set client_id to the
+ // empty string to disallow the renderer process from creating its own
+ // one-time randomized trials; they should be created in the browser process.
+ base::FieldTrialList field_trial(EmptyString());
// Ensure any field trials in browser are reflected into renderer.
if (parsed_command_line.HasSwitch(switches::kForceFieldTestNameAndValue)) {
std::string persistent = parsed_command_line.GetSwitchValueASCII(
diff --git a/net/base/host_resolver_impl.cc b/net/base/host_resolver_impl.cc
index 8b33229..8c9d17f 100644
--- a/net/base/host_resolver_impl.cc
+++ b/net/base/host_resolver_impl.cc
@@ -554,9 +554,8 @@ class HostResolverImpl::Job
UMA_HISTOGRAM_ENUMERATION("DNS.ResolveCategory", category, RESOLVE_MAX);
- static bool show_speculative_experiment_histograms =
- base::FieldTrialList::Find("DnsImpact") &&
- !base::FieldTrialList::Find("DnsImpact")->group_name().empty();
+ static const bool show_speculative_experiment_histograms =
+ base::FieldTrialList::TrialExists("DnsImpact");
if (show_speculative_experiment_histograms) {
UMA_HISTOGRAM_ENUMERATION(
base::FieldTrial::MakeName("DNS.ResolveCategory", "DnsImpact"),
@@ -566,9 +565,8 @@ class HostResolverImpl::Job
"DnsImpact"), duration);
}
}
- static bool show_parallelism_experiment_histograms =
- base::FieldTrialList::Find("DnsParallelism") &&
- !base::FieldTrialList::Find("DnsParallelism")->group_name().empty();
+ static const bool show_parallelism_experiment_histograms =
+ base::FieldTrialList::TrialExists("DnsParallelism");
if (show_parallelism_experiment_histograms) {
UMA_HISTOGRAM_ENUMERATION(
base::FieldTrial::MakeName("DNS.ResolveCategory", "DnsParallelism"),
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc
index 552913f..3b2b77c 100644
--- a/net/http/http_cache_transaction.cc
+++ b/net/http/http_cache_transaction.cc
@@ -865,8 +865,7 @@ int HttpCache::Transaction::DoAddToEntryComplete(int result) {
base::TimeTicks::Now() - entry_lock_waiting_since_;
UMA_HISTOGRAM_TIMES("HttpCache.EntryLockWait", entry_lock_wait);
static const bool prefetching_fieldtrial =
- base::FieldTrialList::Find("Prefetch") &&
- !base::FieldTrialList::Find("Prefetch")->group_name().empty();
+ base::FieldTrialList::TrialExists("Prefetch");
if (prefetching_fieldtrial) {
UMA_HISTOGRAM_TIMES(
base::FieldTrial::MakeName("HttpCache.EntryLockWait", "Prefetch"),
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index 46858e6..604d793 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -1007,9 +1007,8 @@ void HttpNetworkTransaction::LogTransactionConnectedMetrics() {
base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
100);
- static bool use_conn_impact_histogram(
- base::FieldTrialList::Find("ConnCountImpact") &&
- !base::FieldTrialList::Find("ConnCountImpact")->group_name().empty());
+ static const bool use_conn_impact_histogram =
+ base::FieldTrialList::TrialExists("ConnCountImpact");
if (use_conn_impact_histogram) {
UMA_HISTOGRAM_CLIPPED_TIMES(
base::FieldTrial::MakeName("Net.Transaction_Connected_New",
@@ -1020,8 +1019,8 @@ void HttpNetworkTransaction::LogTransactionConnectedMetrics() {
}
}
- static bool use_spdy_histogram(base::FieldTrialList::Find("SpdyImpact") &&
- !base::FieldTrialList::Find("SpdyImpact")->group_name().empty());
+ static const bool use_spdy_histogram =
+ base::FieldTrialList::TrialExists("SpdyImpact");
if (use_spdy_histogram && response_.was_npn_negotiated) {
UMA_HISTOGRAM_CLIPPED_TIMES(
base::FieldTrial::MakeName("Net.Transaction_Connected_Under_10",
diff --git a/net/socket/client_socket_pool_histograms.cc b/net/socket/client_socket_pool_histograms.cc
index 202112b..5c3bddb 100644
--- a/net/socket/client_socket_pool_histograms.cc
+++ b/net/socket/client_socket_pool_histograms.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -58,10 +58,8 @@ void ClientSocketPoolHistograms::AddSocketType(int type) const {
void ClientSocketPoolHistograms::AddRequestTime(base::TimeDelta time) const {
request_time_->AddTime(time);
- static bool proxy_connection_impact_trial_exists(
- base::FieldTrialList::Find("ProxyConnectionImpact") &&
- !base::FieldTrialList::Find("ProxyConnectionImpact")->
- group_name().empty());
+ static const bool proxy_connection_impact_trial_exists =
+ base::FieldTrialList::TrialExists("ProxyConnectionImpact");
if (proxy_connection_impact_trial_exists && is_http_proxy_connection_) {
UMA_HISTOGRAM_CUSTOM_TIMES(
base::FieldTrial::MakeName("Net.HttpProxySocketRequestTime",
diff --git a/net/socket/ssl_client_socket_pool.cc b/net/socket/ssl_client_socket_pool.cc
index 5f8daa7..7bde6d0 100644
--- a/net/socket/ssl_client_socket_pool.cc
+++ b/net/socket/ssl_client_socket_pool.cc
@@ -347,9 +347,8 @@ int SSLConnectJob::DoSSLConnectComplete(int result) {
100);
}
- static bool false_start_trial(
- base::FieldTrialList::Find("SSLFalseStart") &&
- !base::FieldTrialList::Find("SSLFalseStart")->group_name().empty());
+ static const bool false_start_trial =
+ base::FieldTrialList::TrialExists("SSLFalseStart");
if (false_start_trial) {
UMA_HISTOGRAM_CUSTOM_TIMES(base::FieldTrial::MakeName(
"Net.SSL_Connection_Latency",
diff --git a/net/socket/stream_socket.cc b/net/socket/stream_socket.cc
index 37482b4..3ef24c0 100644
--- a/net/socket/stream_socket.cc
+++ b/net/socket/stream_socket.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -134,8 +134,7 @@ void StreamSocket::UseHistory::EmitPreconnectionHistograms() const {
UMA_HISTOGRAM_ENUMERATION("Net.PreconnectUtilization2", result, 9);
static const bool connect_backup_jobs_fieldtrial =
- base::FieldTrialList::Find("ConnnectBackupJobs") &&
- !base::FieldTrialList::Find("ConnnectBackupJobs")->group_name().empty();
+ base::FieldTrialList::TrialExists("ConnnectBackupJobs");
if (connect_backup_jobs_fieldtrial) {
UMA_HISTOGRAM_ENUMERATION(
base::FieldTrial::MakeName("Net.PreconnectUtilization2",
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc
index cfb6ffc..ae87029 100644
--- a/net/url_request/url_request_http_job.cc
+++ b/net/url_request/url_request_http_job.cc
@@ -1123,8 +1123,7 @@ void URLRequestHttpJob::RecordTimer() {
request_creation_time_ = base::Time();
static const bool use_prefetch_histogram =
- base::FieldTrialList::Find("Prefetch") &&
- !base::FieldTrialList::Find("Prefetch")->group_name().empty();
+ base::FieldTrialList::TrialExists("Prefetch");
UMA_HISTOGRAM_MEDIUM_TIMES("Net.HttpTimeToFirstByte", to_start);
if (use_prefetch_histogram) {