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

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

Issue 10151017: Remove the hash fields from FieldTrials. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: header order Created 8 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
« 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"
11 #include "base/stringprintf.h" 11 #include "base/stringprintf.h"
12 #include "base/string_util.h" 12 #include "base/string_util.h"
13 #include "base/sys_byteorder.h" 13 #include "base/sys_byteorder.h"
14 #include "base/utf_string_conversions.h" 14 #include "base/utf_string_conversions.h"
15 15
16 namespace base { 16 namespace base {
17 17
18 static const char kHistogramFieldTrialSeparator('_'); 18 static const char kHistogramFieldTrialSeparator('_');
19 19
20 // statics 20 // statics
21 const int FieldTrial::kNotFinalized = -1; 21 const int FieldTrial::kNotFinalized = -1;
22 const int FieldTrial::kDefaultGroupNumber = 0; 22 const int FieldTrial::kDefaultGroupNumber = 0;
23 const uint32 FieldTrial::kReservedHashValue = 0;
24 bool FieldTrial::enable_benchmarking_ = false; 23 bool FieldTrial::enable_benchmarking_ = false;
25 24
26 const char FieldTrialList::kPersistentStringSeparator('/'); 25 const char FieldTrialList::kPersistentStringSeparator('/');
27 int FieldTrialList::kExpirationYearInFuture = 0; 26 int FieldTrialList::kExpirationYearInFuture = 0;
28 27
29 //------------------------------------------------------------------------------ 28 //------------------------------------------------------------------------------
30 // FieldTrial methods and members. 29 // FieldTrial methods and members.
31 30
32 FieldTrial::FieldTrial(const std::string& name, 31 FieldTrial::FieldTrial(const std::string& name,
33 const Probability total_probability, 32 const Probability total_probability,
34 const std::string& default_group_name, 33 const std::string& default_group_name,
35 const int year, 34 const int year,
36 const int month, 35 const int month,
37 const int day_of_month) 36 const int day_of_month)
38 : name_(name), 37 : name_(name),
39 name_hash_(HashName(name)),
40 divisor_(total_probability), 38 divisor_(total_probability),
41 default_group_name_(default_group_name), 39 default_group_name_(default_group_name),
42 random_(static_cast<Probability>(divisor_ * RandDouble())), 40 random_(static_cast<Probability>(divisor_ * RandDouble())),
43 accumulated_group_probability_(0), 41 accumulated_group_probability_(0),
44 next_group_number_(kDefaultGroupNumber + 1), 42 next_group_number_(kDefaultGroupNumber + 1),
45 group_(kNotFinalized), 43 group_(kNotFinalized),
46 group_name_hash_(kReservedHashValue),
47 enable_field_trial_(true), 44 enable_field_trial_(true),
48 forced_(false) { 45 forced_(false) {
49 DCHECK_GT(total_probability, 0); 46 DCHECK_GT(total_probability, 0);
50 DCHECK(!name_.empty()); 47 DCHECK(!name_.empty());
51 DCHECK(!default_group_name_.empty()); 48 DCHECK(!default_group_name_.empty());
52 49
53 DCHECK_GT(year, 1970); 50 DCHECK_GT(year, 1970);
54 DCHECK_GT(month, 0); 51 DCHECK_GT(month, 0);
55 DCHECK_LT(month, 13); 52 DCHECK_LT(month, 13);
56 DCHECK_GT(day_of_month, 0); 53 DCHECK_GT(day_of_month, 0);
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
144 } 141 }
145 return group_; 142 return group_;
146 } 143 }
147 144
148 std::string FieldTrial::group_name() { 145 std::string FieldTrial::group_name() {
149 group(); // call group() to make sure group assignment was done. 146 group(); // call group() to make sure group assignment was done.
150 DCHECK(!group_name_.empty()); 147 DCHECK(!group_name_.empty());
151 return group_name_; 148 return group_name_;
152 } 149 }
153 150
154 bool FieldTrial::GetNameGroupId(NameGroupId* name_group_id) { 151 bool FieldTrial::GetSelectedGroup(SelectedGroup* selected_group) {
155 if (group_name_hash_ == kReservedHashValue) 152 if (group_ == kNotFinalized)
156 return false; 153 return false;
157 name_group_id->name = name_hash_; 154 selected_group->trial = name_;
158 name_group_id->group = group_name_hash_; 155 selected_group->group = group_name_;
159 return true; 156 return true;
160 } 157 }
161 158
162 // static 159 // static
163 std::string FieldTrial::MakeName(const std::string& name_prefix, 160 std::string FieldTrial::MakeName(const std::string& name_prefix,
164 const std::string& trial_name) { 161 const std::string& trial_name) {
165 std::string big_string(name_prefix); 162 std::string big_string(name_prefix);
166 big_string.append(1, kHistogramFieldTrialSeparator); 163 big_string.append(1, kHistogramFieldTrialSeparator);
167 return big_string.append(FieldTrialList::FindFullName(trial_name)); 164 return big_string.append(FieldTrialList::FindFullName(trial_name));
168 } 165 }
169 166
170 // static 167 // static
171 FieldTrial::NameGroupId FieldTrial::MakeNameGroupId(
172 const std::string& trial_name,
173 const std::string& group_name) {
174 NameGroupId id;
175 id.name = HashName(trial_name);
176 id.group = HashName(group_name);
177 return id;
178 }
179
180 // static
181 void FieldTrial::EnableBenchmarking() { 168 void FieldTrial::EnableBenchmarking() {
182 DCHECK_EQ(0u, FieldTrialList::GetFieldTrialCount()); 169 DCHECK_EQ(0u, FieldTrialList::GetFieldTrialCount());
183 enable_benchmarking_ = true; 170 enable_benchmarking_ = true;
184 } 171 }
185 172
186 FieldTrial::~FieldTrial() {} 173 FieldTrial::~FieldTrial() {}
187 174
188 void FieldTrial::SetGroupChoice(const std::string& name, int number) { 175 void FieldTrial::SetGroupChoice(const std::string& name, int number) {
189 group_ = number; 176 group_ = number;
190 if (name.empty()) 177 if (name.empty())
191 StringAppendF(&group_name_, "%d", group_); 178 StringAppendF(&group_name_, "%d", group_);
192 else 179 else
193 group_name_ = name; 180 group_name_ = name;
194 group_name_hash_ = HashName(group_name_);
195 } 181 }
196 182
197 // static 183 // static
198 double FieldTrial::HashClientId(const std::string& client_id, 184 double FieldTrial::HashClientId(const std::string& client_id,
199 const std::string& trial_name) { 185 const std::string& trial_name) {
200 // SHA-1 is designed to produce a uniformly random spread in its output space, 186 // SHA-1 is designed to produce a uniformly random spread in its output space,
201 // even for nearly-identical inputs, so it helps massage whatever client_id 187 // even for nearly-identical inputs, so it helps massage whatever client_id
202 // and trial_name we get into something with a uniform distribution, which 188 // and trial_name we get into something with a uniform distribution, which
203 // is desirable so that we don't skew any part of the 0-100% spectrum. 189 // is desirable so that we don't skew any part of the 0-100% spectrum.
204 std::string input(client_id + trial_name); 190 std::string input(client_id + trial_name);
205 unsigned char sha1_hash[kSHA1Length]; 191 unsigned char sha1_hash[kSHA1Length];
206 SHA1HashBytes(reinterpret_cast<const unsigned char*>(input.c_str()), 192 SHA1HashBytes(reinterpret_cast<const unsigned char*>(input.c_str()),
207 input.size(), 193 input.size(),
208 sha1_hash); 194 sha1_hash);
209 195
210 COMPILE_ASSERT(sizeof(uint64) < sizeof(sha1_hash), need_more_data); 196 COMPILE_ASSERT(sizeof(uint64) < sizeof(sha1_hash), need_more_data);
211 uint64 bits; 197 uint64 bits;
212 memcpy(&bits, sha1_hash, sizeof(bits)); 198 memcpy(&bits, sha1_hash, sizeof(bits));
213 bits = base::ByteSwapToLE64(bits); 199 bits = base::ByteSwapToLE64(bits);
214 200
215 return BitsToOpenEndedUnitInterval(bits); 201 return BitsToOpenEndedUnitInterval(bits);
216 } 202 }
217 203
218 // static
219 uint32 FieldTrial::HashName(const std::string& name) {
220 // SHA-1 is designed to produce a uniformly random spread in its output space,
221 // even for nearly-identical inputs.
222 unsigned char sha1_hash[kSHA1Length];
223 SHA1HashBytes(reinterpret_cast<const unsigned char*>(name.c_str()),
224 name.size(),
225 sha1_hash);
226
227 COMPILE_ASSERT(sizeof(uint32) < sizeof(sha1_hash), need_more_data);
228 uint32 bits;
229 memcpy(&bits, sha1_hash, sizeof(bits));
230
231 // We only DCHECK, since this should not happen because the registration
232 // of the experiment on the server should have already warn the developer.
233 // If this ever happen, we'll ignore this experiment/group when reporting.
234 DCHECK(bits != kReservedHashValue);
235 return base::ByteSwapToLE32(bits);
236 }
237
238 //------------------------------------------------------------------------------ 204 //------------------------------------------------------------------------------
239 // FieldTrialList methods and members. 205 // FieldTrialList methods and members.
240 206
241 // static 207 // static
242 FieldTrialList* FieldTrialList::global_ = NULL; 208 FieldTrialList* FieldTrialList::global_ = NULL;
243 209
244 // static 210 // static
245 bool FieldTrialList::used_without_global_ = false; 211 bool FieldTrialList::used_without_global_ = false;
246 212
247 FieldTrialList::FieldTrialList(const std::string& client_id) 213 FieldTrialList::FieldTrialList(const std::string& client_id)
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
345 DCHECK_EQ(name.find(kPersistentStringSeparator), std::string::npos); 311 DCHECK_EQ(name.find(kPersistentStringSeparator), std::string::npos);
346 DCHECK_EQ(group_name.find(kPersistentStringSeparator), std::string::npos); 312 DCHECK_EQ(group_name.find(kPersistentStringSeparator), std::string::npos);
347 output->append(name); 313 output->append(name);
348 output->append(1, kPersistentStringSeparator); 314 output->append(1, kPersistentStringSeparator);
349 output->append(group_name); 315 output->append(group_name);
350 output->append(1, kPersistentStringSeparator); 316 output->append(1, kPersistentStringSeparator);
351 } 317 }
352 } 318 }
353 319
354 // static 320 // static
355 void FieldTrialList::GetFieldTrialNameGroupIds( 321 void FieldTrialList::GetFieldTrialSelectedGroups(
356 std::vector<FieldTrial::NameGroupId>* name_group_ids) { 322 FieldTrial::SelectedGroups* selected_groups) {
357 DCHECK(name_group_ids->empty()); 323 DCHECK(selected_groups->empty());
358 if (!global_) 324 if (!global_)
359 return; 325 return;
360 AutoLock auto_lock(global_->lock_); 326 AutoLock auto_lock(global_->lock_);
361 327
362 for (RegistrationList::iterator it = global_->registered_.begin(); 328 for (RegistrationList::iterator it = global_->registered_.begin();
363 it != global_->registered_.end(); ++it) { 329 it != global_->registered_.end(); ++it) {
364 FieldTrial::NameGroupId name_group_id; 330 FieldTrial::SelectedGroup selected_group;
365 if (it->second->GetNameGroupId(&name_group_id)) 331 if (it->second->GetSelectedGroup(&selected_group))
366 name_group_ids->push_back(name_group_id); 332 selected_groups->push_back(selected_group);
367 } 333 }
368 } 334 }
369 335
370 // static 336 // static
371 bool FieldTrialList::CreateTrialsFromString(const std::string& trials_string) { 337 bool FieldTrialList::CreateTrialsFromString(const std::string& trials_string) {
372 DCHECK(global_); 338 DCHECK(global_);
373 if (trials_string.empty() || !global_) 339 if (trials_string.empty() || !global_)
374 return true; 340 return true;
375 341
376 size_t next_item = 0; 342 size_t next_item = 0;
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
490 used_without_global_ = true; 456 used_without_global_ = true;
491 return; 457 return;
492 } 458 }
493 AutoLock auto_lock(global_->lock_); 459 AutoLock auto_lock(global_->lock_);
494 DCHECK(!global_->PreLockedFind(trial->name())); 460 DCHECK(!global_->PreLockedFind(trial->name()));
495 trial->AddRef(); 461 trial->AddRef();
496 global_->registered_[trial->name()] = trial; 462 global_->registered_[trial->name()] = trial;
497 } 463 }
498 464
499 } // namespace base 465 } // 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