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