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

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

Issue 10830318: Use a different algorithm with the low entropy source for field trials. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 4 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) 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 #include "base/metrics/field_trial.h" 5 #include "base/metrics/field_trial.h"
6 6
7 #include "base/build_time.h" 7 #include "base/build_time.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/rand_util.h" 9 #include "base/rand_util.h"
10 #include "base/sha1.h" 10 #include "base/sha1.h"
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
49 49
50 const char FieldTrialList::kPersistentStringSeparator('/'); 50 const char FieldTrialList::kPersistentStringSeparator('/');
51 int FieldTrialList::kExpirationYearInFuture = 0; 51 int FieldTrialList::kExpirationYearInFuture = 0;
52 52
53 //------------------------------------------------------------------------------ 53 //------------------------------------------------------------------------------
54 // FieldTrial methods and members. 54 // FieldTrial methods and members.
55 55
56 FieldTrial::FieldTrial(const std::string& name, 56 FieldTrial::FieldTrial(const std::string& name,
57 const Probability total_probability, 57 const Probability total_probability,
58 const std::string& default_group_name) 58 const std::string& default_group_name)
59 : name_(name), 59 : name_(name),
60 divisor_(total_probability), 60 divisor_(total_probability),
61 default_group_name_(default_group_name), 61 default_group_name_(default_group_name),
62 random_(static_cast<Probability>(divisor_ * RandDouble())), 62 random_(static_cast<Probability>(divisor_ * RandDouble())),
63 accumulated_group_probability_(0), 63 accumulated_group_probability_(0),
64 next_group_number_(kDefaultGroupNumber + 1), 64 next_group_number_(kDefaultGroupNumber + 1),
65 group_(kNotFinalized), 65 group_(kNotFinalized),
66 enable_field_trial_(true), 66 enable_field_trial_(true),
67 forced_(false) { 67 forced_(false) {
68 DCHECK_GT(total_probability, 0); 68 DCHECK_GT(total_probability, 0);
69 DCHECK(!name_.empty()); 69 DCHECK(!name_.empty());
70 DCHECK(!default_group_name_.empty()); 70 DCHECK(!default_group_name_.empty());
71 } 71 }
72 72
73 FieldTrial::EntropyProvider::~EntropyProvider() {
74 }
75
73 void FieldTrial::UseOneTimeRandomization() { 76 void FieldTrial::UseOneTimeRandomization() {
74 // No need to specify randomization when the group choice was forced. 77 // No need to specify randomization when the group choice was forced.
75 if (forced_) 78 if (forced_)
76 return; 79 return;
77 DCHECK_EQ(group_, kNotFinalized); 80 DCHECK_EQ(group_, kNotFinalized);
78 DCHECK_EQ(kDefaultGroupNumber + 1, next_group_number_); 81 DCHECK_EQ(kDefaultGroupNumber + 1, next_group_number_);
79 if (!FieldTrialList::IsOneTimeRandomizationEnabled()) { 82 const EntropyProvider* entropy_provider =
83 FieldTrialList::GetEntropyProviderForOneTimeRandomization();
84 if (!entropy_provider) {
80 NOTREACHED(); 85 NOTREACHED();
81 Disable(); 86 Disable();
82 return; 87 return;
83 } 88 }
84 89
85 random_ = static_cast<Probability>( 90 random_ = static_cast<Probability>(
86 divisor_ * HashClientId(FieldTrialList::client_id(), name_)); 91 divisor_ * entropy_provider->GetEntropyForTrial(name_));
87 } 92 }
88 93
89 void FieldTrial::Disable() { 94 void FieldTrial::Disable() {
90 enable_field_trial_ = false; 95 enable_field_trial_ = false;
91 96
92 // In case we are disabled after initialization, we need to switch 97 // In case we are disabled after initialization, we need to switch
93 // the trial to the default group. 98 // the trial to the default group.
94 if (group_ != kNotFinalized) { 99 if (group_ != kNotFinalized) {
95 // Only reset when not already the default group, because in case we were 100 // Only reset when not already the default group, because in case we were
96 // forced to the default group, the group number may not be 101 // forced to the default group, the group number may not be
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
191 196
192 void FieldTrial::SetGroupChoice(const std::string& name, int number) { 197 void FieldTrial::SetGroupChoice(const std::string& name, int number) {
193 group_ = number; 198 group_ = number;
194 if (name.empty()) 199 if (name.empty())
195 StringAppendF(&group_name_, "%d", group_); 200 StringAppendF(&group_name_, "%d", group_);
196 else 201 else
197 group_name_ = name; 202 group_name_ = name;
198 DVLOG(1) << "Field trial: " << name_ << " Group choice:" << group_name_; 203 DVLOG(1) << "Field trial: " << name_ << " Group choice:" << group_name_;
199 } 204 }
200 205
201 // static
202 double FieldTrial::HashClientId(const std::string& client_id,
203 const std::string& trial_name) {
204 // SHA-1 is designed to produce a uniformly random spread in its output space,
205 // even for nearly-identical inputs, so it helps massage whatever client_id
206 // and trial_name we get into something with a uniform distribution, which
207 // is desirable so that we don't skew any part of the 0-100% spectrum.
208 std::string input(client_id + trial_name);
209 unsigned char sha1_hash[kSHA1Length];
210 SHA1HashBytes(reinterpret_cast<const unsigned char*>(input.c_str()),
211 input.size(),
212 sha1_hash);
213
214 COMPILE_ASSERT(sizeof(uint64) < sizeof(sha1_hash), need_more_data);
215 uint64 bits;
216 memcpy(&bits, sha1_hash, sizeof(bits));
217 bits = base::ByteSwapToLE64(bits);
218
219 return BitsToOpenEndedUnitInterval(bits);
220 }
221
222 //------------------------------------------------------------------------------ 206 //------------------------------------------------------------------------------
223 // FieldTrialList methods and members. 207 // FieldTrialList methods and members.
224 208
225 // static 209 // static
226 FieldTrialList* FieldTrialList::global_ = NULL; 210 FieldTrialList* FieldTrialList::global_ = NULL;
227 211
228 // static 212 // static
229 bool FieldTrialList::used_without_global_ = false; 213 bool FieldTrialList::used_without_global_ = false;
230 214
231 FieldTrialList::FieldTrialList(const std::string& client_id) 215 FieldTrialList::Observer::~Observer() {
216 }
217
218 FieldTrialList::FieldTrialList(
219 const FieldTrial::EntropyProvider* entropy_provider)
232 : application_start_time_(TimeTicks::Now()), 220 : application_start_time_(TimeTicks::Now()),
233 client_id_(client_id), 221 entropy_provider_(entropy_provider),
234 observer_list_(new ObserverListThreadSafe<FieldTrialList::Observer>( 222 observer_list_(new ObserverListThreadSafe<FieldTrialList::Observer>(
235 ObserverListBase<FieldTrialList::Observer>::NOTIFY_EXISTING_ONLY)) { 223 ObserverListBase<FieldTrialList::Observer>::NOTIFY_EXISTING_ONLY)) {
236 DCHECK(!global_); 224 DCHECK(!global_);
237 DCHECK(!used_without_global_); 225 DCHECK(!used_without_global_);
238 global_ = this; 226 global_ = this;
239 227
240 Time::Exploded exploded; 228 Time::Exploded exploded;
241 Time two_years_from_now = 229 Time two_years_from_now =
242 Time::NowFromSystemTime() + TimeDelta::FromDays(730); 230 Time::NowFromSystemTime() + TimeDelta::FromDays(730);
243 two_years_from_now.LocalExplode(&exploded); 231 two_years_from_now.LocalExplode(&exploded);
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after
439 427
440 // static 428 // static
441 size_t FieldTrialList::GetFieldTrialCount() { 429 size_t FieldTrialList::GetFieldTrialCount() {
442 if (!global_) 430 if (!global_)
443 return 0; 431 return 0;
444 AutoLock auto_lock(global_->lock_); 432 AutoLock auto_lock(global_->lock_);
445 return global_->registered_.size(); 433 return global_->registered_.size();
446 } 434 }
447 435
448 // static 436 // static
437 const FieldTrial::EntropyProvider*
438 FieldTrialList::GetEntropyProviderForOneTimeRandomization() {
439 if (!global_) {
440 used_without_global_ = true;
441 return NULL;
442 }
443
444 return global_->entropy_provider_.get();
445 }
446
447 // static
449 bool FieldTrialList::IsOneTimeRandomizationEnabled() { 448 bool FieldTrialList::IsOneTimeRandomizationEnabled() {
450 if (!global_) { 449 return GetEntropyProviderForOneTimeRandomization() != NULL;
451 used_without_global_ = true;
452 return false;
453 }
454
455 return !global_->client_id_.empty();
456 }
457
458 // static
459 const std::string& FieldTrialList::client_id() {
460 DCHECK(global_);
461 if (!global_)
462 return EmptyString();
463
464 return global_->client_id_;
465 } 450 }
466 451
467 FieldTrial* FieldTrialList::PreLockedFind(const std::string& name) { 452 FieldTrial* FieldTrialList::PreLockedFind(const std::string& name) {
468 RegistrationList::iterator it = registered_.find(name); 453 RegistrationList::iterator it = registered_.find(name);
469 if (registered_.end() == it) 454 if (registered_.end() == it)
470 return NULL; 455 return NULL;
471 return it->second; 456 return it->second;
472 } 457 }
473 458
474 // static 459 // static
475 void FieldTrialList::Register(FieldTrial* trial) { 460 void FieldTrialList::Register(FieldTrial* trial) {
476 if (!global_) { 461 if (!global_) {
477 used_without_global_ = true; 462 used_without_global_ = true;
478 return; 463 return;
479 } 464 }
480 AutoLock auto_lock(global_->lock_); 465 AutoLock auto_lock(global_->lock_);
481 DCHECK(!global_->PreLockedFind(trial->name())); 466 DCHECK(!global_->PreLockedFind(trial->name()));
482 trial->AddRef(); 467 trial->AddRef();
483 global_->registered_[trial->name()] = trial; 468 global_->registered_[trial->name()] = trial;
484 } 469 }
485 470
486 } // namespace base 471 } // 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