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 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
87 #include "base/time.h" | 87 #include "base/time.h" |
88 | 88 |
89 namespace base { | 89 namespace base { |
90 | 90 |
91 class FieldTrialList; | 91 class FieldTrialList; |
92 | 92 |
93 class BASE_EXPORT FieldTrial : public RefCounted<FieldTrial> { | 93 class BASE_EXPORT FieldTrial : public RefCounted<FieldTrial> { |
94 public: | 94 public: |
95 typedef int Probability; // Probability type for being selected in a trial. | 95 typedef int Probability; // Probability type for being selected in a trial. |
96 | 96 |
97 // EntropyProvider is an interface for providing entropy for one-time | |
98 // randomized (persistent) field trials. | |
99 class BASE_EXPORT EntropyProvider { | |
100 public: | |
101 virtual ~EntropyProvider() {} | |
Ilya Sherman
2012/08/17 07:34:28
nit: Virtual functions should never be inlined.
Alexei Svitkine (slow)
2012/08/17 14:08:59
Done. I also fixed this for FieldTrialList::Observ
| |
102 | |
103 // Returns a double in the range of [0, 1) based on |trial_name| that will | |
104 // be used for the dice roll for the specified field trial. A given instance | |
105 // should always return the same value given the same input |trial_name|. | |
106 virtual double GetEntropyForTrial(const std::string& trial_name) = 0; | |
107 }; | |
108 | |
97 // A pair representing a Field Trial and its selected group. | 109 // A pair representing a Field Trial and its selected group. |
98 struct SelectedGroup { | 110 struct SelectedGroup { |
99 std::string trial; | 111 std::string trial; |
100 std::string group; | 112 std::string group; |
101 }; | 113 }; |
102 | 114 |
103 typedef std::vector<SelectedGroup> SelectedGroups; | 115 typedef std::vector<SelectedGroup> SelectedGroups; |
104 | 116 |
105 // A return value to indicate that a given instance has not yet had a group | 117 // A return value to indicate that a given instance has not yet had a group |
106 // assignment (and hence is not yet participating in the trial). | 118 // assignment (and hence is not yet participating in the trial). |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
181 | 193 |
182 friend class base::FieldTrialList; | 194 friend class base::FieldTrialList; |
183 | 195 |
184 friend class RefCounted<FieldTrial>; | 196 friend class RefCounted<FieldTrial>; |
185 | 197 |
186 // This is the group number of the 'default' group when a choice wasn't forced | 198 // This is the group number of the 'default' group when a choice wasn't forced |
187 // by a call to FieldTrialList::CreateFieldTrial. It is kept private so that | 199 // by a call to FieldTrialList::CreateFieldTrial. It is kept private so that |
188 // consumers don't use it by mistake in cases where the group was forced. | 200 // consumers don't use it by mistake in cases where the group was forced. |
189 static const int kDefaultGroupNumber; | 201 static const int kDefaultGroupNumber; |
190 | 202 |
191 FieldTrial(const std::string& name, | 203 FieldTrial(EntropyProvider* entropy_provider, |
Ilya Sherman
2012/08/17 07:34:28
nit: Unless you're planning to modify the |entropy
Alexei Svitkine (slow)
2012/08/17 14:08:59
Done.
| |
204 const std::string& name, | |
192 Probability total_probability, | 205 Probability total_probability, |
193 const std::string& default_group_name); | 206 const std::string& default_group_name); |
194 virtual ~FieldTrial(); | 207 virtual ~FieldTrial(); |
195 | 208 |
196 // Return the default group name of the FieldTrial. | 209 // Return the default group name of the FieldTrial. |
197 std::string default_group_name() const { return default_group_name_; } | 210 std::string default_group_name() const { return default_group_name_; } |
198 | 211 |
199 // Sets the group_name as well as group_name_hash to make sure they are sync. | 212 // Sets the group_name as well as group_name_hash to make sure they are sync. |
200 void SetGroupChoice(const std::string& name, int number); | 213 void SetGroupChoice(const std::string& name, int number); |
201 | 214 |
202 // Returns the group_name. A winner need not have been chosen. | 215 // Returns the group_name. A winner need not have been chosen. |
203 std::string group_name_internal() const { return group_name_; } | 216 std::string group_name_internal() const { return group_name_; } |
204 | 217 |
205 // Calculates a uniformly-distributed double between [0.0, 1.0) given | 218 // Entropy provider that will be used if the field trial uses one-time |
206 // a |client_id| and a |trial_name| (the latter is used as salt to avoid | 219 // randomization. Weak pointer, owned by FieldTrialList. |
207 // separate one-time randomized trials from all having the same results). | 220 EntropyProvider* entropy_provider_; |
Ilya Sherman
2012/08/17 07:34:28
nit: const EntropyProvider* const?
Alexei Svitkine (slow)
2012/08/17 14:08:59
Done.
| |
208 static double HashClientId(const std::string& client_id, | |
209 const std::string& trial_name); | |
210 | 221 |
211 // The name of the field trial, as can be found via the FieldTrialList. | 222 // The name of the field trial, as can be found via the FieldTrialList. |
212 const std::string name_; | 223 const std::string name_; |
213 | 224 |
214 // The maximum sum of all probabilities supplied, which corresponds to 100%. | 225 // The maximum sum of all probabilities supplied, which corresponds to 100%. |
215 // This is the scaling factor used to adjust supplied probabilities. | 226 // This is the scaling factor used to adjust supplied probabilities. |
216 const Probability divisor_; | 227 const Probability divisor_; |
217 | 228 |
218 // The name of the default group. | 229 // The name of the default group. |
219 const std::string default_group_name_; | 230 const std::string default_group_name_; |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
271 // Notify observers when FieldTrials's group is selected. | 282 // Notify observers when FieldTrials's group is selected. |
272 virtual void OnFieldTrialGroupFinalized(const std::string& trial_name, | 283 virtual void OnFieldTrialGroupFinalized(const std::string& trial_name, |
273 const std::string& group_name) = 0; | 284 const std::string& group_name) = 0; |
274 | 285 |
275 protected: | 286 protected: |
276 virtual ~Observer() {} | 287 virtual ~Observer() {} |
277 }; | 288 }; |
278 | 289 |
279 // This singleton holds the global list of registered FieldTrials. | 290 // This singleton holds the global list of registered FieldTrials. |
280 // | 291 // |
281 // |client_id| should be an opaque, diverse ID for this client that does not | 292 // To support one-time randomized field trials, specify a non-NULL |
282 // change between sessions, to enable one-time randomized trials. The empty | 293 // |entropy_provider| which should be a source of uniformly distributed |
283 // string may be provided, in which case one-time randomized trials will | 294 // entropy values. |
284 // not be available. | 295 explicit FieldTrialList(FieldTrial::EntropyProvider* entropy_provider); |
285 explicit FieldTrialList(const std::string& client_id); | 296 |
286 // Destructor Release()'s references to all registered FieldTrial instances. | 297 // Destructor Release()'s references to all registered FieldTrial instances. |
287 ~FieldTrialList(); | 298 ~FieldTrialList(); |
288 | 299 |
289 // Get a FieldTrial instance from the factory. | 300 // Get a FieldTrial instance from the factory. |
290 // | 301 // |
291 // |name| is used to register the instance with the FieldTrialList class, | 302 // |name| is used to register the instance with the FieldTrialList class, |
292 // and can be used to find the trial (only one trial can be present for each | 303 // and can be used to find the trial (only one trial can be present for each |
293 // name). |default_group_name| is the name of the default group which will | 304 // name). |default_group_name| is the name of the default group which will |
294 // be chosen if none of the subsequent appended groups get to be chosen. | 305 // be chosen if none of the subsequent appended groups get to be chosen. |
295 // |default_group_number| can receive the group number of the default group as | 306 // |default_group_number| can receive the group number of the default group as |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
386 } | 397 } |
387 | 398 |
388 // Return the number of active field trials. | 399 // Return the number of active field trials. |
389 static size_t GetFieldTrialCount(); | 400 static size_t GetFieldTrialCount(); |
390 | 401 |
391 // Returns true if you can call |FieldTrial::UseOneTimeRandomization()| | 402 // Returns true if you can call |FieldTrial::UseOneTimeRandomization()| |
392 // without error, i.e. if a non-empty string was provided as the client_id | 403 // without error, i.e. if a non-empty string was provided as the client_id |
393 // when constructing the FieldTrialList singleton. | 404 // when constructing the FieldTrialList singleton. |
394 static bool IsOneTimeRandomizationEnabled(); | 405 static bool IsOneTimeRandomizationEnabled(); |
395 | 406 |
396 // Returns an opaque, diverse ID for this client that does not change | |
397 // between sessions. | |
398 // | |
399 // Returns the empty string if one-time randomization is not enabled. | |
400 static const std::string& client_id(); | |
401 | |
402 private: | 407 private: |
403 // A map from FieldTrial names to the actual instances. | 408 // A map from FieldTrial names to the actual instances. |
404 typedef std::map<std::string, FieldTrial*> RegistrationList; | 409 typedef std::map<std::string, FieldTrial*> RegistrationList; |
405 | 410 |
406 // Helper function should be called only while holding lock_. | 411 // Helper function should be called only while holding lock_. |
407 FieldTrial* PreLockedFind(const std::string& name); | 412 FieldTrial* PreLockedFind(const std::string& name); |
408 | 413 |
409 // Register() stores a pointer to the given trial in a global map. | 414 // Register() stores a pointer to the given trial in a global map. |
410 // This method also AddRef's the indicated trial. | 415 // This method also AddRef's the indicated trial. |
411 // This should always be called after creating a new FieldTrial instance. | 416 // This should always be called after creating a new FieldTrial instance. |
412 static void Register(FieldTrial* trial); | 417 static void Register(FieldTrial* trial); |
413 | 418 |
414 static FieldTrialList* global_; // The singleton of this class. | 419 static FieldTrialList* global_; // The singleton of this class. |
415 | 420 |
416 // This will tell us if there is an attempt to register a field | 421 // This will tell us if there is an attempt to register a field |
417 // trial or check if one-time randomization is enabled without | 422 // trial or check if one-time randomization is enabled without |
418 // creating the FieldTrialList. This is not an error, unless a | 423 // creating the FieldTrialList. This is not an error, unless a |
419 // FieldTrialList is created after that. | 424 // FieldTrialList is created after that. |
420 static bool used_without_global_; | 425 static bool used_without_global_; |
421 | 426 |
422 // A helper value made available to users, that shows when the FieldTrialList | 427 // A helper value made available to users, that shows when the FieldTrialList |
423 // was initialized. Note that this is a singleton instance, and hence is a | 428 // was initialized. Note that this is a singleton instance, and hence is a |
424 // good approximation to the start of the process. | 429 // good approximation to the start of the process. |
425 TimeTicks application_start_time_; | 430 TimeTicks application_start_time_; |
426 | 431 |
427 // Lock for access to registered_. | 432 // Lock for access to registered_. |
428 base::Lock lock_; | 433 base::Lock lock_; |
429 RegistrationList registered_; | 434 RegistrationList registered_; |
430 | 435 |
431 // An opaque, diverse ID for this client that does not change | 436 // Entropy provider to be used for one-time randomized field trials. If NULL, |
432 // between sessions, or the empty string if not initialized. | 437 // one-time randomization is not supported. |
433 std::string client_id_; | 438 scoped_ptr<FieldTrial::EntropyProvider> entropy_provider_; |
434 | 439 |
435 // List of observers to be notified when a group is selected for a FieldTrial. | 440 // List of observers to be notified when a group is selected for a FieldTrial. |
436 scoped_refptr<ObserverListThreadSafe<Observer> > observer_list_; | 441 scoped_refptr<ObserverListThreadSafe<Observer> > observer_list_; |
437 | 442 |
438 DISALLOW_COPY_AND_ASSIGN(FieldTrialList); | 443 DISALLOW_COPY_AND_ASSIGN(FieldTrialList); |
439 }; | 444 }; |
440 | 445 |
441 } // namespace base | 446 } // namespace base |
442 | 447 |
443 #endif // BASE_METRICS_FIELD_TRIAL_H_ | 448 #endif // BASE_METRICS_FIELD_TRIAL_H_ |
OLD | NEW |