| 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 |
| 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 |