diff options
author | asvitkine@chromium.org <asvitkine@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-29 19:32:11 +0000 |
---|---|---|
committer | asvitkine@chromium.org <asvitkine@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-29 19:32:11 +0000 |
commit | 97c72f5cd4d7ff5e906d946c6b48b95104dd0349 (patch) | |
tree | 01646ce768256de48b9aa377ca3735c3b3517a8b | |
parent | ccd3e14531792b2479519272f47791e31ce2b3d2 (diff) | |
download | chromium_src-97c72f5cd4d7ff5e906d946c6b48b95104dd0349.zip chromium_src-97c72f5cd4d7ff5e906d946c6b48b95104dd0349.tar.gz chromium_src-97c72f5cd4d7ff5e906d946c6b48b95104dd0349.tar.bz2 |
Add static FieldTrial::CreateSimulatedFieldTrial function.
This allows creating a field trial not associated with the global field trial
list, e.g. to simulate group assignment without affecting global state.
See associated bug for more detailed motivation.
BUG=281474
TEST=New unit tests.
Review URL: https://codereview.chromium.org/23503019
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@231612 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | base/metrics/field_trial.cc | 25 | ||||
-rw-r--r-- | base/metrics/field_trial.h | 27 | ||||
-rw-r--r-- | base/metrics/field_trial_unittest.cc | 43 |
3 files changed, 91 insertions, 4 deletions
diff --git a/base/metrics/field_trial.cc b/base/metrics/field_trial.cc index d500a29..03b63dc 100644 --- a/base/metrics/field_trial.cc +++ b/base/metrics/field_trial.cc @@ -85,7 +85,8 @@ FieldTrial::FieldTrial(const std::string& trial_name, group_(kNotFinalized), enable_field_trial_(true), forced_(false), - group_reported_(false) { + group_reported_(false), + trial_registered_(false) { DCHECK_GT(total_probability, 0); DCHECK(!trial_name_.empty()); DCHECK(!default_group_name_.empty()); @@ -146,7 +147,8 @@ int FieldTrial::AppendGroup(const std::string& name, int FieldTrial::group() { FinalizeGroupChoice(); - FieldTrialList::NotifyFieldTrialGroupSelection(this); + if (trial_registered_) + FieldTrialList::NotifyFieldTrialGroupSelection(this); return group_; } @@ -174,8 +176,24 @@ void FieldTrial::SetForced() { forced_ = true; } +// static +FieldTrial* FieldTrial::CreateSimulatedFieldTrial( + const std::string& trial_name, + Probability total_probability, + const std::string& default_group_name, + double entropy_value) { + return new FieldTrial(trial_name, total_probability, default_group_name, + entropy_value); +} + FieldTrial::~FieldTrial() {} +void FieldTrial::SetTrialRegistered() { + DCHECK_EQ(kNotFinalized, group_); + DCHECK(!trial_registered_); + trial_registered_ = true; +} + void FieldTrial::SetGroupChoice(const std::string& group_name, int number) { group_ = number; if (group_name.empty()) @@ -434,9 +452,9 @@ FieldTrial* FieldTrialList::CreateFieldTrial( } const int kTotalProbability = 100; field_trial = new FieldTrial(name, kTotalProbability, group_name, 0); + FieldTrialList::Register(field_trial); // Force the trial, which will also finalize the group choice. field_trial->SetForced(); - FieldTrialList::Register(field_trial); return field_trial; } @@ -510,6 +528,7 @@ void FieldTrialList::Register(FieldTrial* trial) { AutoLock auto_lock(global_->lock_); DCHECK(!global_->PreLockedFind(trial->trial_name())); trial->AddRef(); + trial->SetTrialRegistered(); global_->registered_[trial->trial_name()] = trial; } diff --git a/base/metrics/field_trial.h b/base/metrics/field_trial.h index 2928935..0a389d3 100644 --- a/base/metrics/field_trial.h +++ b/base/metrics/field_trial.h @@ -153,6 +153,22 @@ class BASE_EXPORT FieldTrial : public RefCounted<FieldTrial> { // be done from the UI thread. void SetForced(); + // Creates a FieldTrial object with the specified parameters, to be used for + // simulation of group assignment without actually affecting global field + // trial state in the running process. Group assignment will be done based on + // |entropy_value|, which must have a range of [0, 1). + // + // Note: Using this function will not register the field trial globally in the + // running process - for that, use FieldTrialList::FactoryGetFieldTrial(). + // + // The ownership of the returned FieldTrial is transfered to the caller which + // is responsible for deref'ing it (e.g. by using scoped_refptr<FieldTrial>). + static FieldTrial* CreateSimulatedFieldTrial( + const std::string& trial_name, + Probability total_probability, + const std::string& default_group_name, + double entropy_value); + private: // Allow tests to access our innards for testing purposes. FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, Registration); @@ -184,7 +200,7 @@ class BASE_EXPORT FieldTrial : public RefCounted<FieldTrial> { // Creates a field trial with the specified parameters. Group assignment will // be done based on |entropy_value|, which must have a range of [0, 1). - FieldTrial(const std::string& name, + FieldTrial(const std::string& trial_name, Probability total_probability, const std::string& default_group_name, double entropy_value); @@ -193,6 +209,10 @@ class BASE_EXPORT FieldTrial : public RefCounted<FieldTrial> { // Return the default group name of the FieldTrial. std::string default_group_name() const { return default_group_name_; } + // Marks this trial as having been registered with the FieldTrialList. Must be + // called no more than once and before any |group()| calls have occurred. + void SetTrialRegistered(); + // Sets the chosen group name and number. void SetGroupChoice(const std::string& group_name, int number); @@ -230,6 +250,7 @@ class BASE_EXPORT FieldTrial : public RefCounted<FieldTrial> { // Sum of the probabilities of all appended groups. Probability accumulated_group_probability_; + // The number that will be returned by the next AppendGroup() call. int next_group_number_; // The pseudo-randomly assigned group number. @@ -251,6 +272,10 @@ class BASE_EXPORT FieldTrial : public RefCounted<FieldTrial> { // Specifies whether the group choice has been reported to observers. bool group_reported_; + // Whether this trial is registered with the global FieldTrialList and thus + // should notify it when its group is queried. + bool trial_registered_; + // When benchmarking is enabled, field trials all revert to the 'default' // group. static bool enable_benchmarking_; diff --git a/base/metrics/field_trial_unittest.cc b/base/metrics/field_trial_unittest.cc index 10d3c3f..a77633e 100644 --- a/base/metrics/field_trial_unittest.cc +++ b/base/metrics/field_trial_unittest.cc @@ -877,4 +877,47 @@ TEST_F(FieldTrialTest, DoesNotSurpassTotalProbability) { EXPECT_EQ("2", trial->group_name()); } +TEST_F(FieldTrialTest, CreateSimulatedFieldTrial) { + const char kTrialName[] = "CreateSimulatedFieldTrial"; + ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName)); + + // Different cases to test, e.g. default vs. non default group being chosen. + struct { + double entropy_value; + const char* expected_group; + } test_cases[] = { + { 0.4, "A" }, + { 0.85, "B" }, + { 0.95, kDefaultGroupName }, + }; + + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { + TestFieldTrialObserver observer; + scoped_refptr<FieldTrial> trial( + FieldTrial::CreateSimulatedFieldTrial(kTrialName, 100, kDefaultGroupName, + test_cases[i].entropy_value)); + trial->AppendGroup("A", 80); + trial->AppendGroup("B", 10); + EXPECT_EQ(test_cases[i].expected_group, trial->group_name()); + + // Field trial shouldn't have been registered with the list. + EXPECT_FALSE(FieldTrialList::TrialExists(kTrialName)); + EXPECT_EQ(0u, FieldTrialList::GetFieldTrialCount()); + + // Observer shouldn't have been notified. + RunLoop().RunUntilIdle(); + EXPECT_TRUE(observer.trial_name().empty()); + + // The trial shouldn't be in the active set of trials. + FieldTrial::ActiveGroups active_groups; + FieldTrialList::GetActiveFieldTrialGroups(&active_groups); + EXPECT_TRUE(active_groups.empty()); + + // The trial shouldn't be listed in the |StatesToString()| result. + std::string states; + FieldTrialList::StatesToString(&states); + EXPECT_TRUE(states.empty()); + } +} + } // namespace base |