| Index: base/metrics/field_trial.cc
|
| diff --git a/base/metrics/field_trial.cc b/base/metrics/field_trial.cc
|
| index 911c8e5ee9842759c3c820929e268098e6a6dbd6..9f8a21265550f311b24f4ad1084173f843e7e70c 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 {
|
| @@ -673,30 +678,6 @@ void FieldTrialList::AppendFieldTrialHandleIfNeeded(
|
| #endif
|
|
|
| // static
|
| -void FieldTrialList::CreateTrialsFromSharedMemory(
|
| - std::unique_ptr<SharedMemory> shm) {
|
| - const SharedPersistentMemoryAllocator shalloc(std::move(shm), 0,
|
| - kAllocatorName, true);
|
| - PersistentMemoryAllocator::Iterator iter(&shalloc);
|
| -
|
| - SharedPersistentMemoryAllocator::Reference ref;
|
| - while ((ref = iter.GetNextOfType(kFieldTrialType)) !=
|
| - SharedPersistentMemoryAllocator::kReferenceNull) {
|
| - const FieldTrialEntry* entry =
|
| - shalloc.GetAsObject<const FieldTrialEntry>(ref, kFieldTrialType);
|
| - FieldTrial* trial =
|
| - CreateFieldTrial(entry->GetTrialName(), entry->GetGroupName());
|
| -
|
| - if (entry->activated) {
|
| - // Call |group()| to mark the trial as "used" and notify observers, if
|
| - // any. This is useful to ensure that field trials created in child
|
| - // processes are properly reported in crash reports.
|
| - trial->group();
|
| - }
|
| - }
|
| -}
|
| -
|
| -// static
|
| void FieldTrialList::CopyFieldTrialStateToFlags(
|
| const char* field_trial_handle_switch,
|
| CommandLine* cmd_line) {
|
| @@ -772,6 +753,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 +774,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)
|
| + ActivateFieldTrialEntryWhileLocked(field_trial);
|
| }
|
|
|
| global_->observer_list_->Notify(
|
| @@ -796,9 +783,43 @@ void FieldTrialList::NotifyFieldTrialGroupSelection(FieldTrial* field_trial) {
|
| field_trial->trial_name(), field_trial->group_name_internal());
|
| }
|
|
|
| +// static
|
| +size_t FieldTrialList::GetFieldTrialCount() {
|
| + if (!global_)
|
| + return 0;
|
| + AutoLock auto_lock(global_->lock_);
|
| + return global_->registered_.size();
|
| +}
|
| +
|
| +// static
|
| +void FieldTrialList::CreateTrialsFromSharedMemory(
|
| + std::unique_ptr<SharedMemory> shm) {
|
| + const SharedPersistentMemoryAllocator shalloc(std::move(shm), 0,
|
| + kAllocatorName, true);
|
| + PersistentMemoryAllocator::Iterator iter(&shalloc);
|
| +
|
| + SharedPersistentMemoryAllocator::Reference ref;
|
| + while ((ref = iter.GetNextOfType(kFieldTrialType)) !=
|
| + SharedPersistentMemoryAllocator::kReferenceNull) {
|
| + const FieldTrialEntry* entry =
|
| + shalloc.GetAsObject<const FieldTrialEntry>(ref, kFieldTrialType);
|
| + FieldTrial* trial =
|
| + CreateFieldTrial(entry->GetTrialName(), entry->GetGroupName());
|
| +
|
| + if (entry->activated) {
|
| + // Call |group()| to mark the trial as "used" and notify observers, if
|
| + // any. This is useful to ensure that field trials created in child
|
| + // processes are properly reported in crash reports.
|
| + trial->group();
|
| + }
|
| + }
|
| +}
|
| +
|
| #if !defined(OS_NACL)
|
| // static
|
| void FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded() {
|
| + 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)
|
| @@ -816,27 +837,33 @@ void FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded() {
|
|
|
| // Add all existing field trials.
|
| for (const auto& registered : global_->registered_) {
|
| - registered.second->AddToAllocatorWhileLocked(
|
| - global_->field_trial_allocator_.get());
|
| + AddToAllocatorWhileLocked(registered.second);
|
| }
|
|
|
| #if defined(OS_WIN)
|
| - // Set |readonly_allocator_handle_| so we can pass it to be inherited and via
|
| - // the command line.
|
| + // 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
|
| +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 +896,27 @@ void FieldTrial::AddToAllocatorWhileLocked(
|
| group_name[trial_state.group_name.size()] = '\0';
|
|
|
| allocator->MakeIterable(ref);
|
| + field_trial->ref_ = ref;
|
| }
|
|
|
| // static
|
| -size_t FieldTrialList::GetFieldTrialCount() {
|
| - if (!global_)
|
| - return 0;
|
| - AutoLock auto_lock(global_->lock_);
|
| - return global_->registered_.size();
|
| +void FieldTrialList::ActivateFieldTrialEntryWhileLocked(
|
| + 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.
|
| + 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;
|
| + }
|
| }
|
|
|
| // static
|
|
|