Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(506)

Unified Diff: base/metrics/field_trial.h

Issue 6883102: Add one-time randomization support for FieldTrial, and the ability to (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Unit test cancel support. Created 9 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: base/metrics/field_trial.h
diff --git a/base/metrics/field_trial.h b/base/metrics/field_trial.h
index dcfd39173a3ade9f4e9f4e0ff56caedfbd4d7738..cf4a13b41c7dda2b4478be5e7e170314f5823491 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,7 @@
// 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());
jar (doing other things) 2011/04/21 22:10:02 Removal of this code is a VERY good improvement.
Jói 2011/04/28 01:03:50 I've updated all the call-sites now. I introduced
Jói 2011/05/02 18:55:03 FYI, there were some merge changes to resolve, I u
-// if (use_memoryexperiment_histogram) {
+// if (FieldTrialList::Find("Memory.RendererTotal")) {
// HISTOGRAM_COUNTS(FieldTrial::MakeName("Memory.RendererTotal",
// "MemoryExperiment"), count);
// }
@@ -102,15 +100,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.
@@ -123,18 +141,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);
@@ -154,6 +171,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;
@@ -167,8 +187,14 @@ 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);
jar (doing other things) 2011/04/21 22:10:02 I would have expected the client_id to be a consta
Jói 2011/04/28 01:03:50 2011/04/21 22:10:02, jar wrote:
+
// The name of the field trial, as can be found via the FieldTrialList.
- // This is empty of the trial is not in the experiment.
+ // This is empty if the trial is not in the experiment.
jar (doing other things) 2011/04/21 22:10:02 hmmm.... is this ever empty now?
Jói 2011/04/28 01:03:50 You're right, I updated the documentation and adde
const std::string name_;
// The maximum sum of all probabilities supplied, which corresponds to 100%.
@@ -181,7 +207,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_;
@@ -192,13 +218,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_;
jar (doing other things) 2011/04/21 22:10:02 Thanks for making this change!
Jói 2011/04/28 01:03:50 No prob.
// When benchmarking is enabled, field trials all revert to the 'default'
// group.
@@ -265,6 +291,23 @@ class BASE_API FieldTrialList {
// Return the number of active field trials.
static size_t GetFieldTrialCount();
+ // Sets an opaque, diverse ID for this client that does not change
+ // between sessions. This must be called exactly once before any call to
+ // |FieldTrial::UseOneTimeRandomization()| and does not need to be called
+ // unless such a call is made.
+ static void EnableOneTimeRandomization(const std::string& client_id);
jar (doing other things) 2011/04/21 22:10:02 I'd be tempted to make this part of required initi
Jói 2011/04/28 01:03:50 I disagree, but am willing to be overridden. Let
jar (doing other things) 2011/04/29 00:57:11 I'm not sold on your arguments. To be specific, f
Jói 2011/05/02 18:55:03 I've switched to having client_id as an argument t
+
+ // Returns true if you can call |FieldTrial::UseOneTimeRandomization()|
+ // without error, i.e. if |EnableOneTimeRandomization()| has been called.
+ static bool IsOneTimeRandomizationEnabled();
+
+ // Returns an opaque, diverse ID for this client that does not change
+ // between sessions.
+ //
+ // Returns the empty string if |EnableOneTimeRandomization()| has not
+ // been called.
+ static const std::string& client_id();
+
private:
// A map from FieldTrial names to the actual instances.
typedef std::map<std::string, FieldTrial*> RegistrationList;
@@ -279,7 +322,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_;
@@ -288,6 +331,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_;
+
DISALLOW_COPY_AND_ASSIGN(FieldTrialList);
};
« no previous file with comments | « base/metrics/OWNERS ('k') | base/metrics/field_trial.cc » ('j') | base/metrics/field_trial.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698