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

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

Issue 2453933004: Fix deadlock issue with AllStatesToString (Closed)
Patch Set: fix unittest Created 4 years, 1 month 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 <algorithm> 7 #include <algorithm>
8 #include <utility> 8 #include <utility>
9 9
10 #include "base/base_switches.h" 10 #include "base/base_switches.h"
(...skipping 18 matching lines...) Expand all
29 const char kPersistentStringSeparator = '/'; // Currently a slash. 29 const char kPersistentStringSeparator = '/'; // Currently a slash.
30 30
31 // Define a marker character to be used as a prefix to a trial name on the 31 // Define a marker character to be used as a prefix to a trial name on the
32 // command line which forces its activation. 32 // command line which forces its activation.
33 const char kActivationMarker = '*'; 33 const char kActivationMarker = '*';
34 34
35 // Use shared memory to communicate field trial (experiment) state. Set to false 35 // Use shared memory to communicate field trial (experiment) state. Set to false
36 // for now while the implementation is fleshed out (e.g. data format, single 36 // for now while the implementation is fleshed out (e.g. data format, single
37 // shared memory segment). See https://codereview.chromium.org/2365273004/ and 37 // shared memory segment). See https://codereview.chromium.org/2365273004/ and
38 // crbug.com/653874 38 // crbug.com/653874
39 const bool kUseSharedMemoryForFieldTrials = false; 39 const bool kUseSharedMemoryForFieldTrials = true;
40 40
41 // Constants for the field trial allocator. 41 // Constants for the field trial allocator.
42 const char kAllocatorName[] = "FieldTrialAllocator"; 42 const char kAllocatorName[] = "FieldTrialAllocator";
43 const uint32_t kFieldTrialType = 0xABA17E13 + 1; // SHA1(FieldTrialEntry) v1 43 const uint32_t kFieldTrialType = 0xABA17E13 + 1; // SHA1(FieldTrialEntry) v1
44 #if !defined(OS_NACL) 44 #if !defined(OS_NACL)
45 const size_t kFieldTrialAllocationSize = 4 << 10; // 4 KiB = one page 45 const size_t kFieldTrialAllocationSize = 4 << 10; // 4 KiB = one page
46 #endif 46 #endif
47 47
48 // We create one FieldTrialEntry struct per field trial in shared memory (via 48 // We create one FieldTrialEntry struct per field trial in shared memory (via
49 // field_trial_allocator_). It contains whether or not it's activated, and the 49 // field_trial_allocator_). It contains whether or not it's activated, and the
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after
243 243
244 DCHECK_LE(accumulated_group_probability_, divisor_); 244 DCHECK_LE(accumulated_group_probability_, divisor_);
245 if (group_ == kNotFinalized && accumulated_group_probability_ > random_) { 245 if (group_ == kNotFinalized && accumulated_group_probability_ > random_) {
246 // This is the group that crossed the random line, so we do the assignment. 246 // This is the group that crossed the random line, so we do the assignment.
247 SetGroupChoice(name, next_group_number_); 247 SetGroupChoice(name, next_group_number_);
248 } 248 }
249 return next_group_number_++; 249 return next_group_number_++;
250 } 250 }
251 251
252 int FieldTrial::group() { 252 int FieldTrial::group() {
253 FinalizeGroupChoice(); 253 FinalizeGroupChoice(false);
254 if (trial_registered_) 254 if (trial_registered_)
255 FieldTrialList::NotifyFieldTrialGroupSelection(this); 255 FieldTrialList::NotifyFieldTrialGroupSelection(this);
256 return group_; 256 return group_;
257 } 257 }
258 258
259 const std::string& FieldTrial::group_name() { 259 const std::string& FieldTrial::group_name() {
260 // Call |group()| to ensure group gets assigned and observers are notified. 260 // Call |group()| to ensure group gets assigned and observers are notified.
261 group(); 261 group();
262 DCHECK(!group_name_.empty()); 262 DCHECK(!group_name_.empty());
263 return group_name_; 263 return group_name_;
264 } 264 }
265 265
266 const std::string& FieldTrial::GetGroupNameWithoutActivation() { 266 const std::string& FieldTrial::GetGroupNameWithoutActivation() {
267 FinalizeGroupChoice(); 267 FinalizeGroupChoice(false);
268 return group_name_; 268 return group_name_;
269 } 269 }
270 270
271 void FieldTrial::SetForced() { 271 void FieldTrial::SetForced() {
272 // We might have been forced before (e.g., by CreateFieldTrial) and it's 272 // We might have been forced before (e.g., by CreateFieldTrial) and it's
273 // first come first served, e.g., command line switch has precedence. 273 // first come first served, e.g., command line switch has precedence.
274 if (forced_) 274 if (forced_)
275 return; 275 return;
276 276
277 // And we must finalize the group choice before we mark ourselves as forced. 277 // And we must finalize the group choice before we mark ourselves as forced.
278 FinalizeGroupChoice(); 278 FinalizeGroupChoice(false);
279 forced_ = true; 279 forced_ = true;
280 } 280 }
281 281
282 // static 282 // static
283 void FieldTrial::EnableBenchmarking() { 283 void FieldTrial::EnableBenchmarking() {
284 DCHECK_EQ(0u, FieldTrialList::GetFieldTrialCount()); 284 DCHECK_EQ(0u, FieldTrialList::GetFieldTrialCount());
285 enable_benchmarking_ = true; 285 enable_benchmarking_ = true;
286 } 286 }
287 287
288 // static 288 // static
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
326 326
327 void FieldTrial::SetGroupChoice(const std::string& group_name, int number) { 327 void FieldTrial::SetGroupChoice(const std::string& group_name, int number) {
328 group_ = number; 328 group_ = number;
329 if (group_name.empty()) 329 if (group_name.empty())
330 StringAppendF(&group_name_, "%d", group_); 330 StringAppendF(&group_name_, "%d", group_);
331 else 331 else
332 group_name_ = group_name; 332 group_name_ = group_name;
333 DVLOG(1) << "Field trial: " << trial_name_ << " Group choice:" << group_name_; 333 DVLOG(1) << "Field trial: " << trial_name_ << " Group choice:" << group_name_;
334 } 334 }
335 335
336 void FieldTrial::FinalizeGroupChoice() { 336 void FieldTrial::FinalizeGroupChoice(bool is_locked) {
337 if (group_ != kNotFinalized) 337 if (group_ != kNotFinalized)
338 return; 338 return;
339 accumulated_group_probability_ = divisor_; 339 accumulated_group_probability_ = divisor_;
340 // Here it's OK to use |kDefaultGroupNumber| since we can't be forced and not 340 // Here it's OK to use |kDefaultGroupNumber| since we can't be forced and not
341 // finalized. 341 // finalized.
342 DCHECK(!forced_); 342 DCHECK(!forced_);
343 SetGroupChoice(default_group_name_, kDefaultGroupNumber); 343 SetGroupChoice(default_group_name_, kDefaultGroupNumber);
344 344
345 // Add the field trial to shared memory. 345 // Add the field trial to shared memory.
346 if (kUseSharedMemoryForFieldTrials) 346 if (kUseSharedMemoryForFieldTrials)
347 FieldTrialList::OnGroupFinalized(this); 347 FieldTrialList::OnGroupFinalized(is_locked, this);
348 } 348 }
349 349
350 bool FieldTrial::GetActiveGroup(ActiveGroup* active_group) const { 350 bool FieldTrial::GetActiveGroup(ActiveGroup* active_group) const {
351 if (!group_reported_ || !enable_field_trial_) 351 if (!group_reported_ || !enable_field_trial_)
352 return false; 352 return false;
353 DCHECK_NE(group_, kNotFinalized); 353 DCHECK_NE(group_, kNotFinalized);
354 active_group->trial_name = trial_name_; 354 active_group->trial_name = trial_name_;
355 active_group->group_name = group_name_; 355 active_group->group_name = group_name_;
356 return true; 356 return true;
357 } 357 }
358 358
359 bool FieldTrial::GetState(State* field_trial_state) { 359 bool FieldTrial::GetState(State* field_trial_state) {
360 if (!enable_field_trial_) 360 if (!enable_field_trial_)
361 return false; 361 return false;
362 FinalizeGroupChoice(); 362 FinalizeGroupChoice(false);
363 field_trial_state->trial_name = trial_name_; 363 field_trial_state->trial_name = trial_name_;
364 field_trial_state->group_name = group_name_; 364 field_trial_state->group_name = group_name_;
365 field_trial_state->activated = group_reported_; 365 field_trial_state->activated = group_reported_;
366 return true;
367 }
368
369 bool FieldTrial::GetStateWhileLocked(State* field_trial_state) {
370 if (!enable_field_trial_)
371 return false;
372 FinalizeGroupChoice(true);
Alexei Svitkine (slow) 2016/10/27 21:40:43 How about making the call that takes the param Fin
lawrencewu 2016/10/28 17:20:21 Done.
373 field_trial_state->trial_name = trial_name_;
374 field_trial_state->group_name = group_name_;
375 field_trial_state->activated = group_reported_;
366 return true; 376 return true;
367 } 377 }
368 378
369 //------------------------------------------------------------------------------ 379 //------------------------------------------------------------------------------
370 // FieldTrialList methods and members. 380 // FieldTrialList methods and members.
371 381
372 // static 382 // static
373 FieldTrialList* FieldTrialList::global_ = NULL; 383 FieldTrialList* FieldTrialList::global_ = NULL;
374 384
375 // static 385 // static
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after
539 } 549 }
540 550
541 // static 551 // static
542 void FieldTrialList::AllStatesToString(std::string* output) { 552 void FieldTrialList::AllStatesToString(std::string* output) {
543 if (!global_) 553 if (!global_)
544 return; 554 return;
545 AutoLock auto_lock(global_->lock_); 555 AutoLock auto_lock(global_->lock_);
546 556
547 for (const auto& registered : global_->registered_) { 557 for (const auto& registered : global_->registered_) {
548 FieldTrial::State trial; 558 FieldTrial::State trial;
549 if (!registered.second->GetState(&trial)) 559 if (!registered.second->GetStateWhileLocked(&trial))
550 continue; 560 continue;
551 DCHECK_EQ(std::string::npos, 561 DCHECK_EQ(std::string::npos,
552 trial.trial_name.find(kPersistentStringSeparator)); 562 trial.trial_name.find(kPersistentStringSeparator));
553 DCHECK_EQ(std::string::npos, 563 DCHECK_EQ(std::string::npos,
554 trial.group_name.find(kPersistentStringSeparator)); 564 trial.group_name.find(kPersistentStringSeparator));
555 if (trial.activated) 565 if (trial.activated)
556 output->append(1, kActivationMarker); 566 output->append(1, kActivationMarker);
557 trial.trial_name.AppendToString(output); 567 trial.trial_name.AppendToString(output);
558 output->append(1, kPersistentStringSeparator); 568 output->append(1, kPersistentStringSeparator);
559 trial.group_name.AppendToString(output); 569 trial.group_name.AppendToString(output);
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
746 } 756 }
747 757
748 // static 758 // static
749 void FieldTrialList::RemoveObserver(Observer* observer) { 759 void FieldTrialList::RemoveObserver(Observer* observer) {
750 if (!global_) 760 if (!global_)
751 return; 761 return;
752 global_->observer_list_->RemoveObserver(observer); 762 global_->observer_list_->RemoveObserver(observer);
753 } 763 }
754 764
755 // static 765 // static
756 void FieldTrialList::OnGroupFinalized(FieldTrial* field_trial) { 766 void FieldTrialList::OnGroupFinalized(bool is_locked, FieldTrial* field_trial) {
757 if (!global_) 767 if (!global_)
758 return; 768 return;
759 AutoLock auto_lock(global_->lock_); 769 if (is_locked) {
760 AddToAllocatorWhileLocked(field_trial); 770 AddToAllocatorWhileLocked(field_trial);
771 } else {
772 AutoLock auto_lock(global_->lock_);
773 AddToAllocatorWhileLocked(field_trial);
774 }
761 } 775 }
762 776
763 // static 777 // static
764 void FieldTrialList::NotifyFieldTrialGroupSelection(FieldTrial* field_trial) { 778 void FieldTrialList::NotifyFieldTrialGroupSelection(FieldTrial* field_trial) {
765 if (!global_) 779 if (!global_)
766 return; 780 return;
767 781
768 { 782 {
769 AutoLock auto_lock(global_->lock_); 783 AutoLock auto_lock(global_->lock_);
770 if (field_trial->group_reported_) 784 if (field_trial->group_reported_)
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
944 return; 958 return;
945 } 959 }
946 AutoLock auto_lock(global_->lock_); 960 AutoLock auto_lock(global_->lock_);
947 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); 961 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name();
948 trial->AddRef(); 962 trial->AddRef();
949 trial->SetTrialRegistered(); 963 trial->SetTrialRegistered();
950 global_->registered_[trial->trial_name()] = trial; 964 global_->registered_[trial->trial_name()] = trial;
951 } 965 }
952 966
953 } // namespace base 967 } // 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