Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(389)

Side by Side Diff: base/metrics/field_trial.cc

Issue 6931048: Revert 84197 - Add one-time randomization support for FieldTrial, and the ability to (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 9 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « base/metrics/field_trial.h ('k') | base/metrics/field_trial_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 #include "base/metrics/field_trial.h" 5 #include "base/metrics/field_trial.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "base/rand_util.h" 8 #include "base/rand_util.h"
9 #include "base/sha1.h"
10 #include "base/string_util.h"
11 #include "base/stringprintf.h" 9 #include "base/stringprintf.h"
12 #include "base/utf_string_conversions.h" 10 #include "base/utf_string_conversions.h"
13 11
14 namespace base { 12 namespace base {
15 13
16 // static 14 // static
17 const int FieldTrial::kNotFinalized = -1; 15 const int FieldTrial::kNotFinalized = -1;
18 16
19 // static 17 // static
20 const int FieldTrial::kDefaultGroupNumber = 0; 18 const int FieldTrial::kDefaultGroupNumber = 0;
(...skipping 15 matching lines...) Expand all
36 34
37 FieldTrial::FieldTrial(const std::string& name, 35 FieldTrial::FieldTrial(const std::string& name,
38 const Probability total_probability, 36 const Probability total_probability,
39 const std::string& default_group_name, 37 const std::string& default_group_name,
40 const int year, 38 const int year,
41 const int month, 39 const int month,
42 const int day_of_month) 40 const int day_of_month)
43 : name_(name), 41 : name_(name),
44 divisor_(total_probability), 42 divisor_(total_probability),
45 default_group_name_(default_group_name), 43 default_group_name_(default_group_name),
46 random_(static_cast<Probability>(divisor_ * RandDouble())), 44 random_(static_cast<Probability>(divisor_ * base::RandDouble())),
47 accumulated_group_probability_(0), 45 accumulated_group_probability_(0),
48 next_group_number_(kDefaultGroupNumber + 1), 46 next_group_number_(kDefaultGroupNumber+1),
49 group_(kNotFinalized), 47 group_(kNotFinalized) {
50 enable_field_trial_(true) {
51 DCHECK_GT(total_probability, 0); 48 DCHECK_GT(total_probability, 0);
52 DCHECK(!name_.empty());
53 DCHECK(!default_group_name_.empty()); 49 DCHECK(!default_group_name_.empty());
54 FieldTrialList::Register(this); 50 FieldTrialList::Register(this);
55 51
56 DCHECK_GT(year, 1970); 52 DCHECK_GT(year, 1970);
57 DCHECK_GT(month, 0); 53 DCHECK_GT(month, 0);
58 DCHECK_LT(month, 13); 54 DCHECK_LT(month, 13);
59 DCHECK_GT(day_of_month, 0); 55 DCHECK_GT(day_of_month, 0);
60 DCHECK_LT(day_of_month, 32); 56 DCHECK_LT(day_of_month, 32);
61 57
62 Time::Exploded exploded; 58 base::Time::Exploded exploded;
63 exploded.year = year; 59 exploded.year = year;
64 exploded.month = month; 60 exploded.month = month;
65 exploded.day_of_week = 0; // Should be unused. 61 exploded.day_of_week = 0; // Should be unused.
66 exploded.day_of_month = day_of_month; 62 exploded.day_of_month = day_of_month;
67 exploded.hour = 0; 63 exploded.hour = 0;
68 exploded.minute = 0; 64 exploded.minute = 0;
69 exploded.second = 0; 65 exploded.second = 0;
70 exploded.millisecond = 0; 66 exploded.millisecond = 0;
71 67
72 Time expiration_time = Time::FromLocalExploded(exploded); 68 base::Time expiration_time = Time::FromLocalExploded(exploded);
73 if (GetBuildTime() > expiration_time) 69 disable_field_trial_ = (GetBuildTime() > expiration_time) ? true : false;
74 Disable();
75 }
76
77 void FieldTrial::UseOneTimeRandomization() {
78 DCHECK_EQ(group_, kNotFinalized);
79 DCHECK_EQ(kDefaultGroupNumber + 1, next_group_number_);
80 if (!FieldTrialList::IsOneTimeRandomizationEnabled()) {
81 NOTREACHED();
82 Disable();
83 return;
84 }
85
86 random_ = static_cast<Probability>(
87 divisor_ * HashClientId(FieldTrialList::client_id(), name_));
88 }
89
90 void FieldTrial::Disable() {
91 enable_field_trial_ = false;
92
93 // In case we are disabled after initialization, we need to switch
94 // the trial to the default group.
95 if (group_ != kNotFinalized) {
96 group_ = kDefaultGroupNumber;
97 group_name_ = default_group_name_;
98 }
99 } 70 }
100 71
101 int FieldTrial::AppendGroup(const std::string& name, 72 int FieldTrial::AppendGroup(const std::string& name,
102 Probability group_probability) { 73 Probability group_probability) {
103 DCHECK_LE(group_probability, divisor_); 74 DCHECK_LE(group_probability, divisor_);
104 DCHECK_GE(group_probability, 0); 75 DCHECK_GE(group_probability, 0);
105 76
106 if (enable_benchmarking_ || !enable_field_trial_) 77 if (enable_benchmarking_ || disable_field_trial_)
107 group_probability = 0; 78 group_probability = 0;
108 79
109 accumulated_group_probability_ += group_probability; 80 accumulated_group_probability_ += group_probability;
110 81
111 DCHECK_LE(accumulated_group_probability_, divisor_); 82 DCHECK_LE(accumulated_group_probability_, divisor_);
112 if (group_ == kNotFinalized && accumulated_group_probability_ > random_) { 83 if (group_ == kNotFinalized && accumulated_group_probability_ > random_) {
113 // This is the group that crossed the random line, so we do the assignment. 84 // This is the group that crossed the random line, so we do the assignment.
114 group_ = next_group_number_; 85 group_ = next_group_number_;
115 if (name.empty()) 86 if (name.empty())
116 StringAppendF(&group_name_, "%d", group_); 87 base::StringAppendF(&group_name_, "%d", group_);
117 else 88 else
118 group_name_ = name; 89 group_name_ = name;
119 FieldTrialList::NotifyFieldTrialGroupSelection(name_, group_name_); 90 FieldTrialList::NotifyFieldTrialGroupSelection(name_, group_name_);
120 } 91 }
121 return next_group_number_++; 92 return next_group_number_++;
122 } 93 }
123 94
124 int FieldTrial::group() { 95 int FieldTrial::group() {
125 if (group_ == kNotFinalized) { 96 if (group_ == kNotFinalized) {
126 accumulated_group_probability_ = divisor_; 97 accumulated_group_probability_ = divisor_;
127 group_ = kDefaultGroupNumber; 98 group_ = kDefaultGroupNumber;
128 group_name_ = default_group_name_; 99 group_name_ = default_group_name_;
129 FieldTrialList::NotifyFieldTrialGroupSelection(name_, group_name_); 100 FieldTrialList::NotifyFieldTrialGroupSelection(name_, group_name_);
130 } 101 }
131 return group_; 102 return group_;
132 } 103 }
133 104
134 std::string FieldTrial::group_name() { 105 std::string FieldTrial::group_name() {
135 group(); // call group() to make sure group assignment was done. 106 group(); // call group() to make group assignment was done.
136 DCHECK(!group_name_.empty());
137 return group_name_; 107 return group_name_;
138 } 108 }
139 109
140 // static 110 // static
141 std::string FieldTrial::MakeName(const std::string& name_prefix, 111 std::string FieldTrial::MakeName(const std::string& name_prefix,
142 const std::string& trial_name) { 112 const std::string& trial_name) {
143 std::string big_string(name_prefix); 113 std::string big_string(name_prefix);
144 big_string.append(1, kHistogramFieldTrialSeparator); 114 big_string.append(1, kHistogramFieldTrialSeparator);
145 return big_string.append(FieldTrialList::FindFullName(trial_name)); 115 return big_string.append(FieldTrialList::FindFullName(trial_name));
146 } 116 }
147 117
148 // static 118 // static
149 void FieldTrial::EnableBenchmarking() { 119 void FieldTrial::EnableBenchmarking() {
150 DCHECK_EQ(0u, FieldTrialList::GetFieldTrialCount()); 120 DCHECK_EQ(0u, FieldTrialList::GetFieldTrialCount());
151 enable_benchmarking_ = true; 121 enable_benchmarking_ = true;
152 } 122 }
153 123
154 FieldTrial::~FieldTrial() {} 124 FieldTrial::~FieldTrial() {}
155 125
156 // static 126 // static
157 Time FieldTrial::GetBuildTime() { 127 Time FieldTrial::GetBuildTime() {
158 Time integral_build_time; 128 Time integral_build_time;
159 const char* kDateTime = __DATE__ " " __TIME__; 129 const char* kDateTime = __DATE__ " " __TIME__;
160 bool result = Time::FromString(ASCIIToWide(kDateTime).c_str(), 130 bool result = Time::FromString(ASCIIToWide(kDateTime).c_str(),
161 &integral_build_time); 131 &integral_build_time);
162 DCHECK(result); 132 DCHECK(result);
163 return integral_build_time; 133 return integral_build_time;
164 } 134 }
165 135
166 // static
167 double FieldTrial::HashClientId(const std::string& client_id,
168 const std::string& trial_name) {
169 // SHA-1 is designed to produce a uniformly random spread in its output space,
170 // even for nearly-identical inputs, so it helps massage whatever client_id
171 // and trial_name we get into something with a uniform distribution, which
172 // is desirable so that we don't skew any part of the 0-100% spectrum.
173 std::string input(client_id + trial_name);
174 unsigned char sha1_hash[SHA1_LENGTH];
175 SHA1HashBytes(reinterpret_cast<const unsigned char*>(input.c_str()),
176 input.size(),
177 sha1_hash);
178
179 COMPILE_ASSERT(sizeof(uint64) < sizeof(sha1_hash), need_more_data);
180 uint64* bits = reinterpret_cast<uint64*>(&sha1_hash[0]);
181
182 return BitsToOpenEndedUnitInterval(*bits);
183 }
184
185 //------------------------------------------------------------------------------ 136 //------------------------------------------------------------------------------
186 // FieldTrialList methods and members. 137 // FieldTrialList methods and members.
187 138
188 // static 139 // static
189 FieldTrialList* FieldTrialList::global_ = NULL; 140 FieldTrialList* FieldTrialList::global_ = NULL;
190 141
191 // static 142 // static
192 bool FieldTrialList::register_without_global_ = false; 143 bool FieldTrialList::register_without_global_ = false;
193 144
194 FieldTrialList::FieldTrialList(const std::string& client_id) 145 FieldTrialList::FieldTrialList()
195 : application_start_time_(TimeTicks::Now()), 146 : application_start_time_(TimeTicks::Now()),
196 client_id_(client_id),
197 observer_list_(ObserverList<Observer>::NOTIFY_EXISTING_ONLY) { 147 observer_list_(ObserverList<Observer>::NOTIFY_EXISTING_ONLY) {
198 DCHECK(!global_); 148 DCHECK(!global_);
199 DCHECK(!register_without_global_); 149 DCHECK(!register_without_global_);
200 global_ = this; 150 global_ = this;
201 151
202 Time::Exploded exploded; 152 Time::Exploded exploded;
203 Time two_years_from_now = 153 Time two_years_from_now =
204 Time::NowFromSystemTime() + TimeDelta::FromDays(730); 154 Time::NowFromSystemTime() + TimeDelta::FromDays(730);
205 two_years_from_now.LocalExplode(&exploded); 155 two_years_from_now.LocalExplode(&exploded);
206 kExpirationYearInFuture = exploded.year; 156 kExpirationYearInFuture = exploded.year;
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
247 197
248 // static 198 // static
249 std::string FieldTrialList::FindFullName(const std::string& name) { 199 std::string FieldTrialList::FindFullName(const std::string& name) {
250 FieldTrial* field_trial = Find(name); 200 FieldTrial* field_trial = Find(name);
251 if (field_trial) 201 if (field_trial)
252 return field_trial->group_name(); 202 return field_trial->group_name();
253 return ""; 203 return "";
254 } 204 }
255 205
256 // static 206 // static
257 bool FieldTrialList::TrialExists(const std::string& name) {
258 return Find(name) != NULL;
259 }
260
261 // static
262 void FieldTrialList::StatesToString(std::string* output) { 207 void FieldTrialList::StatesToString(std::string* output) {
263 if (!global_) 208 if (!global_)
264 return; 209 return;
265 DCHECK(output->empty()); 210 DCHECK(output->empty());
266 AutoLock auto_lock(global_->lock_); 211 AutoLock auto_lock(global_->lock_);
267
268 for (RegistrationList::iterator it = global_->registered_.begin(); 212 for (RegistrationList::iterator it = global_->registered_.begin();
269 it != global_->registered_.end(); ++it) { 213 it != global_->registered_.end(); ++it) {
270 const std::string name = it->first; 214 const std::string name = it->first;
271 std::string group_name = it->second->group_name_internal(); 215 std::string group_name = it->second->group_name_internal();
272 if (group_name.empty()) 216 if (group_name.empty())
273 continue; // Should not include uninitialized trials. 217 // No definitive winner in this trial, use default_group_name as the
218 // group_name.
219 group_name = it->second->default_group_name();
274 DCHECK_EQ(name.find(kPersistentStringSeparator), std::string::npos); 220 DCHECK_EQ(name.find(kPersistentStringSeparator), std::string::npos);
275 DCHECK_EQ(group_name.find(kPersistentStringSeparator), std::string::npos); 221 DCHECK_EQ(group_name.find(kPersistentStringSeparator), std::string::npos);
276 output->append(name); 222 output->append(name);
277 output->append(1, kPersistentStringSeparator); 223 output->append(1, kPersistentStringSeparator);
278 output->append(group_name); 224 output->append(group_name);
279 output->append(1, kPersistentStringSeparator); 225 output->append(1, kPersistentStringSeparator);
280 } 226 }
281 } 227 }
282 228
283 // static 229 // static
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
360 } 306 }
361 307
362 // static 308 // static
363 size_t FieldTrialList::GetFieldTrialCount() { 309 size_t FieldTrialList::GetFieldTrialCount() {
364 if (!global_) 310 if (!global_)
365 return 0; 311 return 0;
366 AutoLock auto_lock(global_->lock_); 312 AutoLock auto_lock(global_->lock_);
367 return global_->registered_.size(); 313 return global_->registered_.size();
368 } 314 }
369 315
370 // static
371 bool FieldTrialList::IsOneTimeRandomizationEnabled() {
372 DCHECK(global_);
373 if (!global_)
374 return false;
375
376 return !global_->client_id_.empty();
377 }
378
379 // static
380 const std::string& FieldTrialList::client_id() {
381 DCHECK(global_);
382 if (!global_)
383 return EmptyString();
384
385 return global_->client_id_;
386 }
387
388 FieldTrial* FieldTrialList::PreLockedFind(const std::string& name) { 316 FieldTrial* FieldTrialList::PreLockedFind(const std::string& name) {
389 RegistrationList::iterator it = registered_.find(name); 317 RegistrationList::iterator it = registered_.find(name);
390 if (registered_.end() == it) 318 if (registered_.end() == it)
391 return NULL; 319 return NULL;
392 return it->second; 320 return it->second;
393 } 321 }
394 322
395 } // namespace base 323 } // namespace base
OLDNEW
« no previous file with comments | « base/metrics/field_trial.h ('k') | base/metrics/field_trial_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698