Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1963)

Unified Diff: base/metrics/field_trial.cc

Issue 2560723004: Add field trial dump and retrieval methods from shared memory (Closed)
Patch Set: Move to FieldTrialEntry. Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: base/metrics/field_trial.cc
diff --git a/base/metrics/field_trial.cc b/base/metrics/field_trial.cc
index b53c932bd2008162510603e62df46030b84a8912..c5c6af0c5a845290a7e87108ab46cd47725a28f9 100644
--- a/base/metrics/field_trial.cc
+++ b/base/metrics/field_trial.cc
@@ -12,7 +12,6 @@
#include "base/command_line.h"
#include "base/logging.h"
#include "base/metrics/field_trial_param_associator.h"
-#include "base/pickle.h"
#include "base/process/memory.h"
#include "base/rand_util.h"
#include "base/strings/string_number_conversions.h"
@@ -69,70 +68,6 @@ const uint32_t kFieldTrialType = 0xABA17E13 + 2; // SHA1(FieldTrialEntry) v2
const size_t kFieldTrialAllocationSize = 128 << 10; // 128 KiB
#endif
-// We create one FieldTrialEntry per field trial in shared memory, via
-// AddToAllocatorWhileLocked. The FieldTrialEntry is followed by a base::Pickle
-// object that we unpickle and read from. Any changes to this structure requires
-// a bump in kFieldTrialType id defined above.
-struct FieldTrialEntry {
- // Expected size for 32/64-bit check.
- static constexpr size_t kExpectedInstanceSize = 8;
-
- // Whether or not this field trial is activated. This is really just a boolean
- // but marked as a uint32_t for portability reasons.
- uint32_t activated;
-
- // Size of the pickled structure, NOT the total size of this entry.
- uint32_t pickle_size;
-
- // Returns an iterator over the data containing names and params.
- PickleIterator GetPickleIterator() const {
- const char* src =
- reinterpret_cast<const char*>(this) + sizeof(FieldTrialEntry);
-
- Pickle pickle(src, pickle_size);
- return PickleIterator(pickle);
- }
-
- // Takes the iterator and writes out the first two items into |trial_name| and
- // |group_name|.
- bool ReadStringPair(PickleIterator* iter,
- StringPiece* trial_name,
- StringPiece* group_name) const {
- if (!iter->ReadStringPiece(trial_name))
- return false;
- if (!iter->ReadStringPiece(group_name))
- return false;
- return true;
- }
-
- // Calling this is only valid when the entry is initialized. That is, it
- // resides in shared memory and has a pickle containing the trial name and
- // group name following it.
- bool GetTrialAndGroupName(StringPiece* trial_name,
- StringPiece* group_name) const {
- PickleIterator iter = GetPickleIterator();
- return ReadStringPair(&iter, trial_name, group_name);
- }
-
- // Calling this is only valid when the entry is initialized as well. Reads the
- // parameters following the trial and group name and stores them as key-value
- // mappings in |params|.
- bool GetParams(std::map<std::string, std::string>* params) const {
- PickleIterator iter = GetPickleIterator();
- StringPiece tmp;
- if (!ReadStringPair(&iter, &tmp, &tmp))
- return false;
-
- while (true) {
- StringPiece key;
- StringPiece value;
- if (!ReadStringPair(&iter, &key, &value))
- return key.empty(); // Non-empty is bad: got one of a pair.
- (*params)[key.as_string()] = value.as_string();
- }
- }
-};
-
// Writes out string1 and then string2 to pickle.
bool WriteStringPair(Pickle* pickle,
const StringPiece& string1,
@@ -314,6 +249,48 @@ FieldTrial::State::State(const State& other) = default;
FieldTrial::State::~State() {}
+PickleIterator FieldTrial::FieldTrialEntry::GetPickleIterator() const {
+ const char* src =
+ reinterpret_cast<const char*>(this) + sizeof(FieldTrialEntry);
+
+ Pickle pickle(src, pickle_size);
+ return PickleIterator(pickle);
+}
+
+bool FieldTrial::FieldTrialEntry::ReadStringPair(
+ PickleIterator* iter,
+ StringPiece* trial_name,
+ StringPiece* group_name) const {
+ if (!iter->ReadStringPiece(trial_name))
+ return false;
+ if (!iter->ReadStringPiece(group_name))
+ return false;
+ return true;
+}
+
+bool FieldTrial::FieldTrialEntry::GetTrialAndGroupName(
+ StringPiece* trial_name,
+ StringPiece* group_name) const {
+ PickleIterator iter = GetPickleIterator();
+ return ReadStringPair(&iter, trial_name, group_name);
+}
+
+bool FieldTrial::FieldTrialEntry::GetParams(
+ std::map<std::string, std::string>* params) const {
+ PickleIterator iter = GetPickleIterator();
+ StringPiece tmp;
+ if (!ReadStringPair(&iter, &tmp, &tmp))
+ return false;
+
+ while (true) {
+ StringPiece key;
+ StringPiece value;
+ if (!ReadStringPair(&iter, &key, &value))
+ return key.empty(); // Non-empty is bad: got one of a pair.
+ (*params)[key.as_string()] = value.as_string();
+ }
+}
+
void FieldTrial::Disable() {
DCHECK(!group_reported_);
enable_field_trial_ = false;
@@ -742,8 +719,9 @@ void FieldTrialList::GetInitiallyActiveFieldTrials(
FieldTrial::FieldTrialRef ref;
while ((ref = mem_iter.GetNextOfType(kFieldTrialType)) !=
SharedPersistentMemoryAllocator::kReferenceNull) {
- const FieldTrialEntry* entry =
- allocator->GetAsObject<const FieldTrialEntry>(ref, kFieldTrialType);
+ const FieldTrial::FieldTrialEntry* entry =
+ allocator->GetAsObject<const FieldTrial::FieldTrialEntry>(
+ ref, kFieldTrialType);
StringPiece trial_name;
StringPiece group_name;
@@ -985,10 +963,12 @@ void FieldTrialList::OnGroupFinalized(bool is_locked, FieldTrial* field_trial) {
if (!global_)
return;
if (is_locked) {
- AddToAllocatorWhileLocked(field_trial);
+ AddToAllocatorWhileLocked(global_->field_trial_allocator_.get(),
+ field_trial);
} else {
AutoLock auto_lock(global_->lock_);
- AddToAllocatorWhileLocked(field_trial);
+ AddToAllocatorWhileLocked(global_->field_trial_allocator_.get(),
+ field_trial);
}
}
@@ -1047,13 +1027,14 @@ bool FieldTrialList::GetParamsFromSharedMemory(
if (!field_trial->ref_)
return false;
- const FieldTrialEntry* entry =
- global_->field_trial_allocator_->GetAsObject<const FieldTrialEntry>(
- field_trial->ref_, kFieldTrialType);
+ const FieldTrial::FieldTrialEntry* entry =
+ global_->field_trial_allocator_
+ ->GetAsObject<const FieldTrial::FieldTrialEntry>(field_trial->ref_,
+ kFieldTrialType);
size_t allocated_size =
global_->field_trial_allocator_->GetAllocSize(field_trial->ref_);
- size_t actual_size = sizeof(FieldTrialEntry) + entry->pickle_size;
+ size_t actual_size = sizeof(FieldTrial::FieldTrialEntry) + entry->pickle_size;
if (allocated_size < actual_size)
return false;
@@ -1083,9 +1064,9 @@ void FieldTrialList::ClearParamsFromSharedMemoryForTesting() {
while ((prev_ref = mem_iter.GetNextOfType(kFieldTrialType)) !=
FieldTrialAllocator::kReferenceNull) {
// Get the existing field trial entry in shared memory.
- const FieldTrialEntry* prev_entry =
- allocator->GetAsObject<const FieldTrialEntry>(prev_ref,
- kFieldTrialType);
+ const FieldTrial::FieldTrialEntry* prev_entry =
+ allocator->GetAsObject<const FieldTrial::FieldTrialEntry>(
+ prev_ref, kFieldTrialType);
StringPiece trial_name;
StringPiece group_name;
if (!prev_entry->GetTrialAndGroupName(&trial_name, &group_name))
@@ -1095,17 +1076,19 @@ void FieldTrialList::ClearParamsFromSharedMemoryForTesting() {
Pickle pickle;
pickle.WriteString(trial_name);
pickle.WriteString(group_name);
- size_t total_size = sizeof(FieldTrialEntry) + pickle.size();
+ size_t total_size = sizeof(FieldTrial::FieldTrialEntry) + pickle.size();
FieldTrial::FieldTrialRef new_ref =
allocator->Allocate(total_size, kFieldTrialType);
- FieldTrialEntry* new_entry =
- allocator->GetAsObject<FieldTrialEntry>(new_ref, kFieldTrialType);
+ FieldTrial::FieldTrialEntry* new_entry =
+ allocator->GetAsObject<FieldTrial::FieldTrialEntry>(new_ref,
+ kFieldTrialType);
new_entry->activated = prev_entry->activated;
new_entry->pickle_size = pickle.size();
// TODO(lawrencewu): Modify base::Pickle to be able to write over a section
// in memory, so we can avoid this memcpy.
- char* dst = reinterpret_cast<char*>(new_entry) + sizeof(FieldTrialEntry);
+ char* dst = reinterpret_cast<char*>(new_entry) +
+ sizeof(FieldTrial::FieldTrialEntry);
memcpy(dst, pickle.data(), pickle.size());
// Update the ref on the field trial and add it to the list to be made
@@ -1123,6 +1106,34 @@ void FieldTrialList::ClearParamsFromSharedMemoryForTesting() {
}
}
+// static
+void FieldTrialList::DumpAllFieldTrialsToPersistentAllocator(
+ PersistentMemoryAllocator* allocator) {
+ if (!global_)
+ return;
+ AutoLock auto_lock(global_->lock_);
+ for (const auto& registered : global_->registered_) {
+ AddToAllocatorWhileLocked(allocator, registered.second);
+ }
+}
+
+// static
+std::vector<FieldTrial::FieldTrialEntry*>
+FieldTrialList::GetAllFieldTrialsFromPersistentAllocator(
+ PersistentMemoryAllocator* allocator) {
+ std::vector<FieldTrial::FieldTrialEntry*> field_trial_entries;
+ FieldTrial::FieldTrialRef ref;
+ FieldTrialAllocator::Iterator iter(allocator);
+ while ((ref = iter.GetNextOfType(kFieldTrialType)) !=
+ FieldTrialAllocator::kReferenceNull) {
+ FieldTrial::FieldTrialEntry* entry =
bcwhite 2016/12/09 19:40:28 const
lawrencewu 2016/12/09 19:47:59 Done.
+ allocator->GetAsObject<FieldTrial::FieldTrialEntry>(ref,
+ kFieldTrialType);
+ field_trial_entries.push_back(entry);
+ }
+ return field_trial_entries;
+}
+
#if defined(OS_WIN)
// static
bool FieldTrialList::CreateTrialsFromHandleSwitch(
@@ -1159,8 +1170,9 @@ bool FieldTrialList::CreateTrialsFromSharedMemory(
FieldTrial::FieldTrialRef ref;
while ((ref = mem_iter.GetNextOfType(kFieldTrialType)) !=
FieldTrialAllocator::kReferenceNull) {
- const FieldTrialEntry* entry =
- shalloc->GetAsObject<const FieldTrialEntry>(ref, kFieldTrialType);
+ const FieldTrial::FieldTrialEntry* entry =
+ shalloc->GetAsObject<const FieldTrial::FieldTrialEntry>(
+ ref, kFieldTrialType);
StringPiece trial_name;
StringPiece group_name;
@@ -1210,7 +1222,8 @@ void FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded() {
// Add all existing field trials.
for (const auto& registered : global_->registered_) {
- AddToAllocatorWhileLocked(registered.second);
+ AddToAllocatorWhileLocked(global_->field_trial_allocator_.get(),
+ registered.second);
}
// Add all existing features.
@@ -1227,9 +1240,9 @@ void FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded() {
#endif
// static
-void FieldTrialList::AddToAllocatorWhileLocked(FieldTrial* field_trial) {
- FieldTrialAllocator* allocator = global_->field_trial_allocator_.get();
-
+void FieldTrialList::AddToAllocatorWhileLocked(
+ PersistentMemoryAllocator* allocator,
+ FieldTrial* field_trial) {
// Don't do anything if the allocator hasn't been instantiated yet.
if (allocator == nullptr)
return;
@@ -1254,7 +1267,7 @@ void FieldTrialList::AddToAllocatorWhileLocked(FieldTrial* field_trial) {
return;
}
- size_t total_size = sizeof(FieldTrialEntry) + pickle.size();
+ size_t total_size = sizeof(FieldTrial::FieldTrialEntry) + pickle.size();
FieldTrial::FieldTrialRef ref =
allocator->Allocate(total_size, kFieldTrialType);
if (ref == FieldTrialAllocator::kReferenceNull) {
@@ -1262,14 +1275,15 @@ void FieldTrialList::AddToAllocatorWhileLocked(FieldTrial* field_trial) {
return;
}
- FieldTrialEntry* entry =
- allocator->GetAsObject<FieldTrialEntry>(ref, kFieldTrialType);
+ FieldTrial::FieldTrialEntry* entry =
+ allocator->GetAsObject<FieldTrial::FieldTrialEntry>(ref, kFieldTrialType);
entry->activated = trial_state.activated;
entry->pickle_size = pickle.size();
// TODO(lawrencewu): Modify base::Pickle to be able to write over a section in
// memory, so we can avoid this memcpy.
- char* dst = reinterpret_cast<char*>(entry) + sizeof(FieldTrialEntry);
+ char* dst =
+ reinterpret_cast<char*>(entry) + sizeof(FieldTrial::FieldTrialEntry);
memcpy(dst, pickle.data(), pickle.size());
allocator->MakeIterable(ref);
@@ -1289,13 +1303,15 @@ void FieldTrialList::ActivateFieldTrialEntryWhileLocked(
if (ref == FieldTrialAllocator::kReferenceNull) {
// It's fine to do this even if the allocator hasn't been instantiated
// yet -- it'll just return early.
- AddToAllocatorWhileLocked(field_trial);
+ AddToAllocatorWhileLocked(global_->field_trial_allocator_.get(),
+ 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);
+ FieldTrial::FieldTrialEntry* entry =
+ allocator->GetAsObject<FieldTrial::FieldTrialEntry>(ref,
+ kFieldTrialType);
entry->activated = true;
}
}

Powered by Google App Engine
This is Rietveld 408576698