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

Side by Side Diff: base/metrics/field_trial.cc

Issue 2560723004: Add field trial dump and retrieval methods from shared memory (Closed)
Patch Set: add BASE_EXPORT 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 unified diff | Download patch
« no previous file with comments | « base/metrics/field_trial.h ('k') | base/metrics/field_trial_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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"
11 #include "base/build_time.h" 11 #include "base/build_time.h"
12 #include "base/command_line.h" 12 #include "base/command_line.h"
13 #include "base/logging.h" 13 #include "base/logging.h"
14 #include "base/metrics/field_trial_param_associator.h" 14 #include "base/metrics/field_trial_param_associator.h"
15 #include "base/pickle.h"
16 #include "base/process/memory.h" 15 #include "base/process/memory.h"
17 #include "base/rand_util.h" 16 #include "base/rand_util.h"
18 #include "base/strings/string_number_conversions.h" 17 #include "base/strings/string_number_conversions.h"
19 #include "base/strings/string_util.h" 18 #include "base/strings/string_util.h"
20 #include "base/strings/stringprintf.h" 19 #include "base/strings/stringprintf.h"
21 #include "base/strings/utf_string_conversions.h" 20 #include "base/strings/utf_string_conversions.h"
22 21
23 // On systems that use the zygote process to spawn child processes, we must 22 // On systems that use the zygote process to spawn child processes, we must
24 // retrieve the correct fd using the mapping in GlobalDescriptors. 23 // retrieve the correct fd using the mapping in GlobalDescriptors.
25 #if defined(OS_POSIX) && !defined(OS_NACL) && !defined(OS_MACOSX) && \ 24 #if defined(OS_POSIX) && !defined(OS_NACL) && !defined(OS_MACOSX) && \
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
62 // as most people use 3 - 25 KiB for field trials (as of 11/25/2016). 61 // as most people use 3 - 25 KiB for field trials (as of 11/25/2016).
63 // This also doesn't allocate all 128 KiB at once -- the pages only get mapped 62 // This also doesn't allocate all 128 KiB at once -- the pages only get mapped
64 // to physical memory when they are touched. If the size of the allocated field 63 // to physical memory when they are touched. If the size of the allocated field
65 // trials does get larger than 128 KiB, then we will drop some field trials in 64 // trials does get larger than 128 KiB, then we will drop some field trials in
66 // child processes, leading to an inconsistent view between browser and child 65 // child processes, leading to an inconsistent view between browser and child
67 // processes and possibly causing crashes (see crbug.com/661617). 66 // processes and possibly causing crashes (see crbug.com/661617).
68 #if !defined(OS_NACL) 67 #if !defined(OS_NACL)
69 const size_t kFieldTrialAllocationSize = 128 << 10; // 128 KiB 68 const size_t kFieldTrialAllocationSize = 128 << 10; // 128 KiB
70 #endif 69 #endif
71 70
72 // We create one FieldTrialEntry per field trial in shared memory, via
73 // AddToAllocatorWhileLocked. The FieldTrialEntry is followed by a base::Pickle
74 // object that we unpickle and read from. Any changes to this structure requires
75 // a bump in kFieldTrialType id defined above.
76 struct FieldTrialEntry {
77 // Expected size for 32/64-bit check.
78 static constexpr size_t kExpectedInstanceSize = 8;
79
80 // Whether or not this field trial is activated. This is really just a boolean
81 // but marked as a uint32_t for portability reasons.
82 uint32_t activated;
83
84 // Size of the pickled structure, NOT the total size of this entry.
85 uint32_t pickle_size;
86
87 // Returns an iterator over the data containing names and params.
88 PickleIterator GetPickleIterator() const {
89 const char* src =
90 reinterpret_cast<const char*>(this) + sizeof(FieldTrialEntry);
91
92 Pickle pickle(src, pickle_size);
93 return PickleIterator(pickle);
94 }
95
96 // Takes the iterator and writes out the first two items into |trial_name| and
97 // |group_name|.
98 bool ReadStringPair(PickleIterator* iter,
99 StringPiece* trial_name,
100 StringPiece* group_name) const {
101 if (!iter->ReadStringPiece(trial_name))
102 return false;
103 if (!iter->ReadStringPiece(group_name))
104 return false;
105 return true;
106 }
107
108 // Calling this is only valid when the entry is initialized. That is, it
109 // resides in shared memory and has a pickle containing the trial name and
110 // group name following it.
111 bool GetTrialAndGroupName(StringPiece* trial_name,
112 StringPiece* group_name) const {
113 PickleIterator iter = GetPickleIterator();
114 return ReadStringPair(&iter, trial_name, group_name);
115 }
116
117 // Calling this is only valid when the entry is initialized as well. Reads the
118 // parameters following the trial and group name and stores them as key-value
119 // mappings in |params|.
120 bool GetParams(std::map<std::string, std::string>* params) const {
121 PickleIterator iter = GetPickleIterator();
122 StringPiece tmp;
123 if (!ReadStringPair(&iter, &tmp, &tmp))
124 return false;
125
126 while (true) {
127 StringPiece key;
128 StringPiece value;
129 if (!ReadStringPair(&iter, &key, &value))
130 return key.empty(); // Non-empty is bad: got one of a pair.
131 (*params)[key.as_string()] = value.as_string();
132 }
133 }
134 };
135
136 // Writes out string1 and then string2 to pickle. 71 // Writes out string1 and then string2 to pickle.
137 bool WriteStringPair(Pickle* pickle, 72 bool WriteStringPair(Pickle* pickle,
138 const StringPiece& string1, 73 const StringPiece& string1,
139 const StringPiece& string2) { 74 const StringPiece& string2) {
140 if (!pickle->WriteString(string1)) 75 if (!pickle->WriteString(string1))
141 return false; 76 return false;
142 if (!pickle->WriteString(string2)) 77 if (!pickle->WriteString(string2))
143 return false; 78 return false;
144 return true; 79 return true;
145 } 80 }
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after
307 242
308 FieldTrial::EntropyProvider::~EntropyProvider() { 243 FieldTrial::EntropyProvider::~EntropyProvider() {
309 } 244 }
310 245
311 FieldTrial::State::State() : activated(false) {} 246 FieldTrial::State::State() : activated(false) {}
312 247
313 FieldTrial::State::State(const State& other) = default; 248 FieldTrial::State::State(const State& other) = default;
314 249
315 FieldTrial::State::~State() {} 250 FieldTrial::State::~State() {}
316 251
252 bool FieldTrial::FieldTrialEntry::GetTrialAndGroupName(
253 StringPiece* trial_name,
254 StringPiece* group_name) const {
255 PickleIterator iter = GetPickleIterator();
256 return ReadStringPair(&iter, trial_name, group_name);
257 }
258
259 bool FieldTrial::FieldTrialEntry::GetParams(
260 std::map<std::string, std::string>* params) const {
261 PickleIterator iter = GetPickleIterator();
262 StringPiece tmp;
263 // Skip reading trial and group name.
264 if (!ReadStringPair(&iter, &tmp, &tmp))
265 return false;
266
267 while (true) {
268 StringPiece key;
269 StringPiece value;
270 if (!ReadStringPair(&iter, &key, &value))
271 return key.empty(); // Non-empty is bad: got one of a pair.
272 (*params)[key.as_string()] = value.as_string();
273 }
274 }
275
276 PickleIterator FieldTrial::FieldTrialEntry::GetPickleIterator() const {
277 const char* src =
278 reinterpret_cast<const char*>(this) + sizeof(FieldTrialEntry);
279
280 Pickle pickle(src, pickle_size);
281 return PickleIterator(pickle);
282 }
283
284 bool FieldTrial::FieldTrialEntry::ReadStringPair(
285 PickleIterator* iter,
286 StringPiece* trial_name,
287 StringPiece* group_name) const {
288 if (!iter->ReadStringPiece(trial_name))
289 return false;
290 if (!iter->ReadStringPiece(group_name))
291 return false;
292 return true;
293 }
294
317 void FieldTrial::Disable() { 295 void FieldTrial::Disable() {
318 DCHECK(!group_reported_); 296 DCHECK(!group_reported_);
319 enable_field_trial_ = false; 297 enable_field_trial_ = false;
320 298
321 // In case we are disabled after initialization, we need to switch 299 // In case we are disabled after initialization, we need to switch
322 // the trial to the default group. 300 // the trial to the default group.
323 if (group_ != kNotFinalized) { 301 if (group_ != kNotFinalized) {
324 // Only reset when not already the default group, because in case we were 302 // Only reset when not already the default group, because in case we were
325 // forced to the default group, the group number may not be 303 // forced to the default group, the group number may not be
326 // kDefaultGroupNumber, so we should keep it as is. 304 // kDefaultGroupNumber, so we should keep it as is.
(...skipping 408 matching lines...) Expand 10 before | Expand all | Expand 10 after
735 command_line.GetSwitchValueASCII(switches::kForceFieldTrials), 713 command_line.GetSwitchValueASCII(switches::kForceFieldTrials),
736 active_groups); 714 active_groups);
737 return; 715 return;
738 } 716 }
739 717
740 FieldTrialAllocator* allocator = global_->field_trial_allocator_.get(); 718 FieldTrialAllocator* allocator = global_->field_trial_allocator_.get();
741 FieldTrialAllocator::Iterator mem_iter(allocator); 719 FieldTrialAllocator::Iterator mem_iter(allocator);
742 FieldTrial::FieldTrialRef ref; 720 FieldTrial::FieldTrialRef ref;
743 while ((ref = mem_iter.GetNextOfType(kFieldTrialType)) != 721 while ((ref = mem_iter.GetNextOfType(kFieldTrialType)) !=
744 SharedPersistentMemoryAllocator::kReferenceNull) { 722 SharedPersistentMemoryAllocator::kReferenceNull) {
745 const FieldTrialEntry* entry = 723 const FieldTrial::FieldTrialEntry* entry =
746 allocator->GetAsObject<const FieldTrialEntry>(ref, kFieldTrialType); 724 allocator->GetAsObject<const FieldTrial::FieldTrialEntry>(
725 ref, kFieldTrialType);
747 726
748 StringPiece trial_name; 727 StringPiece trial_name;
749 StringPiece group_name; 728 StringPiece group_name;
750 if (entry->activated && 729 if (entry->activated &&
751 entry->GetTrialAndGroupName(&trial_name, &group_name)) { 730 entry->GetTrialAndGroupName(&trial_name, &group_name)) {
752 FieldTrial::ActiveGroup group; 731 FieldTrial::ActiveGroup group;
753 group.trial_name = trial_name.as_string(); 732 group.trial_name = trial_name.as_string();
754 group.group_name = group_name.as_string(); 733 group.group_name = group_name.as_string();
755 active_groups->push_back(group); 734 active_groups->push_back(group);
756 } 735 }
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after
978 if (!global_) 957 if (!global_)
979 return; 958 return;
980 global_->observer_list_->RemoveObserver(observer); 959 global_->observer_list_->RemoveObserver(observer);
981 } 960 }
982 961
983 // static 962 // static
984 void FieldTrialList::OnGroupFinalized(bool is_locked, FieldTrial* field_trial) { 963 void FieldTrialList::OnGroupFinalized(bool is_locked, FieldTrial* field_trial) {
985 if (!global_) 964 if (!global_)
986 return; 965 return;
987 if (is_locked) { 966 if (is_locked) {
988 AddToAllocatorWhileLocked(field_trial); 967 AddToAllocatorWhileLocked(global_->field_trial_allocator_.get(),
968 field_trial);
989 } else { 969 } else {
990 AutoLock auto_lock(global_->lock_); 970 AutoLock auto_lock(global_->lock_);
991 AddToAllocatorWhileLocked(field_trial); 971 AddToAllocatorWhileLocked(global_->field_trial_allocator_.get(),
972 field_trial);
992 } 973 }
993 } 974 }
994 975
995 // static 976 // static
996 void FieldTrialList::NotifyFieldTrialGroupSelection(FieldTrial* field_trial) { 977 void FieldTrialList::NotifyFieldTrialGroupSelection(FieldTrial* field_trial) {
997 if (!global_) 978 if (!global_)
998 return; 979 return;
999 980
1000 { 981 {
1001 AutoLock auto_lock(global_->lock_); 982 AutoLock auto_lock(global_->lock_);
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
1040 // allocator should get set up very early in the lifecycle. Try to see if 1021 // allocator should get set up very early in the lifecycle. Try to see if
1041 // you can call it after it's been set up. 1022 // you can call it after it's been set up.
1042 AutoLock auto_lock(global_->lock_); 1023 AutoLock auto_lock(global_->lock_);
1043 if (!global_->field_trial_allocator_) 1024 if (!global_->field_trial_allocator_)
1044 return false; 1025 return false;
1045 1026
1046 // If ref_ isn't set, then the field trial data can't be in shared memory. 1027 // If ref_ isn't set, then the field trial data can't be in shared memory.
1047 if (!field_trial->ref_) 1028 if (!field_trial->ref_)
1048 return false; 1029 return false;
1049 1030
1050 const FieldTrialEntry* entry = 1031 const FieldTrial::FieldTrialEntry* entry =
1051 global_->field_trial_allocator_->GetAsObject<const FieldTrialEntry>( 1032 global_->field_trial_allocator_
1052 field_trial->ref_, kFieldTrialType); 1033 ->GetAsObject<const FieldTrial::FieldTrialEntry>(field_trial->ref_,
1034 kFieldTrialType);
1053 1035
1054 size_t allocated_size = 1036 size_t allocated_size =
1055 global_->field_trial_allocator_->GetAllocSize(field_trial->ref_); 1037 global_->field_trial_allocator_->GetAllocSize(field_trial->ref_);
1056 size_t actual_size = sizeof(FieldTrialEntry) + entry->pickle_size; 1038 size_t actual_size = sizeof(FieldTrial::FieldTrialEntry) + entry->pickle_size;
1057 if (allocated_size < actual_size) 1039 if (allocated_size < actual_size)
1058 return false; 1040 return false;
1059 1041
1060 return entry->GetParams(params); 1042 return entry->GetParams(params);
1061 } 1043 }
1062 1044
1063 // static 1045 // static
1064 void FieldTrialList::ClearParamsFromSharedMemoryForTesting() { 1046 void FieldTrialList::ClearParamsFromSharedMemoryForTesting() {
1065 if (!global_) 1047 if (!global_)
1066 return; 1048 return;
1067 1049
1068 AutoLock auto_lock(global_->lock_); 1050 AutoLock auto_lock(global_->lock_);
1069 if (!global_->field_trial_allocator_) 1051 if (!global_->field_trial_allocator_)
1070 return; 1052 return;
1071 1053
1072 // To clear the params, we iterate through every item in the allocator, copy 1054 // To clear the params, we iterate through every item in the allocator, copy
1073 // just the trial and group name into a newly-allocated segment and then clear 1055 // just the trial and group name into a newly-allocated segment and then clear
1074 // the existing item. 1056 // the existing item.
1075 FieldTrialAllocator* allocator = global_->field_trial_allocator_.get(); 1057 FieldTrialAllocator* allocator = global_->field_trial_allocator_.get();
1076 FieldTrialAllocator::Iterator mem_iter(allocator); 1058 FieldTrialAllocator::Iterator mem_iter(allocator);
1077 1059
1078 // List of refs to eventually be made iterable. We can't make it in the loop, 1060 // List of refs to eventually be made iterable. We can't make it in the loop,
1079 // since it would go on forever. 1061 // since it would go on forever.
1080 std::vector<FieldTrial::FieldTrialRef> new_refs; 1062 std::vector<FieldTrial::FieldTrialRef> new_refs;
1081 1063
1082 FieldTrial::FieldTrialRef prev_ref; 1064 FieldTrial::FieldTrialRef prev_ref;
1083 while ((prev_ref = mem_iter.GetNextOfType(kFieldTrialType)) != 1065 while ((prev_ref = mem_iter.GetNextOfType(kFieldTrialType)) !=
1084 FieldTrialAllocator::kReferenceNull) { 1066 FieldTrialAllocator::kReferenceNull) {
1085 // Get the existing field trial entry in shared memory. 1067 // Get the existing field trial entry in shared memory.
1086 const FieldTrialEntry* prev_entry = 1068 const FieldTrial::FieldTrialEntry* prev_entry =
1087 allocator->GetAsObject<const FieldTrialEntry>(prev_ref, 1069 allocator->GetAsObject<const FieldTrial::FieldTrialEntry>(
1088 kFieldTrialType); 1070 prev_ref, kFieldTrialType);
1089 StringPiece trial_name; 1071 StringPiece trial_name;
1090 StringPiece group_name; 1072 StringPiece group_name;
1091 if (!prev_entry->GetTrialAndGroupName(&trial_name, &group_name)) 1073 if (!prev_entry->GetTrialAndGroupName(&trial_name, &group_name))
1092 continue; 1074 continue;
1093 1075
1094 // Write a new entry, minus the params. 1076 // Write a new entry, minus the params.
1095 Pickle pickle; 1077 Pickle pickle;
1096 pickle.WriteString(trial_name); 1078 pickle.WriteString(trial_name);
1097 pickle.WriteString(group_name); 1079 pickle.WriteString(group_name);
1098 size_t total_size = sizeof(FieldTrialEntry) + pickle.size(); 1080 size_t total_size = sizeof(FieldTrial::FieldTrialEntry) + pickle.size();
1099 FieldTrial::FieldTrialRef new_ref = 1081 FieldTrial::FieldTrialRef new_ref =
1100 allocator->Allocate(total_size, kFieldTrialType); 1082 allocator->Allocate(total_size, kFieldTrialType);
1101 FieldTrialEntry* new_entry = 1083 FieldTrial::FieldTrialEntry* new_entry =
1102 allocator->GetAsObject<FieldTrialEntry>(new_ref, kFieldTrialType); 1084 allocator->GetAsObject<FieldTrial::FieldTrialEntry>(new_ref,
1085 kFieldTrialType);
1103 new_entry->activated = prev_entry->activated; 1086 new_entry->activated = prev_entry->activated;
1104 new_entry->pickle_size = pickle.size(); 1087 new_entry->pickle_size = pickle.size();
1105 1088
1106 // TODO(lawrencewu): Modify base::Pickle to be able to write over a section 1089 // TODO(lawrencewu): Modify base::Pickle to be able to write over a section
1107 // in memory, so we can avoid this memcpy. 1090 // in memory, so we can avoid this memcpy.
1108 char* dst = reinterpret_cast<char*>(new_entry) + sizeof(FieldTrialEntry); 1091 char* dst = reinterpret_cast<char*>(new_entry) +
1092 sizeof(FieldTrial::FieldTrialEntry);
1109 memcpy(dst, pickle.data(), pickle.size()); 1093 memcpy(dst, pickle.data(), pickle.size());
1110 1094
1111 // Update the ref on the field trial and add it to the list to be made 1095 // Update the ref on the field trial and add it to the list to be made
1112 // iterable. 1096 // iterable.
1113 FieldTrial* trial = global_->PreLockedFind(trial_name.as_string()); 1097 FieldTrial* trial = global_->PreLockedFind(trial_name.as_string());
1114 trial->ref_ = new_ref; 1098 trial->ref_ = new_ref;
1115 new_refs.push_back(new_ref); 1099 new_refs.push_back(new_ref);
1116 1100
1117 // Mark the existing entry as unused. 1101 // Mark the existing entry as unused.
1118 allocator->ChangeType(prev_ref, 0, kFieldTrialType); 1102 allocator->ChangeType(prev_ref, 0, kFieldTrialType);
1119 } 1103 }
1120 1104
1121 for (const auto& ref : new_refs) { 1105 for (const auto& ref : new_refs) {
1122 allocator->MakeIterable(ref); 1106 allocator->MakeIterable(ref);
1123 } 1107 }
1124 } 1108 }
1125 1109
1110 // static
1111 void FieldTrialList::DumpAllFieldTrialsToPersistentAllocator(
1112 PersistentMemoryAllocator* allocator) {
1113 if (!global_)
1114 return;
1115 AutoLock auto_lock(global_->lock_);
1116 for (const auto& registered : global_->registered_) {
1117 AddToAllocatorWhileLocked(allocator, registered.second);
1118 }
1119 }
1120
1121 // static
1122 std::vector<const FieldTrial::FieldTrialEntry*>
1123 FieldTrialList::GetAllFieldTrialsFromPersistentAllocator(
1124 PersistentMemoryAllocator const& allocator) {
1125 std::vector<const FieldTrial::FieldTrialEntry*> entries;
1126 FieldTrial::FieldTrialRef ref;
1127 FieldTrialAllocator::Iterator iter(&allocator);
1128 while ((ref = iter.GetNextOfType(kFieldTrialType)) !=
1129 FieldTrialAllocator::kReferenceNull) {
1130 const FieldTrial::FieldTrialEntry* entry =
1131 allocator.GetAsObject<const FieldTrial::FieldTrialEntry>(
1132 ref, kFieldTrialType);
1133 entries.push_back(entry);
1134 }
1135 return entries;
1136 }
1137
1126 #if defined(OS_WIN) 1138 #if defined(OS_WIN)
1127 // static 1139 // static
1128 bool FieldTrialList::CreateTrialsFromHandleSwitch( 1140 bool FieldTrialList::CreateTrialsFromHandleSwitch(
1129 const std::string& handle_switch) { 1141 const std::string& handle_switch) {
1130 int field_trial_handle = std::stoi(handle_switch); 1142 int field_trial_handle = std::stoi(handle_switch);
1131 HANDLE handle = reinterpret_cast<HANDLE>(field_trial_handle); 1143 HANDLE handle = reinterpret_cast<HANDLE>(field_trial_handle);
1132 SharedMemoryHandle shm_handle(handle, GetCurrentProcId()); 1144 SharedMemoryHandle shm_handle(handle, GetCurrentProcId());
1133 return FieldTrialList::CreateTrialsFromSharedMemoryHandle(shm_handle); 1145 return FieldTrialList::CreateTrialsFromSharedMemoryHandle(shm_handle);
1134 } 1146 }
1135 #endif 1147 #endif
(...skipping 16 matching lines...) Expand all
1152 bool FieldTrialList::CreateTrialsFromSharedMemory( 1164 bool FieldTrialList::CreateTrialsFromSharedMemory(
1153 std::unique_ptr<SharedMemory> shm) { 1165 std::unique_ptr<SharedMemory> shm) {
1154 global_->field_trial_allocator_.reset( 1166 global_->field_trial_allocator_.reset(
1155 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, true)); 1167 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, true));
1156 FieldTrialAllocator* shalloc = global_->field_trial_allocator_.get(); 1168 FieldTrialAllocator* shalloc = global_->field_trial_allocator_.get();
1157 FieldTrialAllocator::Iterator mem_iter(shalloc); 1169 FieldTrialAllocator::Iterator mem_iter(shalloc);
1158 1170
1159 FieldTrial::FieldTrialRef ref; 1171 FieldTrial::FieldTrialRef ref;
1160 while ((ref = mem_iter.GetNextOfType(kFieldTrialType)) != 1172 while ((ref = mem_iter.GetNextOfType(kFieldTrialType)) !=
1161 FieldTrialAllocator::kReferenceNull) { 1173 FieldTrialAllocator::kReferenceNull) {
1162 const FieldTrialEntry* entry = 1174 const FieldTrial::FieldTrialEntry* entry =
1163 shalloc->GetAsObject<const FieldTrialEntry>(ref, kFieldTrialType); 1175 shalloc->GetAsObject<const FieldTrial::FieldTrialEntry>(
1176 ref, kFieldTrialType);
1164 1177
1165 StringPiece trial_name; 1178 StringPiece trial_name;
1166 StringPiece group_name; 1179 StringPiece group_name;
1167 if (!entry->GetTrialAndGroupName(&trial_name, &group_name)) 1180 if (!entry->GetTrialAndGroupName(&trial_name, &group_name))
1168 return false; 1181 return false;
1169 1182
1170 // TODO(lawrencewu): Convert the API for CreateFieldTrial to take 1183 // TODO(lawrencewu): Convert the API for CreateFieldTrial to take
1171 // StringPieces. 1184 // StringPieces.
1172 FieldTrial* trial = 1185 FieldTrial* trial =
1173 CreateFieldTrial(trial_name.as_string(), group_name.as_string()); 1186 CreateFieldTrial(trial_name.as_string(), group_name.as_string());
(...skipping 29 matching lines...) Expand all
1203 1216
1204 if (!shm->Map(kFieldTrialAllocationSize)) 1217 if (!shm->Map(kFieldTrialAllocationSize))
1205 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); 1218 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize);
1206 1219
1207 global_->field_trial_allocator_.reset( 1220 global_->field_trial_allocator_.reset(
1208 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, false)); 1221 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, false));
1209 global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName); 1222 global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName);
1210 1223
1211 // Add all existing field trials. 1224 // Add all existing field trials.
1212 for (const auto& registered : global_->registered_) { 1225 for (const auto& registered : global_->registered_) {
1213 AddToAllocatorWhileLocked(registered.second); 1226 AddToAllocatorWhileLocked(global_->field_trial_allocator_.get(),
1227 registered.second);
1214 } 1228 }
1215 1229
1216 // Add all existing features. 1230 // Add all existing features.
1217 FeatureList::GetInstance()->AddFeaturesToAllocator( 1231 FeatureList::GetInstance()->AddFeaturesToAllocator(
1218 global_->field_trial_allocator_.get()); 1232 global_->field_trial_allocator_.get());
1219 1233
1220 #if defined(OS_WIN) || defined(POSIX_WITH_ZYGOTE) 1234 #if defined(OS_WIN) || defined(POSIX_WITH_ZYGOTE)
1221 // Set |readonly_allocator_handle_| so we can pass it to be inherited and 1235 // Set |readonly_allocator_handle_| so we can pass it to be inherited and
1222 // via the command line. 1236 // via the command line.
1223 global_->readonly_allocator_handle_ = 1237 global_->readonly_allocator_handle_ =
1224 CreateReadOnlyHandle(global_->field_trial_allocator_.get()); 1238 CreateReadOnlyHandle(global_->field_trial_allocator_.get());
1225 #endif 1239 #endif
1226 } 1240 }
1227 #endif 1241 #endif
1228 1242
1229 // static 1243 // static
1230 void FieldTrialList::AddToAllocatorWhileLocked(FieldTrial* field_trial) { 1244 void FieldTrialList::AddToAllocatorWhileLocked(
1231 FieldTrialAllocator* allocator = global_->field_trial_allocator_.get(); 1245 PersistentMemoryAllocator* allocator,
1232 1246 FieldTrial* field_trial) {
1233 // Don't do anything if the allocator hasn't been instantiated yet. 1247 // Don't do anything if the allocator hasn't been instantiated yet.
1234 if (allocator == nullptr) 1248 if (allocator == nullptr)
1235 return; 1249 return;
1236 1250
1237 // Or if the allocator is read only, which means we are in a child process and 1251 // Or if the allocator is read only, which means we are in a child process and
1238 // shouldn't be writing to it. 1252 // shouldn't be writing to it.
1239 if (allocator->IsReadonly()) 1253 if (allocator->IsReadonly())
1240 return; 1254 return;
1241 1255
1242 FieldTrial::State trial_state; 1256 FieldTrial::State trial_state;
1243 if (!field_trial->GetStateWhileLocked(&trial_state)) 1257 if (!field_trial->GetStateWhileLocked(&trial_state))
1244 return; 1258 return;
1245 1259
1246 // Or if we've already added it. We must check after GetState since it can 1260 // Or if we've already added it. We must check after GetState since it can
1247 // also add to the allocator. 1261 // also add to the allocator.
1248 if (field_trial->ref_) 1262 if (field_trial->ref_)
1249 return; 1263 return;
1250 1264
1251 Pickle pickle; 1265 Pickle pickle;
1252 if (!PickleFieldTrial(trial_state, &pickle)) { 1266 if (!PickleFieldTrial(trial_state, &pickle)) {
1253 NOTREACHED(); 1267 NOTREACHED();
1254 return; 1268 return;
1255 } 1269 }
1256 1270
1257 size_t total_size = sizeof(FieldTrialEntry) + pickle.size(); 1271 size_t total_size = sizeof(FieldTrial::FieldTrialEntry) + pickle.size();
1258 FieldTrial::FieldTrialRef ref = 1272 FieldTrial::FieldTrialRef ref =
1259 allocator->Allocate(total_size, kFieldTrialType); 1273 allocator->Allocate(total_size, kFieldTrialType);
1260 if (ref == FieldTrialAllocator::kReferenceNull) { 1274 if (ref == FieldTrialAllocator::kReferenceNull) {
1261 NOTREACHED(); 1275 NOTREACHED();
1262 return; 1276 return;
1263 } 1277 }
1264 1278
1265 FieldTrialEntry* entry = 1279 FieldTrial::FieldTrialEntry* entry =
1266 allocator->GetAsObject<FieldTrialEntry>(ref, kFieldTrialType); 1280 allocator->GetAsObject<FieldTrial::FieldTrialEntry>(ref, kFieldTrialType);
1267 entry->activated = trial_state.activated; 1281 entry->activated = trial_state.activated;
1268 entry->pickle_size = pickle.size(); 1282 entry->pickle_size = pickle.size();
1269 1283
1270 // TODO(lawrencewu): Modify base::Pickle to be able to write over a section in 1284 // TODO(lawrencewu): Modify base::Pickle to be able to write over a section in
1271 // memory, so we can avoid this memcpy. 1285 // memory, so we can avoid this memcpy.
1272 char* dst = reinterpret_cast<char*>(entry) + sizeof(FieldTrialEntry); 1286 char* dst =
1287 reinterpret_cast<char*>(entry) + sizeof(FieldTrial::FieldTrialEntry);
1273 memcpy(dst, pickle.data(), pickle.size()); 1288 memcpy(dst, pickle.data(), pickle.size());
1274 1289
1275 allocator->MakeIterable(ref); 1290 allocator->MakeIterable(ref);
1276 field_trial->ref_ = ref; 1291 field_trial->ref_ = ref;
1277 } 1292 }
1278 1293
1279 // static 1294 // static
1280 void FieldTrialList::ActivateFieldTrialEntryWhileLocked( 1295 void FieldTrialList::ActivateFieldTrialEntryWhileLocked(
1281 FieldTrial* field_trial) { 1296 FieldTrial* field_trial) {
1282 FieldTrialAllocator* allocator = global_->field_trial_allocator_.get(); 1297 FieldTrialAllocator* allocator = global_->field_trial_allocator_.get();
1283 1298
1284 // Check if we're in the child process and return early if so. 1299 // Check if we're in the child process and return early if so.
1285 if (allocator && allocator->IsReadonly()) 1300 if (allocator && allocator->IsReadonly())
1286 return; 1301 return;
1287 1302
1288 FieldTrial::FieldTrialRef ref = field_trial->ref_; 1303 FieldTrial::FieldTrialRef ref = field_trial->ref_;
1289 if (ref == FieldTrialAllocator::kReferenceNull) { 1304 if (ref == FieldTrialAllocator::kReferenceNull) {
1290 // It's fine to do this even if the allocator hasn't been instantiated 1305 // It's fine to do this even if the allocator hasn't been instantiated
1291 // yet -- it'll just return early. 1306 // yet -- it'll just return early.
1292 AddToAllocatorWhileLocked(field_trial); 1307 AddToAllocatorWhileLocked(global_->field_trial_allocator_.get(),
1308 field_trial);
1293 } else { 1309 } else {
1294 // It's also okay to do this even though the callee doesn't have a lock -- 1310 // It's also okay to do this even though the callee doesn't have a lock --
1295 // the only thing that happens on a stale read here is a slight performance 1311 // the only thing that happens on a stale read here is a slight performance
1296 // hit from the child re-synchronizing activation state. 1312 // hit from the child re-synchronizing activation state.
1297 FieldTrialEntry* entry = 1313 FieldTrial::FieldTrialEntry* entry =
1298 allocator->GetAsObject<FieldTrialEntry>(ref, kFieldTrialType); 1314 allocator->GetAsObject<FieldTrial::FieldTrialEntry>(ref,
1315 kFieldTrialType);
1299 entry->activated = true; 1316 entry->activated = true;
1300 } 1317 }
1301 } 1318 }
1302 1319
1303 // static 1320 // static
1304 const FieldTrial::EntropyProvider* 1321 const FieldTrial::EntropyProvider*
1305 FieldTrialList::GetEntropyProviderForOneTimeRandomization() { 1322 FieldTrialList::GetEntropyProviderForOneTimeRandomization() {
1306 if (!global_) { 1323 if (!global_) {
1307 used_without_global_ = true; 1324 used_without_global_ = true;
1308 return NULL; 1325 return NULL;
(...skipping 16 matching lines...) Expand all
1325 return; 1342 return;
1326 } 1343 }
1327 AutoLock auto_lock(global_->lock_); 1344 AutoLock auto_lock(global_->lock_);
1328 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); 1345 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name();
1329 trial->AddRef(); 1346 trial->AddRef();
1330 trial->SetTrialRegistered(); 1347 trial->SetTrialRegistered();
1331 global_->registered_[trial->trial_name()] = trial; 1348 global_->registered_[trial->trial_name()] = trial;
1332 } 1349 }
1333 1350
1334 } // namespace base 1351 } // namespace base
OLDNEW
« no previous file with comments | « base/metrics/field_trial.h ('k') | base/metrics/field_trial_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698