OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // FieldTrial is a class for handling details of statistical experiments | 5 // FieldTrial is a class for handling details of statistical experiments |
6 // performed by actual users in the field (i.e., in a shipped or beta product). | 6 // performed by actual users in the field (i.e., in a shipped or beta product). |
7 // All code is called exclusively on the UI thread currently. | 7 // All code is called exclusively on the UI thread currently. |
8 // | 8 // |
9 // The simplest example is an experiment to see whether one of two options | 9 // The simplest example is an experiment to see whether one of two options |
10 // produces "better" results across our user population. In that scenario, UMA | 10 // produces "better" results across our user population. In that scenario, UMA |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
85 #include "base/synchronization/lock.h" | 85 #include "base/synchronization/lock.h" |
86 #include "base/time.h" | 86 #include "base/time.h" |
87 | 87 |
88 namespace base { | 88 namespace base { |
89 | 89 |
90 class FieldTrialList; | 90 class FieldTrialList; |
91 | 91 |
92 class BASE_EXPORT FieldTrial : public RefCounted<FieldTrial> { | 92 class BASE_EXPORT FieldTrial : public RefCounted<FieldTrial> { |
93 public: | 93 public: |
94 typedef int Probability; // Probability type for being selected in a trial. | 94 typedef int Probability; // Probability type for being selected in a trial. |
95 // The Unique ID of a trial, where the name and group identifiers are | 95 |
96 // hashes of the trial and group name strings. | 96 // A pair representing a Field Trial and its selected group. |
97 struct NameGroupId { | 97 struct SelectedGroup { |
98 uint32 name; | 98 std::string trial; |
99 uint32 group; | 99 std::string group; |
100 }; | 100 }; |
101 | 101 |
102 typedef std::vector<SelectedGroup> SelectedGroups; | |
103 | |
102 // A return value to indicate that a given instance has not yet had a group | 104 // A return value to indicate that a given instance has not yet had a group |
103 // assignment (and hence is not yet participating in the trial). | 105 // assignment (and hence is not yet participating in the trial). |
104 static const int kNotFinalized; | 106 static const int kNotFinalized; |
105 | 107 |
106 // Changes the field trial to use one-time randomization, i.e. produce the | 108 // Changes the field trial to use one-time randomization, i.e. produce the |
107 // same result for the current trial on every run of this client. Must be | 109 // same result for the current trial on every run of this client. Must be |
108 // called right after construction. | 110 // called right after construction. |
109 void UseOneTimeRandomization(); | 111 void UseOneTimeRandomization(); |
110 | 112 |
111 // Disables this trial, meaning it always determines the default group | 113 // Disables this trial, meaning it always determines the default group |
(...skipping 16 matching lines...) Expand all Loading... | |
128 | 130 |
129 // Return the randomly selected group number that was assigned. | 131 // Return the randomly selected group number that was assigned. |
130 // Note that this will force an instance to participate, and make it illegal | 132 // Note that this will force an instance to participate, and make it illegal |
131 // to attempt to probabilistically add any other groups to the trial. | 133 // to attempt to probabilistically add any other groups to the trial. |
132 int group(); | 134 int group(); |
133 | 135 |
134 // If the group's name is empty, a string version containing the group number | 136 // If the group's name is empty, a string version containing the group number |
135 // is used as the group name. This causes a winner to be chosen if none was. | 137 // is used as the group name. This causes a winner to be chosen if none was. |
136 std::string group_name(); | 138 std::string group_name(); |
137 | 139 |
138 // Gets the unique identifier of the Field Trial, but only if a group was | 140 // Gets the SelectedGroup of the Field Trial, but only if a group was |
139 // officially chosen, otherwise name_group_id is left untouched and false | 141 // officially chosen, otherwise name_group_id is left untouched and false |
140 // is returned. When true is returned, the name and group ids were | 142 // is returned. When true is returned, the trial and group names were |
141 // successfully set in name_group_id. | 143 // successfully set in selected_group. |
142 bool GetNameGroupId(NameGroupId* name_group_id); | 144 bool GetSelectedGroup(SelectedGroup* selected_group); |
143 | 145 |
144 // Helper function for the most common use: as an argument to specify the | 146 // Helper function for the most common use: as an argument to specify the |
145 // name of a HISTOGRAM. Use the original histogram name as the name_prefix. | 147 // name of a HISTOGRAM. Use the original histogram name as the name_prefix. |
146 static std::string MakeName(const std::string& name_prefix, | 148 static std::string MakeName(const std::string& name_prefix, |
147 const std::string& trial_name); | 149 const std::string& trial_name); |
148 | 150 |
149 // Helper function to create a NameGroupId from |trial_name| and |group_name|. | |
150 static NameGroupId MakeNameGroupId(const std::string& trial_name, | |
151 const std::string& group_name); | |
152 | |
153 // Enable benchmarking sets field trials to a common setting. | 151 // Enable benchmarking sets field trials to a common setting. |
154 static void EnableBenchmarking(); | 152 static void EnableBenchmarking(); |
155 | 153 |
156 private: | 154 private: |
157 // Allow tests to access our innards for testing purposes. | 155 // Allow tests to access our innards for testing purposes. |
158 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, Registration); | 156 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, Registration); |
159 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, AbsoluteProbabilities); | 157 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, AbsoluteProbabilities); |
160 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, RemainingProbability); | 158 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, RemainingProbability); |
161 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, FiftyFiftyProbability); | 159 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, FiftyFiftyProbability); |
162 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, MiddleProbabilities); | 160 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, MiddleProbabilities); |
163 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, OneWinner); | 161 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, OneWinner); |
164 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, DisableProbability); | 162 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, DisableProbability); |
165 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, Save); | 163 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, Save); |
166 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, DuplicateRestore); | 164 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, DuplicateRestore); |
167 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, MakeName); | 165 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, MakeName); |
168 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, HashClientId); | 166 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, HashClientId); |
169 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, HashClientIdIsUniform); | 167 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, HashClientIdIsUniform); |
170 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, HashName); | |
171 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, NameGroupIds); | 168 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, NameGroupIds); |
172 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, UseOneTimeRandomization); | 169 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, UseOneTimeRandomization); |
173 | 170 |
174 friend class base::FieldTrialList; | 171 friend class base::FieldTrialList; |
175 | 172 |
176 friend class RefCounted<FieldTrial>; | 173 friend class RefCounted<FieldTrial>; |
177 | 174 |
178 // This is the group number of the 'default' group when a choice wasn't forced | 175 // This is the group number of the 'default' group when a choice wasn't forced |
179 // by a call to FieldTrialList::CreateFieldTrial. It is kept private so that | 176 // by a call to FieldTrialList::CreateFieldTrial. It is kept private so that |
180 // consumers don't use it by mistake in cases where the group was forced. | 177 // consumers don't use it by mistake in cases where the group was forced. |
(...skipping 12 matching lines...) Expand all Loading... | |
193 | 190 |
194 // Returns the group_name. A winner need not have been chosen. | 191 // Returns the group_name. A winner need not have been chosen. |
195 std::string group_name_internal() const { return group_name_; } | 192 std::string group_name_internal() const { return group_name_; } |
196 | 193 |
197 // Calculates a uniformly-distributed double between [0.0, 1.0) given | 194 // Calculates a uniformly-distributed double between [0.0, 1.0) given |
198 // a |client_id| and a |trial_name| (the latter is used as salt to avoid | 195 // a |client_id| and a |trial_name| (the latter is used as salt to avoid |
199 // separate one-time randomized trials from all having the same results). | 196 // separate one-time randomized trials from all having the same results). |
200 static double HashClientId(const std::string& client_id, | 197 static double HashClientId(const std::string& client_id, |
201 const std::string& trial_name); | 198 const std::string& trial_name); |
202 | 199 |
203 // Creates unique identifier for the trial by hashing a name string, whether | |
204 // it's for the field trial or the group name. | |
205 static uint32 HashName(const std::string& name); | |
206 | |
207 // The name of the field trial, as can be found via the FieldTrialList. | 200 // The name of the field trial, as can be found via the FieldTrialList. |
208 const std::string name_; | 201 const std::string name_; |
209 | 202 |
210 // The hashed name of the field trial to be sent as a unique identifier. | |
211 const uint32 name_hash_; | |
212 | |
213 // The maximum sum of all probabilities supplied, which corresponds to 100%. | 203 // The maximum sum of all probabilities supplied, which corresponds to 100%. |
214 // This is the scaling factor used to adjust supplied probabilities. | 204 // This is the scaling factor used to adjust supplied probabilities. |
215 const Probability divisor_; | 205 const Probability divisor_; |
216 | 206 |
217 // The name of the default group. | 207 // The name of the default group. |
218 const std::string default_group_name_; | 208 const std::string default_group_name_; |
219 | 209 |
220 // The randomly selected probability that is used to select a group (or have | 210 // The randomly selected probability that is used to select a group (or have |
221 // the instance not participate). It is the product of divisor_ and a random | 211 // the instance not participate). It is the product of divisor_ and a random |
222 // number between [0, 1). | 212 // number between [0, 1). |
223 Probability random_; | 213 Probability random_; |
224 | 214 |
225 // Sum of the probabilities of all appended groups. | 215 // Sum of the probabilities of all appended groups. |
226 Probability accumulated_group_probability_; | 216 Probability accumulated_group_probability_; |
227 | 217 |
228 int next_group_number_; | 218 int next_group_number_; |
229 | 219 |
230 // The pseudo-randomly assigned group number. | 220 // The pseudo-randomly assigned group number. |
231 // This is kNotFinalized if no group has been assigned. | 221 // This is kNotFinalized if no group has been assigned. |
232 int group_; | 222 int group_; |
233 | 223 |
234 // A textual name for the randomly selected group. Valid after |group()| | 224 // A textual name for the randomly selected group. Valid after |group()| |
235 // has been called. | 225 // has been called. |
236 std::string group_name_; | 226 std::string group_name_; |
237 | 227 |
238 // The hashed name of the group to be sent as a unique identifier. | |
239 // Is not valid while group_ is equal to kNotFinalized. | |
240 uint32 group_name_hash_; | |
241 | |
242 // When enable_field_trial_ is false, field trial reverts to the 'default' | 228 // When enable_field_trial_ is false, field trial reverts to the 'default' |
243 // group. | 229 // group. |
244 bool enable_field_trial_; | 230 bool enable_field_trial_; |
245 | 231 |
246 // When forced_ is true, we return the chosen group from AppendGroup when | 232 // When forced_ is true, we return the chosen group from AppendGroup when |
247 // appropriate. | 233 // appropriate. |
248 bool forced_; | 234 bool forced_; |
249 | 235 |
250 // When benchmarking is enabled, field trials all revert to the 'default' | 236 // When benchmarking is enabled, field trials all revert to the 'default' |
251 // group. | 237 // group. |
252 static bool enable_benchmarking_; | 238 static bool enable_benchmarking_; |
253 | 239 |
254 // This value is reserved for an uninitialized hash value. | |
255 static const uint32 kReservedHashValue; | |
256 | |
257 DISALLOW_COPY_AND_ASSIGN(FieldTrial); | 240 DISALLOW_COPY_AND_ASSIGN(FieldTrial); |
258 }; | 241 }; |
259 | 242 |
260 //------------------------------------------------------------------------------ | 243 //------------------------------------------------------------------------------ |
261 // Class with a list of all active field trials. A trial is active if it has | 244 // Class with a list of all active field trials. A trial is active if it has |
262 // been registered, which includes evaluating its state based on its probaility. | 245 // been registered, which includes evaluating its state based on its probaility. |
263 // Only one instance of this class exists. | 246 // Only one instance of this class exists. |
264 class BASE_EXPORT FieldTrialList { | 247 class BASE_EXPORT FieldTrialList { |
265 public: | 248 public: |
266 // Define a separator character to use when creating a persistent form of an | 249 // Define a separator character to use when creating a persistent form of an |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
336 static bool TrialExists(const std::string& name); | 319 static bool TrialExists(const std::string& name); |
337 | 320 |
338 // Creates a persistent representation of all FieldTrial instances for | 321 // Creates a persistent representation of all FieldTrial instances for |
339 // resurrection in another process. This allows randomization to be done in | 322 // resurrection in another process. This allows randomization to be done in |
340 // one process, and secondary processes can be synchronized on the result. | 323 // one process, and secondary processes can be synchronized on the result. |
341 // The resulting string contains the name and group name pairs for all trials, | 324 // The resulting string contains the name and group name pairs for all trials, |
342 // with "/" used to separate all names and to terminate the string. This | 325 // with "/" used to separate all names and to terminate the string. This |
343 // string is parsed by CreateTrialsFromString(). | 326 // string is parsed by CreateTrialsFromString(). |
344 static void StatesToString(std::string* output); | 327 static void StatesToString(std::string* output); |
345 | 328 |
346 // Returns an array of Unique IDs for each Field Trial that has a chosen | 329 // Returns an array of SelectedGroup objects, each representing a chosen Field |
jar (doing other things)
2012/04/26 22:24:22
nit: (even in pre-existing comentary): It doesn't
SteveT
2012/04/26 23:42:47
Very true. Done.
| |
347 // group. Field Trials for which a group has not been chosen yet are NOT | 330 // Trial group. Field Trials for which a group has not been chosen yet are NOT |
348 // returned in this list. | 331 // returned in this list. |
349 static void GetFieldTrialNameGroupIds( | 332 static void GetFieldTrialSelectedGroups( |
350 std::vector<FieldTrial::NameGroupId>* name_group_ids); | 333 FieldTrial::SelectedGroups* selected_groups); |
351 | 334 |
352 // Use a state string (re: StatesToString()) to augment the current list of | 335 // Use a state string (re: StatesToString()) to augment the current list of |
353 // field tests to include the supplied tests, and using a 100% probability for | 336 // field tests to include the supplied tests, and using a 100% probability for |
354 // each test, force them to have the same group string. This is commonly used | 337 // each test, force them to have the same group string. This is commonly used |
355 // in a non-browser process, to carry randomly selected state in a browser | 338 // in a non-browser process, to carry randomly selected state in a browser |
356 // process into this non-browser process, but could also be invoked through a | 339 // process into this non-browser process, but could also be invoked through a |
357 // command line argument to the browser process. | 340 // command line argument to the browser process. |
358 static bool CreateTrialsFromString(const std::string& prior_trials); | 341 static bool CreateTrialsFromString(const std::string& prior_trials); |
359 | 342 |
360 // Create a FieldTrial with the given |name| and using 100% probability for | 343 // Create a FieldTrial with the given |name| and using 100% probability for |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
439 | 422 |
440 // List of observers to be notified when a group is selected for a FieldTrial. | 423 // List of observers to be notified when a group is selected for a FieldTrial. |
441 ObserverList<Observer> observer_list_; | 424 ObserverList<Observer> observer_list_; |
442 | 425 |
443 DISALLOW_COPY_AND_ASSIGN(FieldTrialList); | 426 DISALLOW_COPY_AND_ASSIGN(FieldTrialList); |
444 }; | 427 }; |
445 | 428 |
446 } // namespace base | 429 } // namespace base |
447 | 430 |
448 #endif // BASE_METRICS_FIELD_TRIAL_H_ | 431 #endif // BASE_METRICS_FIELD_TRIAL_H_ |
OLD | NEW |