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 |