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