summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorasvitkine@chromium.org <asvitkine@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-29 19:32:11 +0000
committerasvitkine@chromium.org <asvitkine@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-29 19:32:11 +0000
commit97c72f5cd4d7ff5e906d946c6b48b95104dd0349 (patch)
tree01646ce768256de48b9aa377ca3735c3b3517a8b
parentccd3e14531792b2479519272f47791e31ce2b3d2 (diff)
downloadchromium_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.cc25
-rw-r--r--base/metrics/field_trial.h27
-rw-r--r--base/metrics/field_trial_unittest.cc43
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