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 // A return value to indicate that a given instance has not yet had a group | 102 // 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). | 103 // assignment (and hence is not yet participating in the trial). |
104 static const int kNotFinalized; | 104 static const int kNotFinalized; |
105 | 105 |
106 // Changes the field trial to use one-time randomization, i.e. produce the | 106 // 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 | 107 // same result for the current trial on every run of this client. Must be |
108 // called right after construction. | 108 // called right after construction. |
109 void UseOneTimeRandomization(); | 109 void UseOneTimeRandomization(); |
(...skipping 18 matching lines...) Expand all Loading... |
128 | 128 |
129 // Return the randomly selected group number that was assigned. | 129 // Return the randomly selected group number that was assigned. |
130 // Note that this will force an instance to participate, and make it illegal | 130 // 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. | 131 // to attempt to probabilistically add any other groups to the trial. |
132 int group(); | 132 int group(); |
133 | 133 |
134 // If the group's name is empty, a string version containing the group number | 134 // 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. | 135 // is used as the group name. This causes a winner to be chosen if none was. |
136 std::string group_name(); | 136 std::string group_name(); |
137 | 137 |
138 // Gets the unique identifier of the Field Trial, but only if a group was | 138 // 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 | 139 // officially chosen, otherwise name_group_id is left untouched and false |
140 // is returned. When true is returned, the name and group ids were | 140 // is returned. When true is returned, the trial and group names were |
141 // successfully set in name_group_id. | 141 // successfully set in selected_group. |
142 bool GetNameGroupId(NameGroupId* name_group_id); | 142 bool GetSelectedGroup(SelectedGroup* selected_group); |
143 | 143 |
144 // Helper function for the most common use: as an argument to specify the | 144 // 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. | 145 // name of a HISTOGRAM. Use the original histogram name as the name_prefix. |
146 static std::string MakeName(const std::string& name_prefix, | 146 static std::string MakeName(const std::string& name_prefix, |
147 const std::string& trial_name); | 147 const std::string& trial_name); |
148 | 148 |
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. | 149 // Enable benchmarking sets field trials to a common setting. |
154 static void EnableBenchmarking(); | 150 static void EnableBenchmarking(); |
155 | 151 |
156 private: | 152 private: |
157 // Allow tests to access our innards for testing purposes. | 153 // Allow tests to access our innards for testing purposes. |
158 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, Registration); | 154 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, Registration); |
159 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, AbsoluteProbabilities); | 155 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, AbsoluteProbabilities); |
160 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, RemainingProbability); | 156 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, RemainingProbability); |
161 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, FiftyFiftyProbability); | 157 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, FiftyFiftyProbability); |
162 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, MiddleProbabilities); | 158 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, MiddleProbabilities); |
163 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, OneWinner); | 159 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, OneWinner); |
164 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, DisableProbability); | 160 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, DisableProbability); |
165 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, Save); | 161 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, Save); |
166 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, DuplicateRestore); | 162 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, DuplicateRestore); |
167 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, MakeName); | 163 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, MakeName); |
168 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, HashClientId); | 164 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, HashClientId); |
169 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, HashClientIdIsUniform); | 165 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, HashClientIdIsUniform); |
170 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, HashName); | |
171 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, NameGroupIds); | 166 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, NameGroupIds); |
172 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, UseOneTimeRandomization); | 167 FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, UseOneTimeRandomization); |
173 | 168 |
174 friend class base::FieldTrialList; | 169 friend class base::FieldTrialList; |
175 | 170 |
176 friend class RefCounted<FieldTrial>; | 171 friend class RefCounted<FieldTrial>; |
177 | 172 |
178 // This is the group number of the 'default' group when a choice wasn't forced | 173 // 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 | 174 // 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. | 175 // consumers don't use it by mistake in cases where the group was forced. |
(...skipping 12 matching lines...) Expand all Loading... |
193 | 188 |
194 // Returns the group_name. A winner need not have been chosen. | 189 // Returns the group_name. A winner need not have been chosen. |
195 std::string group_name_internal() const { return group_name_; } | 190 std::string group_name_internal() const { return group_name_; } |
196 | 191 |
197 // Calculates a uniformly-distributed double between [0.0, 1.0) given | 192 // 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 | 193 // 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). | 194 // separate one-time randomized trials from all having the same results). |
200 static double HashClientId(const std::string& client_id, | 195 static double HashClientId(const std::string& client_id, |
201 const std::string& trial_name); | 196 const std::string& trial_name); |
202 | 197 |
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. | 198 // The name of the field trial, as can be found via the FieldTrialList. |
208 const std::string name_; | 199 const std::string name_; |
209 | 200 |
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%. | 201 // The maximum sum of all probabilities supplied, which corresponds to 100%. |
214 // This is the scaling factor used to adjust supplied probabilities. | 202 // This is the scaling factor used to adjust supplied probabilities. |
215 const Probability divisor_; | 203 const Probability divisor_; |
216 | 204 |
217 // The name of the default group. | 205 // The name of the default group. |
218 const std::string default_group_name_; | 206 const std::string default_group_name_; |
219 | 207 |
220 // The randomly selected probability that is used to select a group (or have | 208 // 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 | 209 // the instance not participate). It is the product of divisor_ and a random |
222 // number between [0, 1). | 210 // number between [0, 1). |
223 Probability random_; | 211 Probability random_; |
224 | 212 |
225 // Sum of the probabilities of all appended groups. | 213 // Sum of the probabilities of all appended groups. |
226 Probability accumulated_group_probability_; | 214 Probability accumulated_group_probability_; |
227 | 215 |
228 int next_group_number_; | 216 int next_group_number_; |
229 | 217 |
230 // The pseudo-randomly assigned group number. | 218 // The pseudo-randomly assigned group number. |
231 // This is kNotFinalized if no group has been assigned. | 219 // This is kNotFinalized if no group has been assigned. |
232 int group_; | 220 int group_; |
233 | 221 |
234 // A textual name for the randomly selected group. Valid after |group()| | 222 // A textual name for the randomly selected group. Valid after |group()| |
235 // has been called. | 223 // has been called. |
236 std::string group_name_; | 224 std::string group_name_; |
237 | 225 |
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' | 226 // When enable_field_trial_ is false, field trial reverts to the 'default' |
243 // group. | 227 // group. |
244 bool enable_field_trial_; | 228 bool enable_field_trial_; |
245 | 229 |
246 // When forced_ is true, we return the chosen group from AppendGroup when | 230 // When forced_ is true, we return the chosen group from AppendGroup when |
247 // appropriate. | 231 // appropriate. |
248 bool forced_; | 232 bool forced_; |
249 | 233 |
250 // When benchmarking is enabled, field trials all revert to the 'default' | 234 // When benchmarking is enabled, field trials all revert to the 'default' |
251 // group. | 235 // group. |
252 static bool enable_benchmarking_; | 236 static bool enable_benchmarking_; |
253 | 237 |
254 // This value is reserved for an uninitialized hash value. | |
255 static const uint32 kReservedHashValue; | |
256 | |
257 DISALLOW_COPY_AND_ASSIGN(FieldTrial); | 238 DISALLOW_COPY_AND_ASSIGN(FieldTrial); |
258 }; | 239 }; |
259 | 240 |
260 //------------------------------------------------------------------------------ | 241 //------------------------------------------------------------------------------ |
261 // Class with a list of all active field trials. A trial is active if it has | 242 // 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. | 243 // been registered, which includes evaluating its state based on its probaility. |
263 // Only one instance of this class exists. | 244 // Only one instance of this class exists. |
264 class BASE_EXPORT FieldTrialList { | 245 class BASE_EXPORT FieldTrialList { |
265 public: | 246 public: |
266 // Define a separator character to use when creating a persistent form of an | 247 // 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); | 317 static bool TrialExists(const std::string& name); |
337 | 318 |
338 // Creates a persistent representation of all FieldTrial instances for | 319 // Creates a persistent representation of all FieldTrial instances for |
339 // resurrection in another process. This allows randomization to be done in | 320 // resurrection in another process. This allows randomization to be done in |
340 // one process, and secondary processes can be synchronized on the result. | 321 // 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, | 322 // 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 | 323 // with "/" used to separate all names and to terminate the string. This |
343 // string is parsed by CreateTrialsFromString(). | 324 // string is parsed by CreateTrialsFromString(). |
344 static void StatesToString(std::string* output); | 325 static void StatesToString(std::string* output); |
345 | 326 |
346 // Returns an array of Unique IDs for each Field Trial that has a chosen | 327 // Returns an array of SelectedGroup objects, each representing a chosen Field |
347 // group. Field Trials for which a group has not been chosen yet are NOT | 328 // Trial group. Field Trials for which a group has not been chosen yet are NOT |
348 // returned in this list. | 329 // returned in this list. |
349 static void GetFieldTrialNameGroupIds( | 330 static void GetFieldTrialSelectedGroups( |
350 std::vector<FieldTrial::NameGroupId>* name_group_ids); | 331 std::vector<FieldTrial::SelectedGroup>* selected_groups); |
351 | 332 |
352 // Use a state string (re: StatesToString()) to augment the current list of | 333 // 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 | 334 // 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 | 335 // 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 | 336 // 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 | 337 // process into this non-browser process, but could also be invoked through a |
357 // command line argument to the browser process. | 338 // command line argument to the browser process. |
358 static bool CreateTrialsFromString(const std::string& prior_trials); | 339 static bool CreateTrialsFromString(const std::string& prior_trials); |
359 | 340 |
360 // Create a FieldTrial with the given |name| and using 100% probability for | 341 // 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 | 420 |
440 // List of observers to be notified when a group is selected for a FieldTrial. | 421 // List of observers to be notified when a group is selected for a FieldTrial. |
441 ObserverList<Observer> observer_list_; | 422 ObserverList<Observer> observer_list_; |
442 | 423 |
443 DISALLOW_COPY_AND_ASSIGN(FieldTrialList); | 424 DISALLOW_COPY_AND_ASSIGN(FieldTrialList); |
444 }; | 425 }; |
445 | 426 |
446 } // namespace base | 427 } // namespace base |
447 | 428 |
448 #endif // BASE_METRICS_FIELD_TRIAL_H_ | 429 #endif // BASE_METRICS_FIELD_TRIAL_H_ |
OLD | NEW |