OLD | NEW |
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 Loading... |
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 Loading... |
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::AddToAllocator(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 424 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
777 return; | 782 return; |
778 | 783 |
779 { | 784 { |
780 AutoLock auto_lock(global_->lock_); | 785 AutoLock auto_lock(global_->lock_); |
781 if (field_trial->group_reported_) | 786 if (field_trial->group_reported_) |
782 return; | 787 return; |
783 field_trial->group_reported_ = true; | 788 field_trial->group_reported_ = true; |
784 | 789 |
785 if (!field_trial->enable_field_trial_) | 790 if (!field_trial->enable_field_trial_) |
786 return; | 791 return; |
| 792 } |
787 | 793 |
788 if (kUseSharedMemoryForFieldTrials) { | 794 if (kUseSharedMemoryForFieldTrials) |
789 field_trial->AddToAllocatorWhileLocked( | 795 ActivateFieldTrialEntry(field_trial); |
790 global_->field_trial_allocator_.get()); | |
791 } | |
792 } | |
793 | 796 |
794 global_->observer_list_->Notify( | 797 global_->observer_list_->Notify( |
795 FROM_HERE, &FieldTrialList::Observer::OnFieldTrialGroupFinalized, | 798 FROM_HERE, &FieldTrialList::Observer::OnFieldTrialGroupFinalized, |
796 field_trial->trial_name(), field_trial->group_name_internal()); | 799 field_trial->trial_name(), field_trial->group_name_internal()); |
797 } | 800 } |
798 | 801 |
| 802 // static |
| 803 void FieldTrialList::ActivateFieldTrialEntry(FieldTrial* field_trial) { |
| 804 SharedPersistentMemoryAllocator* allocator = |
| 805 global_->field_trial_allocator_.get(); |
| 806 SharedPersistentMemoryAllocator::Reference ref = field_trial->ref_; |
| 807 if (ref == SharedPersistentMemoryAllocator::kReferenceNull) { |
| 808 // It's fine to do this even if the allocator hasn't been instantiated |
| 809 // yet -- it'll just return early. |
| 810 AddToAllocator(field_trial); |
| 811 } else { |
| 812 // It's also okay to do this even though the callee doesn't have a lock -- |
| 813 // the only thing that happens on a stale read here is a slight performance |
| 814 // hit from the child re-synchronizing activation state. |
| 815 FieldTrialEntry* entry = |
| 816 allocator->GetAsObject<FieldTrialEntry>(ref, kFieldTrialType); |
| 817 entry->activated = true; |
| 818 } |
| 819 } |
| 820 |
799 #if !defined(OS_NACL) | 821 #if !defined(OS_NACL) |
800 // static | 822 // static |
801 void FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded() { | 823 void FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded() { |
802 AutoLock auto_lock(global_->lock_); | 824 if (!global_) |
803 // Create the allocator if not already created and add all existing trials. | |
804 if (global_->field_trial_allocator_ != nullptr) | |
805 return; | 825 return; |
| 826 { |
| 827 AutoLock auto_lock(global_->lock_); |
| 828 // Create the allocator if not already created and add all existing trials. |
| 829 if (global_->field_trial_allocator_ != nullptr) |
| 830 return; |
806 | 831 |
807 std::unique_ptr<SharedMemory> shm(new SharedMemory()); | 832 std::unique_ptr<SharedMemory> shm(new SharedMemory()); |
808 if (!shm->CreateAndMapAnonymous(kFieldTrialAllocationSize)) | 833 if (!shm->CreateAndMapAnonymous(kFieldTrialAllocationSize)) |
809 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); | 834 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); |
810 | 835 |
811 // TODO(lawrencewu): call UpdateTrackingHistograms() when all field trials | 836 // TODO(lawrencewu): call UpdateTrackingHistograms() when all field trials |
812 // have been registered (perhaps in the destructor?) | 837 // have been registered (perhaps in the destructor?) |
813 global_->field_trial_allocator_.reset(new SharedPersistentMemoryAllocator( | 838 global_->field_trial_allocator_.reset(new SharedPersistentMemoryAllocator( |
814 std::move(shm), 0, kAllocatorName, false)); | 839 std::move(shm), 0, kAllocatorName, false)); |
815 global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName); | 840 global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName); |
816 | 841 |
817 // Add all existing field trials. | 842 #if defined(OS_WIN) |
818 for (const auto& registered : global_->registered_) { | 843 // Set |readonly_allocator_handle_| so we can pass it to be inherited and |
819 registered.second->AddToAllocatorWhileLocked( | 844 // via the command line. |
820 global_->field_trial_allocator_.get()); | 845 global_->readonly_allocator_handle_ = |
| 846 CreateReadOnlyHandle(global_->field_trial_allocator_.get()); |
| 847 #endif |
821 } | 848 } |
822 | 849 |
823 #if defined(OS_WIN) | 850 // Add all existing field trials. Needs to be outside the lock since |
824 // Set |readonly_allocator_handle_| so we can pass it to be inherited and via | 851 // AddToAllocator locks as well. |
825 // the command line. | 852 for (const auto& registered : global_->registered_) { |
826 global_->readonly_allocator_handle_ = | 853 AddToAllocator(registered.second); |
827 CreateReadOnlyHandle(global_->field_trial_allocator_.get()); | 854 } |
828 #endif | |
829 } | 855 } |
830 #endif | 856 #endif |
831 | 857 |
832 void FieldTrial::AddToAllocatorWhileLocked( | 858 // static |
833 SharedPersistentMemoryAllocator* allocator) { | 859 size_t FieldTrialList::GetFieldTrialCount() { |
| 860 if (!global_) |
| 861 return 0; |
| 862 AutoLock auto_lock(global_->lock_); |
| 863 return global_->registered_.size(); |
| 864 } |
| 865 |
| 866 // static |
| 867 void FieldTrialList::AddToAllocator(FieldTrial* field_trial) { |
| 868 if (!global_) |
| 869 return; |
| 870 AutoLock auto_lock(global_->lock_); |
| 871 |
| 872 SharedPersistentMemoryAllocator* allocator = |
| 873 global_->field_trial_allocator_.get(); |
| 874 |
834 // Don't do anything if the allocator hasn't been instantiated yet. | 875 // Don't do anything if the allocator hasn't been instantiated yet. |
835 if (allocator == nullptr) | 876 if (allocator == nullptr) |
836 return; | 877 return; |
837 | 878 |
838 State trial_state; | 879 // Or if we've already added it. |
839 if (!GetState(&trial_state)) | 880 if (field_trial->ref_ != SharedPersistentMemoryAllocator::kReferenceNull) |
| 881 return; |
| 882 |
| 883 FieldTrial::State trial_state; |
| 884 if (!field_trial->GetState(&trial_state)) |
840 return; | 885 return; |
841 | 886 |
842 size_t trial_name_size = trial_state.trial_name.size() + 1; | 887 size_t trial_name_size = trial_state.trial_name.size() + 1; |
843 size_t group_name_size = trial_state.group_name.size() + 1; | 888 size_t group_name_size = trial_state.group_name.size() + 1; |
844 size_t size = sizeof(FieldTrialEntry) + trial_name_size + group_name_size; | 889 size_t size = sizeof(FieldTrialEntry) + trial_name_size + group_name_size; |
845 | 890 |
846 // Allocate just enough memory to fit the FieldTrialEntry struct, trial name, | 891 // Allocate just enough memory to fit the FieldTrialEntry struct, trial name, |
847 // and group name. | 892 // and group name. |
848 SharedPersistentMemoryAllocator::Reference ref = | 893 SharedPersistentMemoryAllocator::Reference ref = |
849 allocator->Allocate(size, kFieldTrialType); | 894 allocator->Allocate(size, kFieldTrialType); |
(...skipping 12 matching lines...) Expand all Loading... |
862 char* trial_name = reinterpret_cast<char*>(entry) + trial_name_offset; | 907 char* trial_name = reinterpret_cast<char*>(entry) + trial_name_offset; |
863 char* group_name = reinterpret_cast<char*>(entry) + group_name_offset; | 908 char* group_name = reinterpret_cast<char*>(entry) + group_name_offset; |
864 memcpy(trial_name, trial_state.trial_name.data(), trial_name_size); | 909 memcpy(trial_name, trial_state.trial_name.data(), trial_name_size); |
865 memcpy(group_name, trial_state.group_name.data(), group_name_size); | 910 memcpy(group_name, trial_state.group_name.data(), group_name_size); |
866 | 911 |
867 // Null terminate the strings. | 912 // Null terminate the strings. |
868 trial_name[trial_state.trial_name.size()] = '\0'; | 913 trial_name[trial_state.trial_name.size()] = '\0'; |
869 group_name[trial_state.group_name.size()] = '\0'; | 914 group_name[trial_state.group_name.size()] = '\0'; |
870 | 915 |
871 allocator->MakeIterable(ref); | 916 allocator->MakeIterable(ref); |
| 917 field_trial->ref_ = ref; |
872 } | 918 } |
873 | 919 |
874 // static | 920 // static |
875 size_t FieldTrialList::GetFieldTrialCount() { | |
876 if (!global_) | |
877 return 0; | |
878 AutoLock auto_lock(global_->lock_); | |
879 return global_->registered_.size(); | |
880 } | |
881 | |
882 // static | |
883 const FieldTrial::EntropyProvider* | 921 const FieldTrial::EntropyProvider* |
884 FieldTrialList::GetEntropyProviderForOneTimeRandomization() { | 922 FieldTrialList::GetEntropyProviderForOneTimeRandomization() { |
885 if (!global_) { | 923 if (!global_) { |
886 used_without_global_ = true; | 924 used_without_global_ = true; |
887 return NULL; | 925 return NULL; |
888 } | 926 } |
889 | 927 |
890 return global_->entropy_provider_.get(); | 928 return global_->entropy_provider_.get(); |
891 } | 929 } |
892 | 930 |
(...skipping 11 matching lines...) Expand all Loading... |
904 return; | 942 return; |
905 } | 943 } |
906 AutoLock auto_lock(global_->lock_); | 944 AutoLock auto_lock(global_->lock_); |
907 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); | 945 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); |
908 trial->AddRef(); | 946 trial->AddRef(); |
909 trial->SetTrialRegistered(); | 947 trial->SetTrialRegistered(); |
910 global_->registered_[trial->trial_name()] = trial; | 948 global_->registered_[trial->trial_name()] = trial; |
911 } | 949 } |
912 | 950 |
913 } // namespace base | 951 } // namespace base |
OLD | NEW |