Chromium Code Reviews| 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(); | |
| 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) const = 0; | |
| 107 }; | |
|
jar (doing other things)
2012/08/17 19:06:19
Please add DISALLOW_COPY_AND_ASSIGN(..)
Alexei Svitkine (slow)
2012/08/20 15:57:40
We don't usually do this for pure interface classe
| |
| 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(const EntropyProvider* entropy_provider, |
|
jar (doing other things)
2012/08/17 19:06:19
nit: add comment that |entropy_provider_| is null
Alexei Svitkine (slow)
2012/08/20 15:57:40
No longer needed since the param is removed.
| |
| 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 const EntropyProvider* const entropy_provider_; |
|
jar (doing other things)
2012/08/17 19:06:19
Why is this needed on a per-FieldTrial basis? I w
Alexei Svitkine (slow)
2012/08/20 15:57:40
The entropy provider is responsible for providing
| |
| 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 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 266 static int kExpirationYearInFuture; | 277 static int kExpirationYearInFuture; |
| 267 | 278 |
| 268 // Observer is notified when a FieldTrial's group is selected. | 279 // Observer is notified when a FieldTrial's group is selected. |
| 269 class BASE_EXPORT Observer { | 280 class BASE_EXPORT Observer { |
| 270 public: | 281 public: |
| 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. Takes ownership of |entropy_provider|. |
|
jar (doing other things)
2012/08/17 19:06:19
nit: Comment should be explicit that a NULL value
Alexei Svitkine (slow)
2012/08/20 15:57:40
Done.
| |
| 284 // not be available. | 295 explicit FieldTrialList(FieldTrial::EntropyProvider* entropy_provider); |
|
Ilya Sherman
2012/08/17 17:53:20
Optional nit: I would pass this in as a scoped_ptr
Alexei Svitkine (slow)
2012/08/17 17:58:58
I tried that, but then FieldTrialList(NULL) doesn'
Ilya Sherman
2012/08/17 18:16:55
How about FieldTrialList<scoped_ptr<FieldTrial::En
| |
| 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 |