| Index: base/metrics/field_trial.cc
|
| diff --git a/base/metrics/field_trial.cc b/base/metrics/field_trial.cc
|
| index 911c8e5ee9842759c3c820929e268098e6a6dbd6..b96d15a5d9fb3307d586af6e33c9171cfcffb9ef 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::AddToAllocator(this);
|
| }
|
|
|
| bool FieldTrial::GetActiveGroup(ActiveGroup* active_group) const {
|
| @@ -784,59 +789,99 @@ 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(
|
| FROM_HERE, &FieldTrialList::Observer::OnFieldTrialGroupFinalized,
|
| field_trial->trial_name(), field_trial->group_name_internal());
|
| }
|
|
|
| +// static
|
| +void FieldTrialList::ActivateFieldTrialEntry(FieldTrial* field_trial) {
|
| + 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.
|
| + AddToAllocator(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;
|
| + {
|
| + 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);
|
| -
|
| - // 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);
|
| + std::unique_ptr<SharedMemory> shm(new SharedMemory());
|
| + if (!shm->CreateAndMapAnonymous(kFieldTrialAllocationSize))
|
| + TerminateBecauseOutOfMemory(kFieldTrialAllocationSize);
|
|
|
| - // Add all existing field trials.
|
| - for (const auto& registered : global_->registered_) {
|
| - registered.second->AddToAllocatorWhileLocked(
|
| - global_->field_trial_allocator_.get());
|
| - }
|
| + // 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);
|
|
|
| #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
|
| + }
|
| +
|
| + // Add all existing field trials. Needs to be outside the lock since
|
| + // AddToAllocator locks as well.
|
| + for (const auto& registered : global_->registered_) {
|
| + AddToAllocator(registered.second);
|
| + }
|
| }
|
| #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::AddToAllocator(FieldTrial* field_trial) {
|
| + if (!global_)
|
| + return;
|
| + AutoLock auto_lock(global_->lock_);
|
| +
|
| + 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 +914,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
|
|
|