Chromium Code Reviews| Index: base/metrics/field_trial.cc |
| diff --git a/base/metrics/field_trial.cc b/base/metrics/field_trial.cc |
| index 911c8e5ee9842759c3c820929e268098e6a6dbd6..8ecfd0163f2aae51ee87c423cfd3ae3713d8cb87 100644 |
| --- a/base/metrics/field_trial.cc |
| +++ b/base/metrics/field_trial.cc |
| @@ -309,7 +309,8 @@ FieldTrial::FieldTrial(const std::string& trial_name, |
| enable_field_trial_(true), |
| forced_(false), |
| group_reported_(false), |
| - trial_registered_(false) { |
| + trial_registered_(false), |
| + ref_(SharedPersistentMemoryAllocator::kReferenceNull) { |
| DCHECK_GT(total_probability, 0); |
| DCHECK(!trial_name_.empty()); |
| DCHECK(!default_group_name_.empty()); |
| @@ -340,6 +341,10 @@ void FieldTrial::FinalizeGroupChoice() { |
| // finalized. |
| DCHECK(!forced_); |
| SetGroupChoice(default_group_name_, kDefaultGroupNumber); |
| + |
| + // Add the field trial to shared memory. |
| + if (kUseSharedMemoryForFieldTrials) |
| + FieldTrialList::OnGroupFinalized(this); |
| } |
| bool FieldTrial::GetActiveGroup(ActiveGroup* active_group) const { |
| @@ -772,6 +777,14 @@ void FieldTrialList::RemoveObserver(Observer* observer) { |
| } |
| // static |
| +void FieldTrialList::OnGroupFinalized(FieldTrial* field_trial) { |
| + if (!global_) |
| + return; |
| + AutoLock auto_lock(global_->lock_); |
| + AddToAllocatorWhileLocked(field_trial); |
| +} |
| + |
| +// static |
| void FieldTrialList::NotifyFieldTrialGroupSelection(FieldTrial* field_trial) { |
| if (!global_) |
| return; |
| @@ -785,10 +798,8 @@ void FieldTrialList::NotifyFieldTrialGroupSelection(FieldTrial* field_trial) { |
| if (!field_trial->enable_field_trial_) |
| return; |
| - if (kUseSharedMemoryForFieldTrials) { |
| - field_trial->AddToAllocatorWhileLocked( |
| - global_->field_trial_allocator_.get()); |
| - } |
| + if (kUseSharedMemoryForFieldTrials) |
| + ActivateFieldTrialEntry(field_trial); |
| } |
| global_->observer_list_->Notify( |
| @@ -796,47 +807,84 @@ void FieldTrialList::NotifyFieldTrialGroupSelection(FieldTrial* field_trial) { |
| field_trial->trial_name(), field_trial->group_name_internal()); |
| } |
| +// static |
| +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.
|
| + SharedPersistentMemoryAllocator* allocator = |
| + global_->field_trial_allocator_.get(); |
| + SharedPersistentMemoryAllocator::Reference ref = field_trial->ref_; |
| + if (ref == SharedPersistentMemoryAllocator::kReferenceNull) { |
| + // It's fine to do this even if the allocator hasn't been instantiated |
| + // yet -- it'll just return early. |
| + AddToAllocatorWhileLocked(field_trial); |
| + } else { |
| + // It's also okay to do this even though the callee doesn't have a lock -- |
| + // the only thing that happens on a stale read here is a slight performance |
| + // hit from the child re-synchronizing activation state. |
| + FieldTrialEntry* entry = |
| + allocator->GetAsObject<FieldTrialEntry>(ref, kFieldTrialType); |
| + entry->activated = true; |
| + } |
| +} |
| + |
| #if !defined(OS_NACL) |
| // static |
| void FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded() { |
| - AutoLock auto_lock(global_->lock_); |
| - // Create the allocator if not already created and add all existing trials. |
| - if (global_->field_trial_allocator_ != nullptr) |
| + if (!global_) |
| return; |
| + { |
|
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.
|
| + AutoLock auto_lock(global_->lock_); |
| + // Create the allocator if not already created and add all existing trials. |
| + if (global_->field_trial_allocator_ != nullptr) |
| + return; |
| - std::unique_ptr<SharedMemory> shm(new SharedMemory()); |
| - if (!shm->CreateAndMapAnonymous(kFieldTrialAllocationSize)) |
| - TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); |
| + std::unique_ptr<SharedMemory> shm(new SharedMemory()); |
| + if (!shm->CreateAndMapAnonymous(kFieldTrialAllocationSize)) |
| + TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); |
| - // TODO(lawrencewu): call UpdateTrackingHistograms() when all field trials |
| - // have been registered (perhaps in the destructor?) |
| - global_->field_trial_allocator_.reset(new SharedPersistentMemoryAllocator( |
| - std::move(shm), 0, kAllocatorName, false)); |
| - global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName); |
| + // TODO(lawrencewu): call UpdateTrackingHistograms() when all field trials |
| + // have been registered (perhaps in the destructor?) |
| + global_->field_trial_allocator_.reset(new SharedPersistentMemoryAllocator( |
| + std::move(shm), 0, kAllocatorName, false)); |
| + global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName); |
| - // Add all existing field trials. |
| - for (const auto& registered : global_->registered_) { |
| - registered.second->AddToAllocatorWhileLocked( |
| - global_->field_trial_allocator_.get()); |
| - } |
| + // Add all existing field trials. |
| + for (const auto& registered : global_->registered_) { |
| + AddToAllocatorWhileLocked(registered.second); |
| + } |
| #if defined(OS_WIN) |
| - // Set |readonly_allocator_handle_| so we can pass it to be inherited and via |
| - // the command line. |
| - global_->readonly_allocator_handle_ = |
| - CreateReadOnlyHandle(global_->field_trial_allocator_.get()); |
| + // Set |readonly_allocator_handle_| so we can pass it to be inherited and |
| + // via the command line. |
| + global_->readonly_allocator_handle_ = |
| + CreateReadOnlyHandle(global_->field_trial_allocator_.get()); |
| #endif |
| + } |
| } |
| #endif |
| -void FieldTrial::AddToAllocatorWhileLocked( |
| - SharedPersistentMemoryAllocator* allocator) { |
| +// static |
| +size_t FieldTrialList::GetFieldTrialCount() { |
| + if (!global_) |
| + return 0; |
| + AutoLock auto_lock(global_->lock_); |
| + return global_->registered_.size(); |
| +} |
| + |
| +// static |
| +void FieldTrialList::AddToAllocatorWhileLocked(FieldTrial* field_trial) { |
| + SharedPersistentMemoryAllocator* allocator = |
| + global_->field_trial_allocator_.get(); |
| + |
| // Don't do anything if the allocator hasn't been instantiated yet. |
| if (allocator == nullptr) |
| return; |
| - State trial_state; |
| - if (!GetState(&trial_state)) |
| + // Or if we've already added it. |
| + if (field_trial->ref_ != SharedPersistentMemoryAllocator::kReferenceNull) |
| + return; |
| + |
| + FieldTrial::State trial_state; |
| + if (!field_trial->GetState(&trial_state)) |
| return; |
| size_t trial_name_size = trial_state.trial_name.size() + 1; |
| @@ -869,14 +917,7 @@ void FieldTrial::AddToAllocatorWhileLocked( |
| group_name[trial_state.group_name.size()] = '\0'; |
| allocator->MakeIterable(ref); |
| -} |
| - |
| -// static |
| -size_t FieldTrialList::GetFieldTrialCount() { |
| - if (!global_) |
| - return 0; |
| - AutoLock auto_lock(global_->lock_); |
| - return global_->registered_.size(); |
| + field_trial->ref_ = ref; |
| } |
| // static |