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

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

Issue 2449143002: Actually update FieldTrialEntry's activated field (Closed)
Patch Set: ActivateFieldTrialEntry += WhileLocked 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') | no next file » | 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 291 matching lines...) Expand 10 before | Expand all | Expand 10 after
302 : trial_name_(trial_name), 302 : trial_name_(trial_name),
303 divisor_(total_probability), 303 divisor_(total_probability),
304 default_group_name_(default_group_name), 304 default_group_name_(default_group_name),
305 random_(GetGroupBoundaryValue(total_probability, entropy_value)), 305 random_(GetGroupBoundaryValue(total_probability, entropy_value)),
306 accumulated_group_probability_(0), 306 accumulated_group_probability_(0),
307 next_group_number_(kDefaultGroupNumber + 1), 307 next_group_number_(kDefaultGroupNumber + 1),
308 group_(kNotFinalized), 308 group_(kNotFinalized),
309 enable_field_trial_(true), 309 enable_field_trial_(true),
310 forced_(false), 310 forced_(false),
311 group_reported_(false), 311 group_reported_(false),
312 trial_registered_(false) { 312 trial_registered_(false),
313 ref_(SharedPersistentMemoryAllocator::kReferenceNull) {
313 DCHECK_GT(total_probability, 0); 314 DCHECK_GT(total_probability, 0);
314 DCHECK(!trial_name_.empty()); 315 DCHECK(!trial_name_.empty());
315 DCHECK(!default_group_name_.empty()); 316 DCHECK(!default_group_name_.empty());
316 } 317 }
317 318
318 FieldTrial::~FieldTrial() {} 319 FieldTrial::~FieldTrial() {}
319 320
320 void FieldTrial::SetTrialRegistered() { 321 void FieldTrial::SetTrialRegistered() {
321 DCHECK_EQ(kNotFinalized, group_); 322 DCHECK_EQ(kNotFinalized, group_);
322 DCHECK(!trial_registered_); 323 DCHECK(!trial_registered_);
(...skipping 10 matching lines...) Expand all
333 } 334 }
334 335
335 void FieldTrial::FinalizeGroupChoice() { 336 void FieldTrial::FinalizeGroupChoice() {
336 if (group_ != kNotFinalized) 337 if (group_ != kNotFinalized)
337 return; 338 return;
338 accumulated_group_probability_ = divisor_; 339 accumulated_group_probability_ = divisor_;
339 // 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
340 // finalized. 341 // finalized.
341 DCHECK(!forced_); 342 DCHECK(!forced_);
342 SetGroupChoice(default_group_name_, kDefaultGroupNumber); 343 SetGroupChoice(default_group_name_, kDefaultGroupNumber);
344
345 // Add the field trial to shared memory.
346 if (kUseSharedMemoryForFieldTrials)
347 FieldTrialList::OnGroupFinalized(this);
343 } 348 }
344 349
345 bool FieldTrial::GetActiveGroup(ActiveGroup* active_group) const { 350 bool FieldTrial::GetActiveGroup(ActiveGroup* active_group) const {
346 if (!group_reported_ || !enable_field_trial_) 351 if (!group_reported_ || !enable_field_trial_)
347 return false; 352 return false;
348 DCHECK_NE(group_, kNotFinalized); 353 DCHECK_NE(group_, kNotFinalized);
349 active_group->trial_name = trial_name_; 354 active_group->trial_name = trial_name_;
350 active_group->group_name = group_name_; 355 active_group->group_name = group_name_;
351 return true; 356 return true;
352 } 357 }
(...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after
666 return; 671 return;
667 if (kUseSharedMemoryForFieldTrials) { 672 if (kUseSharedMemoryForFieldTrials) {
668 InstantiateFieldTrialAllocatorIfNeeded(); 673 InstantiateFieldTrialAllocatorIfNeeded();
669 if (global_->readonly_allocator_handle_) 674 if (global_->readonly_allocator_handle_)
670 handles->push_back(global_->readonly_allocator_handle_); 675 handles->push_back(global_->readonly_allocator_handle_);
671 } 676 }
672 } 677 }
673 #endif 678 #endif
674 679
675 // static 680 // static
676 void FieldTrialList::CreateTrialsFromSharedMemory(
677 std::unique_ptr<SharedMemory> shm) {
678 const SharedPersistentMemoryAllocator shalloc(std::move(shm), 0,
679 kAllocatorName, true);
680 PersistentMemoryAllocator::Iterator iter(&shalloc);
681
682 SharedPersistentMemoryAllocator::Reference ref;
683 while ((ref = iter.GetNextOfType(kFieldTrialType)) !=
684 SharedPersistentMemoryAllocator::kReferenceNull) {
685 const FieldTrialEntry* entry =
686 shalloc.GetAsObject<const FieldTrialEntry>(ref, kFieldTrialType);
687 FieldTrial* trial =
688 CreateFieldTrial(entry->GetTrialName(), entry->GetGroupName());
689
690 if (entry->activated) {
691 // Call |group()| to mark the trial as "used" and notify observers, if
692 // any. This is useful to ensure that field trials created in child
693 // processes are properly reported in crash reports.
694 trial->group();
695 }
696 }
697 }
698
699 // static
700 void FieldTrialList::CopyFieldTrialStateToFlags( 681 void FieldTrialList::CopyFieldTrialStateToFlags(
701 const char* field_trial_handle_switch, 682 const char* field_trial_handle_switch,
702 CommandLine* cmd_line) { 683 CommandLine* cmd_line) {
703 #if defined(OS_WIN) 684 #if defined(OS_WIN)
704 // Use shared memory to pass the state if the feature is enabled, otherwise 685 // Use shared memory to pass the state if the feature is enabled, otherwise
705 // fallback to passing it via the command line as a string. 686 // fallback to passing it via the command line as a string.
706 if (kUseSharedMemoryForFieldTrials) { 687 if (kUseSharedMemoryForFieldTrials) {
707 InstantiateFieldTrialAllocatorIfNeeded(); 688 InstantiateFieldTrialAllocatorIfNeeded();
708 // If the readonly handle didn't get duplicated properly, then fallback to 689 // If the readonly handle didn't get duplicated properly, then fallback to
709 // original behavior. 690 // original behavior.
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
765 } 746 }
766 747
767 // static 748 // static
768 void FieldTrialList::RemoveObserver(Observer* observer) { 749 void FieldTrialList::RemoveObserver(Observer* observer) {
769 if (!global_) 750 if (!global_)
770 return; 751 return;
771 global_->observer_list_->RemoveObserver(observer); 752 global_->observer_list_->RemoveObserver(observer);
772 } 753 }
773 754
774 // static 755 // static
756 void FieldTrialList::OnGroupFinalized(FieldTrial* field_trial) {
757 if (!global_)
758 return;
759 AutoLock auto_lock(global_->lock_);
760 AddToAllocatorWhileLocked(field_trial);
761 }
762
763 // static
775 void FieldTrialList::NotifyFieldTrialGroupSelection(FieldTrial* field_trial) { 764 void FieldTrialList::NotifyFieldTrialGroupSelection(FieldTrial* field_trial) {
776 if (!global_) 765 if (!global_)
777 return; 766 return;
778 767
779 { 768 {
780 AutoLock auto_lock(global_->lock_); 769 AutoLock auto_lock(global_->lock_);
781 if (field_trial->group_reported_) 770 if (field_trial->group_reported_)
782 return; 771 return;
783 field_trial->group_reported_ = true; 772 field_trial->group_reported_ = true;
784 773
785 if (!field_trial->enable_field_trial_) 774 if (!field_trial->enable_field_trial_)
786 return; 775 return;
787 776
788 if (kUseSharedMemoryForFieldTrials) { 777 if (kUseSharedMemoryForFieldTrials)
789 field_trial->AddToAllocatorWhileLocked( 778 ActivateFieldTrialEntryWhileLocked(field_trial);
790 global_->field_trial_allocator_.get());
791 }
792 } 779 }
793 780
794 global_->observer_list_->Notify( 781 global_->observer_list_->Notify(
795 FROM_HERE, &FieldTrialList::Observer::OnFieldTrialGroupFinalized, 782 FROM_HERE, &FieldTrialList::Observer::OnFieldTrialGroupFinalized,
796 field_trial->trial_name(), field_trial->group_name_internal()); 783 field_trial->trial_name(), field_trial->group_name_internal());
797 } 784 }
798 785
786 // static
787 size_t FieldTrialList::GetFieldTrialCount() {
788 if (!global_)
789 return 0;
790 AutoLock auto_lock(global_->lock_);
791 return global_->registered_.size();
792 }
793
794 // static
795 void FieldTrialList::CreateTrialsFromSharedMemory(
796 std::unique_ptr<SharedMemory> shm) {
797 const SharedPersistentMemoryAllocator shalloc(std::move(shm), 0,
798 kAllocatorName, true);
799 PersistentMemoryAllocator::Iterator iter(&shalloc);
800
801 SharedPersistentMemoryAllocator::Reference ref;
802 while ((ref = iter.GetNextOfType(kFieldTrialType)) !=
803 SharedPersistentMemoryAllocator::kReferenceNull) {
804 const FieldTrialEntry* entry =
805 shalloc.GetAsObject<const FieldTrialEntry>(ref, kFieldTrialType);
806 FieldTrial* trial =
807 CreateFieldTrial(entry->GetTrialName(), entry->GetGroupName());
808
809 if (entry->activated) {
810 // Call |group()| to mark the trial as "used" and notify observers, if
811 // any. This is useful to ensure that field trials created in child
812 // processes are properly reported in crash reports.
813 trial->group();
814 }
815 }
816 }
817
799 #if !defined(OS_NACL) 818 #if !defined(OS_NACL)
800 // static 819 // static
801 void FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded() { 820 void FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded() {
821 if (!global_)
822 return;
802 AutoLock auto_lock(global_->lock_); 823 AutoLock auto_lock(global_->lock_);
803 // Create the allocator if not already created and add all existing trials. 824 // Create the allocator if not already created and add all existing trials.
804 if (global_->field_trial_allocator_ != nullptr) 825 if (global_->field_trial_allocator_ != nullptr)
805 return; 826 return;
806 827
807 std::unique_ptr<SharedMemory> shm(new SharedMemory()); 828 std::unique_ptr<SharedMemory> shm(new SharedMemory());
808 if (!shm->CreateAndMapAnonymous(kFieldTrialAllocationSize)) 829 if (!shm->CreateAndMapAnonymous(kFieldTrialAllocationSize))
809 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); 830 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize);
810 831
811 // TODO(lawrencewu): call UpdateTrackingHistograms() when all field trials 832 // TODO(lawrencewu): call UpdateTrackingHistograms() when all field trials
812 // have been registered (perhaps in the destructor?) 833 // have been registered (perhaps in the destructor?)
813 global_->field_trial_allocator_.reset(new SharedPersistentMemoryAllocator( 834 global_->field_trial_allocator_.reset(new SharedPersistentMemoryAllocator(
814 std::move(shm), 0, kAllocatorName, false)); 835 std::move(shm), 0, kAllocatorName, false));
815 global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName); 836 global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName);
816 837
817 // Add all existing field trials. 838 // Add all existing field trials.
818 for (const auto& registered : global_->registered_) { 839 for (const auto& registered : global_->registered_) {
819 registered.second->AddToAllocatorWhileLocked( 840 AddToAllocatorWhileLocked(registered.second);
820 global_->field_trial_allocator_.get());
821 } 841 }
822 842
823 #if defined(OS_WIN) 843 #if defined(OS_WIN)
824 // Set |readonly_allocator_handle_| so we can pass it to be inherited and via 844 // Set |readonly_allocator_handle_| so we can pass it to be inherited and
825 // the command line. 845 // via the command line.
826 global_->readonly_allocator_handle_ = 846 global_->readonly_allocator_handle_ =
827 CreateReadOnlyHandle(global_->field_trial_allocator_.get()); 847 CreateReadOnlyHandle(global_->field_trial_allocator_.get());
828 #endif 848 #endif
829 } 849 }
830 #endif 850 #endif
831 851
832 void FieldTrial::AddToAllocatorWhileLocked( 852 // static
833 SharedPersistentMemoryAllocator* allocator) { 853 void FieldTrialList::AddToAllocatorWhileLocked(FieldTrial* field_trial) {
854 SharedPersistentMemoryAllocator* allocator =
855 global_->field_trial_allocator_.get();
856
834 // Don't do anything if the allocator hasn't been instantiated yet. 857 // Don't do anything if the allocator hasn't been instantiated yet.
835 if (allocator == nullptr) 858 if (allocator == nullptr)
836 return; 859 return;
837 860
838 State trial_state; 861 // Or if we've already added it.
839 if (!GetState(&trial_state)) 862 if (field_trial->ref_ != SharedPersistentMemoryAllocator::kReferenceNull)
863 return;
864
865 FieldTrial::State trial_state;
866 if (!field_trial->GetState(&trial_state))
840 return; 867 return;
841 868
842 size_t trial_name_size = trial_state.trial_name.size() + 1; 869 size_t trial_name_size = trial_state.trial_name.size() + 1;
843 size_t group_name_size = trial_state.group_name.size() + 1; 870 size_t group_name_size = trial_state.group_name.size() + 1;
844 size_t size = sizeof(FieldTrialEntry) + trial_name_size + group_name_size; 871 size_t size = sizeof(FieldTrialEntry) + trial_name_size + group_name_size;
845 872
846 // Allocate just enough memory to fit the FieldTrialEntry struct, trial name, 873 // Allocate just enough memory to fit the FieldTrialEntry struct, trial name,
847 // and group name. 874 // and group name.
848 SharedPersistentMemoryAllocator::Reference ref = 875 SharedPersistentMemoryAllocator::Reference ref =
849 allocator->Allocate(size, kFieldTrialType); 876 allocator->Allocate(size, kFieldTrialType);
(...skipping 12 matching lines...) Expand all
862 char* trial_name = reinterpret_cast<char*>(entry) + trial_name_offset; 889 char* trial_name = reinterpret_cast<char*>(entry) + trial_name_offset;
863 char* group_name = reinterpret_cast<char*>(entry) + group_name_offset; 890 char* group_name = reinterpret_cast<char*>(entry) + group_name_offset;
864 memcpy(trial_name, trial_state.trial_name.data(), trial_name_size); 891 memcpy(trial_name, trial_state.trial_name.data(), trial_name_size);
865 memcpy(group_name, trial_state.group_name.data(), group_name_size); 892 memcpy(group_name, trial_state.group_name.data(), group_name_size);
866 893
867 // Null terminate the strings. 894 // Null terminate the strings.
868 trial_name[trial_state.trial_name.size()] = '\0'; 895 trial_name[trial_state.trial_name.size()] = '\0';
869 group_name[trial_state.group_name.size()] = '\0'; 896 group_name[trial_state.group_name.size()] = '\0';
870 897
871 allocator->MakeIterable(ref); 898 allocator->MakeIterable(ref);
899 field_trial->ref_ = ref;
872 } 900 }
873 901
874 // static 902 // static
875 size_t FieldTrialList::GetFieldTrialCount() { 903 void FieldTrialList::ActivateFieldTrialEntryWhileLocked(
876 if (!global_) 904 FieldTrial* field_trial) {
877 return 0; 905 SharedPersistentMemoryAllocator* allocator =
878 AutoLock auto_lock(global_->lock_); 906 global_->field_trial_allocator_.get();
879 return global_->registered_.size(); 907 SharedPersistentMemoryAllocator::Reference ref = field_trial->ref_;
908 if (ref == SharedPersistentMemoryAllocator::kReferenceNull) {
909 // It's fine to do this even if the allocator hasn't been instantiated
910 // yet -- it'll just return early.
911 AddToAllocatorWhileLocked(field_trial);
912 } else {
913 // It's also okay to do this even though the callee doesn't have a lock --
914 // the only thing that happens on a stale read here is a slight performance
915 // hit from the child re-synchronizing activation state.
916 FieldTrialEntry* entry =
917 allocator->GetAsObject<FieldTrialEntry>(ref, kFieldTrialType);
918 entry->activated = true;
919 }
880 } 920 }
881 921
882 // static 922 // static
883 const FieldTrial::EntropyProvider* 923 const FieldTrial::EntropyProvider*
884 FieldTrialList::GetEntropyProviderForOneTimeRandomization() { 924 FieldTrialList::GetEntropyProviderForOneTimeRandomization() {
885 if (!global_) { 925 if (!global_) {
886 used_without_global_ = true; 926 used_without_global_ = true;
887 return NULL; 927 return NULL;
888 } 928 }
889 929
(...skipping 14 matching lines...) Expand all
904 return; 944 return;
905 } 945 }
906 AutoLock auto_lock(global_->lock_); 946 AutoLock auto_lock(global_->lock_);
907 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); 947 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name();
908 trial->AddRef(); 948 trial->AddRef();
909 trial->SetTrialRegistered(); 949 trial->SetTrialRegistered();
910 global_->registered_[trial->trial_name()] = trial; 950 global_->registered_[trial->trial_name()] = trial;
911 } 951 }
912 952
913 } // namespace base 953 } // namespace base
OLDNEW
« no previous file with comments | « base/metrics/field_trial.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698