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

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

Issue 6883102: 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, 8 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
OLDNEW
1 // Copyright (c) 2010 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/file_util.h"
7 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/pickle.h"
8 #include "base/rand_util.h" 10 #include "base/rand_util.h"
11 #include "base/sha1.h"
9 #include "base/stringprintf.h" 12 #include "base/stringprintf.h"
10 #include "base/utf_string_conversions.h" 13 #include "base/utf_string_conversions.h"
11 14
12 namespace base { 15 namespace base {
13 16
14 // static 17 // static
15 const int FieldTrial::kNotFinalized = -1; 18 const int FieldTrial::kNotFinalized = -1;
16 19
17 // static 20 // static
18 const int FieldTrial::kDefaultGroupNumber = 0; 21 const int FieldTrial::kDefaultGroupNumber = 0;
(...skipping 11 matching lines...) Expand all
30 33
31 FieldTrial::FieldTrial(const std::string& name, 34 FieldTrial::FieldTrial(const std::string& name,
32 const Probability total_probability, 35 const Probability total_probability,
33 const std::string& default_group_name, 36 const std::string& default_group_name,
34 const int year, 37 const int year,
35 const int month, 38 const int month,
36 const int day_of_month) 39 const int day_of_month)
37 : name_(name), 40 : name_(name),
38 divisor_(total_probability), 41 divisor_(total_probability),
39 default_group_name_(default_group_name), 42 default_group_name_(default_group_name),
40 random_(static_cast<Probability>(divisor_ * base::RandDouble())), 43 random_(static_cast<Probability>(divisor_ * RandDouble())),
41 accumulated_group_probability_(0), 44 accumulated_group_probability_(0),
42 next_group_number_(kDefaultGroupNumber+1), 45 next_group_number_(kDefaultGroupNumber+1),
43 group_(kNotFinalized) { 46 group_(kNotFinalized),
47 disable_field_trial_(false) {
44 DCHECK_GT(total_probability, 0); 48 DCHECK_GT(total_probability, 0);
45 DCHECK(!default_group_name_.empty()); 49 DCHECK(!default_group_name_.empty());
46 FieldTrialList::Register(this); 50 FieldTrialList::Register(this);
47 51
48 DCHECK_GT(year, 1970); 52 DCHECK_GT(year, 1970);
49 DCHECK_GT(month, 0); 53 DCHECK_GT(month, 0);
50 DCHECK_LT(month, 13); 54 DCHECK_LT(month, 13);
51 DCHECK_GT(day_of_month, 0); 55 DCHECK_GT(day_of_month, 0);
52 DCHECK_LT(day_of_month, 32); 56 DCHECK_LT(day_of_month, 32);
53 57
54 base::Time::Exploded exploded; 58 Time::Exploded exploded;
55 exploded.year = year; 59 exploded.year = year;
56 exploded.month = month; 60 exploded.month = month;
57 exploded.day_of_week = 0; // Should be unused. 61 exploded.day_of_week = 0; // Should be unused.
58 exploded.day_of_month = day_of_month; 62 exploded.day_of_month = day_of_month;
59 exploded.hour = 0; 63 exploded.hour = 0;
60 exploded.minute = 0; 64 exploded.minute = 0;
61 exploded.second = 0; 65 exploded.second = 0;
62 exploded.millisecond = 0; 66 exploded.millisecond = 0;
63 67
64 base::Time expiration_time = Time::FromLocalExploded(exploded); 68 Time expiration_time = Time::FromLocalExploded(exploded);
65 disable_field_trial_ = (GetBuildTime() > expiration_time) ? true : false; 69 if (GetBuildTime() > expiration_time) {
70 Disable();
71 }
jar (doing other things) 2011/04/21 01:03:50 style nit: Don't bother with braces on one line if
Jói 2011/04/21 19:50:33 Done.
72 }
73
74 void FieldTrial::UseOneTimeRandomization(const std::string& machine_id) {
75 DCHECK_EQ(group_, kNotFinalized);
76 if (machine_id.empty()) {
77 NOTREACHED();
78 disable_field_trial_ = true;
79 return;
80 }
81
82 random_ = static_cast<Probability>(
83 divisor_ * MachineIdToUniformDouble(machine_id));
jar (doing other things) 2011/04/21 01:03:50 Is your hope to make these repeatable on a given m
Jói 2011/04/21 19:50:33 I'm now using the UMA ID and salting with the tria
84 }
85
86 void FieldTrial::Disable() {
87 disable_field_trial_ = true;
66 } 88 }
67 89
68 int FieldTrial::AppendGroup(const std::string& name, 90 int FieldTrial::AppendGroup(const std::string& name,
69 Probability group_probability) { 91 Probability group_probability) {
70 DCHECK(group_probability <= divisor_); 92 DCHECK(group_probability <= divisor_);
71 DCHECK_GE(group_probability, 0); 93 DCHECK_GE(group_probability, 0);
72 94
73 if (enable_benchmarking_ || disable_field_trial_) 95 if (enable_benchmarking_ || disable_field_trial_)
74 group_probability = 0; 96 group_probability = 0;
75 97
76 accumulated_group_probability_ += group_probability; 98 accumulated_group_probability_ += group_probability;
77 99
78 DCHECK(accumulated_group_probability_ <= divisor_); 100 DCHECK(accumulated_group_probability_ <= divisor_);
79 if (group_ == kNotFinalized && accumulated_group_probability_ > random_) { 101 if (group_ == kNotFinalized && accumulated_group_probability_ > random_) {
80 // This is the group that crossed the random line, so we do the assignment. 102 // This is the group that crossed the random line, so we do the assignment.
81 group_ = next_group_number_; 103 group_ = next_group_number_;
82 if (name.empty()) 104 if (name.empty())
83 base::StringAppendF(&group_name_, "%d", group_); 105 StringAppendF(&group_name_, "%d", group_);
84 else 106 else
85 group_name_ = name; 107 group_name_ = name;
86 } 108 }
87 return next_group_number_++; 109 return next_group_number_++;
88 } 110 }
89 111
90 int FieldTrial::group() { 112 int FieldTrial::group() {
91 if (group_ == kNotFinalized) { 113 if (group_ == kNotFinalized) {
92 accumulated_group_probability_ = divisor_; 114 accumulated_group_probability_ = divisor_;
93 group_ = kDefaultGroupNumber; 115 group_ = kDefaultGroupNumber;
(...skipping 26 matching lines...) Expand all
120 // static 142 // static
121 Time FieldTrial::GetBuildTime() { 143 Time FieldTrial::GetBuildTime() {
122 Time integral_build_time; 144 Time integral_build_time;
123 const char* kDateTime = __DATE__ " " __TIME__; 145 const char* kDateTime = __DATE__ " " __TIME__;
124 bool result = Time::FromString(ASCIIToWide(kDateTime).c_str(), 146 bool result = Time::FromString(ASCIIToWide(kDateTime).c_str(),
125 &integral_build_time); 147 &integral_build_time);
126 DCHECK(result); 148 DCHECK(result);
127 return integral_build_time; 149 return integral_build_time;
128 } 150 }
129 151
152 // static
153 double FieldTrial::MachineIdToUniformDouble(const std::string& machine_id) {
154 // We use SHA-1 over the unique ID we have for machine/user (we add
155 // the user part by adding the user's home directory). SHA-1 is designed
156 // to produce a uniformly random spread in its output space, even for
157 // nearly-identical inputs, so it helps make this data look like a uniform
158 // random distribution.
159 Pickle pickle;
160 pickle.WriteString(machine_id);
161 file_util::GetHomeDir().WriteToPickle(&pickle);
jar (doing other things) 2011/04/21 01:03:50 Pickling is a waste. It doesn't add to the entrop
Jói 2011/04/21 19:50:33 Done.
162
163 unsigned char sha1_hash[SHA1_LENGTH];
164 SHA1HashBytes(reinterpret_cast<const unsigned char*>(pickle.data()),
165 pickle.size(),
166 sha1_hash);
167
168 COMPILE_ASSERT(sizeof(uint64) < sizeof(sha1_hash), need_more_data);
169 uint64* bits = reinterpret_cast<uint64*>(&sha1_hash[0]);
170
171 return BitsToRandDouble(*bits);
172 }
173
130 //------------------------------------------------------------------------------ 174 //------------------------------------------------------------------------------
131 // FieldTrialList methods and members. 175 // FieldTrialList methods and members.
132 176
133 // static 177 // static
134 FieldTrialList* FieldTrialList::global_ = NULL; 178 FieldTrialList* FieldTrialList::global_ = NULL;
135 179
136 // static 180 // static
137 bool FieldTrialList::register_without_global_ = false; 181 bool FieldTrialList::register_without_global_ = false;
138 182
139 FieldTrialList::FieldTrialList() : application_start_time_(TimeTicks::Now()) { 183 FieldTrialList::FieldTrialList() : application_start_time_(TimeTicks::Now()) {
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
264 } 308 }
265 309
266 FieldTrial* FieldTrialList::PreLockedFind(const std::string& name) { 310 FieldTrial* FieldTrialList::PreLockedFind(const std::string& name) {
267 RegistrationList::iterator it = registered_.find(name); 311 RegistrationList::iterator it = registered_.find(name);
268 if (registered_.end() == it) 312 if (registered_.end() == it)
269 return NULL; 313 return NULL;
270 return it->second; 314 return it->second;
271 } 315 }
272 316
273 } // namespace base 317 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698