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

Side by Side 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 unified diff | Download patch
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 PickleIterator FieldTrial::FieldTrialEntry::GetPickleIterator() const {
253 const char* src =
254 reinterpret_cast<const char*>(this) + sizeof(FieldTrialEntry);
255
256 Pickle pickle(src, pickle_size);
257 return PickleIterator(pickle);
258 }
259
260 bool FieldTrial::FieldTrialEntry::ReadStringPair(
261 PickleIterator* iter,
262 StringPiece* trial_name,
263 StringPiece* group_name) const {
264 if (!iter->ReadStringPiece(trial_name))
265 return false;
266 if (!iter->ReadStringPiece(group_name))
267 return false;
268 return true;
269 }
270
271 bool FieldTrial::FieldTrialEntry::GetTrialAndGroupName(
272 StringPiece* trial_name,
273 StringPiece* group_name) const {
274 PickleIterator iter = GetPickleIterator();
275 return ReadStringPair(&iter, trial_name, group_name);
276 }
277
278 bool FieldTrial::FieldTrialEntry::GetParams(
279 std::map<std::string, std::string>* params) const {
280 PickleIterator iter = GetPickleIterator();
281 StringPiece tmp;
282 if (!ReadStringPair(&iter, &tmp, &tmp))
283 return false;
284
285 while (true) {
286 StringPiece key;
287 StringPiece value;
288 if (!ReadStringPair(&iter, &key, &value))
289 return key.empty(); // Non-empty is bad: got one of a pair.
290 (*params)[key.as_string()] = value.as_string();
291 }
292 }
293
317 void FieldTrial::Disable() { 294 void FieldTrial::Disable() {
318 DCHECK(!group_reported_); 295 DCHECK(!group_reported_);
319 enable_field_trial_ = false; 296 enable_field_trial_ = false;
320 297
321 // In case we are disabled after initialization, we need to switch 298 // In case we are disabled after initialization, we need to switch
322 // the trial to the default group. 299 // the trial to the default group.
323 if (group_ != kNotFinalized) { 300 if (group_ != kNotFinalized) {
324 // Only reset when not already the default group, because in case we were 301 // 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 302 // forced to the default group, the group number may not be
326 // kDefaultGroupNumber, so we should keep it as is. 303 // 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), 712 command_line.GetSwitchValueASCII(switches::kForceFieldTrials),
736 active_groups); 713 active_groups);
737 return; 714 return;
738 } 715 }
739 716
740 FieldTrialAllocator* allocator = global_->field_trial_allocator_.get(); 717 FieldTrialAllocator* allocator = global_->field_trial_allocator_.get();
741 FieldTrialAllocator::Iterator mem_iter(allocator); 718 FieldTrialAllocator::Iterator mem_iter(allocator);
742 FieldTrial::FieldTrialRef ref; 719 FieldTrial::FieldTrialRef ref;
743 while ((ref = mem_iter.GetNextOfType(kFieldTrialType)) != 720 while ((ref = mem_iter.GetNextOfType(kFieldTrialType)) !=
744 SharedPersistentMemoryAllocator::kReferenceNull) { 721 SharedPersistentMemoryAllocator::kReferenceNull) {
745 const FieldTrialEntry* entry = 722 const FieldTrial::FieldTrialEntry* entry =
746 allocator->GetAsObject<const FieldTrialEntry>(ref, kFieldTrialType); 723 allocator->GetAsObject<const FieldTrial::FieldTrialEntry>(
724 ref, kFieldTrialType);
747 725
748 StringPiece trial_name; 726 StringPiece trial_name;
749 StringPiece group_name; 727 StringPiece group_name;
750 if (entry->activated && 728 if (entry->activated &&
751 entry->GetTrialAndGroupName(&trial_name, &group_name)) { 729 entry->GetTrialAndGroupName(&trial_name, &group_name)) {
752 FieldTrial::ActiveGroup group; 730 FieldTrial::ActiveGroup group;
753 group.trial_name = trial_name.as_string(); 731 group.trial_name = trial_name.as_string();
754 group.group_name = group_name.as_string(); 732 group.group_name = group_name.as_string();
755 active_groups->push_back(group); 733 active_groups->push_back(group);
756 } 734 }
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after
978 if (!global_) 956 if (!global_)
979 return; 957 return;
980 global_->observer_list_->RemoveObserver(observer); 958 global_->observer_list_->RemoveObserver(observer);
981 } 959 }
982 960
983 // static 961 // static
984 void FieldTrialList::OnGroupFinalized(bool is_locked, FieldTrial* field_trial) { 962 void FieldTrialList::OnGroupFinalized(bool is_locked, FieldTrial* field_trial) {
985 if (!global_) 963 if (!global_)
986 return; 964 return;
987 if (is_locked) { 965 if (is_locked) {
988 AddToAllocatorWhileLocked(field_trial); 966 AddToAllocatorWhileLocked(global_->field_trial_allocator_.get(),
967 field_trial);
989 } else { 968 } else {
990 AutoLock auto_lock(global_->lock_); 969 AutoLock auto_lock(global_->lock_);
991 AddToAllocatorWhileLocked(field_trial); 970 AddToAllocatorWhileLocked(global_->field_trial_allocator_.get(),
971 field_trial);
992 } 972 }
993 } 973 }
994 974
995 // static 975 // static
996 void FieldTrialList::NotifyFieldTrialGroupSelection(FieldTrial* field_trial) { 976 void FieldTrialList::NotifyFieldTrialGroupSelection(FieldTrial* field_trial) {
997 if (!global_) 977 if (!global_)
998 return; 978 return;
999 979
1000 { 980 {
1001 AutoLock auto_lock(global_->lock_); 981 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 1020 // 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. 1021 // you can call it after it's been set up.
1042 AutoLock auto_lock(global_->lock_); 1022 AutoLock auto_lock(global_->lock_);
1043 if (!global_->field_trial_allocator_) 1023 if (!global_->field_trial_allocator_)
1044 return false; 1024 return false;
1045 1025
1046 // If ref_ isn't set, then the field trial data can't be in shared memory. 1026 // If ref_ isn't set, then the field trial data can't be in shared memory.
1047 if (!field_trial->ref_) 1027 if (!field_trial->ref_)
1048 return false; 1028 return false;
1049 1029
1050 const FieldTrialEntry* entry = 1030 const FieldTrial::FieldTrialEntry* entry =
1051 global_->field_trial_allocator_->GetAsObject<const FieldTrialEntry>( 1031 global_->field_trial_allocator_
1052 field_trial->ref_, kFieldTrialType); 1032 ->GetAsObject<const FieldTrial::FieldTrialEntry>(field_trial->ref_,
1033 kFieldTrialType);
1053 1034
1054 size_t allocated_size = 1035 size_t allocated_size =
1055 global_->field_trial_allocator_->GetAllocSize(field_trial->ref_); 1036 global_->field_trial_allocator_->GetAllocSize(field_trial->ref_);
1056 size_t actual_size = sizeof(FieldTrialEntry) + entry->pickle_size; 1037 size_t actual_size = sizeof(FieldTrial::FieldTrialEntry) + entry->pickle_size;
1057 if (allocated_size < actual_size) 1038 if (allocated_size < actual_size)
1058 return false; 1039 return false;
1059 1040
1060 return entry->GetParams(params); 1041 return entry->GetParams(params);
1061 } 1042 }
1062 1043
1063 // static 1044 // static
1064 void FieldTrialList::ClearParamsFromSharedMemoryForTesting() { 1045 void FieldTrialList::ClearParamsFromSharedMemoryForTesting() {
1065 if (!global_) 1046 if (!global_)
1066 return; 1047 return;
1067 1048
1068 AutoLock auto_lock(global_->lock_); 1049 AutoLock auto_lock(global_->lock_);
1069 if (!global_->field_trial_allocator_) 1050 if (!global_->field_trial_allocator_)
1070 return; 1051 return;
1071 1052
1072 // To clear the params, we iterate through every item in the allocator, copy 1053 // 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 1054 // just the trial and group name into a newly-allocated segment and then clear
1074 // the existing item. 1055 // the existing item.
1075 FieldTrialAllocator* allocator = global_->field_trial_allocator_.get(); 1056 FieldTrialAllocator* allocator = global_->field_trial_allocator_.get();
1076 FieldTrialAllocator::Iterator mem_iter(allocator); 1057 FieldTrialAllocator::Iterator mem_iter(allocator);
1077 1058
1078 // List of refs to eventually be made iterable. We can't make it in the loop, 1059 // List of refs to eventually be made iterable. We can't make it in the loop,
1079 // since it would go on forever. 1060 // since it would go on forever.
1080 std::vector<FieldTrial::FieldTrialRef> new_refs; 1061 std::vector<FieldTrial::FieldTrialRef> new_refs;
1081 1062
1082 FieldTrial::FieldTrialRef prev_ref; 1063 FieldTrial::FieldTrialRef prev_ref;
1083 while ((prev_ref = mem_iter.GetNextOfType(kFieldTrialType)) != 1064 while ((prev_ref = mem_iter.GetNextOfType(kFieldTrialType)) !=
1084 FieldTrialAllocator::kReferenceNull) { 1065 FieldTrialAllocator::kReferenceNull) {
1085 // Get the existing field trial entry in shared memory. 1066 // Get the existing field trial entry in shared memory.
1086 const FieldTrialEntry* prev_entry = 1067 const FieldTrial::FieldTrialEntry* prev_entry =
1087 allocator->GetAsObject<const FieldTrialEntry>(prev_ref, 1068 allocator->GetAsObject<const FieldTrial::FieldTrialEntry>(
1088 kFieldTrialType); 1069 prev_ref, kFieldTrialType);
1089 StringPiece trial_name; 1070 StringPiece trial_name;
1090 StringPiece group_name; 1071 StringPiece group_name;
1091 if (!prev_entry->GetTrialAndGroupName(&trial_name, &group_name)) 1072 if (!prev_entry->GetTrialAndGroupName(&trial_name, &group_name))
1092 continue; 1073 continue;
1093 1074
1094 // Write a new entry, minus the params. 1075 // Write a new entry, minus the params.
1095 Pickle pickle; 1076 Pickle pickle;
1096 pickle.WriteString(trial_name); 1077 pickle.WriteString(trial_name);
1097 pickle.WriteString(group_name); 1078 pickle.WriteString(group_name);
1098 size_t total_size = sizeof(FieldTrialEntry) + pickle.size(); 1079 size_t total_size = sizeof(FieldTrial::FieldTrialEntry) + pickle.size();
1099 FieldTrial::FieldTrialRef new_ref = 1080 FieldTrial::FieldTrialRef new_ref =
1100 allocator->Allocate(total_size, kFieldTrialType); 1081 allocator->Allocate(total_size, kFieldTrialType);
1101 FieldTrialEntry* new_entry = 1082 FieldTrial::FieldTrialEntry* new_entry =
1102 allocator->GetAsObject<FieldTrialEntry>(new_ref, kFieldTrialType); 1083 allocator->GetAsObject<FieldTrial::FieldTrialEntry>(new_ref,
1084 kFieldTrialType);
1103 new_entry->activated = prev_entry->activated; 1085 new_entry->activated = prev_entry->activated;
1104 new_entry->pickle_size = pickle.size(); 1086 new_entry->pickle_size = pickle.size();
1105 1087
1106 // TODO(lawrencewu): Modify base::Pickle to be able to write over a section 1088 // TODO(lawrencewu): Modify base::Pickle to be able to write over a section
1107 // in memory, so we can avoid this memcpy. 1089 // in memory, so we can avoid this memcpy.
1108 char* dst = reinterpret_cast<char*>(new_entry) + sizeof(FieldTrialEntry); 1090 char* dst = reinterpret_cast<char*>(new_entry) +
1091 sizeof(FieldTrial::FieldTrialEntry);
1109 memcpy(dst, pickle.data(), pickle.size()); 1092 memcpy(dst, pickle.data(), pickle.size());
1110 1093
1111 // Update the ref on the field trial and add it to the list to be made 1094 // Update the ref on the field trial and add it to the list to be made
1112 // iterable. 1095 // iterable.
1113 FieldTrial* trial = global_->PreLockedFind(trial_name.as_string()); 1096 FieldTrial* trial = global_->PreLockedFind(trial_name.as_string());
1114 trial->ref_ = new_ref; 1097 trial->ref_ = new_ref;
1115 new_refs.push_back(new_ref); 1098 new_refs.push_back(new_ref);
1116 1099
1117 // Mark the existing entry as unused. 1100 // Mark the existing entry as unused.
1118 allocator->ChangeType(prev_ref, 0, kFieldTrialType); 1101 allocator->ChangeType(prev_ref, 0, kFieldTrialType);
1119 } 1102 }
1120 1103
1121 for (const auto& ref : new_refs) { 1104 for (const auto& ref : new_refs) {
1122 allocator->MakeIterable(ref); 1105 allocator->MakeIterable(ref);
1123 } 1106 }
1124 } 1107 }
1125 1108
1109 // static
1110 void FieldTrialList::DumpAllFieldTrialsToPersistentAllocator(
1111 PersistentMemoryAllocator* allocator) {
1112 if (!global_)
1113 return;
1114 AutoLock auto_lock(global_->lock_);
1115 for (const auto& registered : global_->registered_) {
1116 AddToAllocatorWhileLocked(allocator, registered.second);
1117 }
1118 }
1119
1120 // static
1121 std::vector<FieldTrial::FieldTrialEntry*>
1122 FieldTrialList::GetAllFieldTrialsFromPersistentAllocator(
1123 PersistentMemoryAllocator* allocator) {
1124 std::vector<FieldTrial::FieldTrialEntry*> field_trial_entries;
1125 FieldTrial::FieldTrialRef ref;
1126 FieldTrialAllocator::Iterator iter(allocator);
1127 while ((ref = iter.GetNextOfType(kFieldTrialType)) !=
1128 FieldTrialAllocator::kReferenceNull) {
1129 FieldTrial::FieldTrialEntry* entry =
bcwhite 2016/12/09 19:40:28 const
lawrencewu 2016/12/09 19:47:59 Done.
1130 allocator->GetAsObject<FieldTrial::FieldTrialEntry>(ref,
1131 kFieldTrialType);
1132 field_trial_entries.push_back(entry);
1133 }
1134 return field_trial_entries;
1135 }
1136
1126 #if defined(OS_WIN) 1137 #if defined(OS_WIN)
1127 // static 1138 // static
1128 bool FieldTrialList::CreateTrialsFromHandleSwitch( 1139 bool FieldTrialList::CreateTrialsFromHandleSwitch(
1129 const std::string& handle_switch) { 1140 const std::string& handle_switch) {
1130 int field_trial_handle = std::stoi(handle_switch); 1141 int field_trial_handle = std::stoi(handle_switch);
1131 HANDLE handle = reinterpret_cast<HANDLE>(field_trial_handle); 1142 HANDLE handle = reinterpret_cast<HANDLE>(field_trial_handle);
1132 SharedMemoryHandle shm_handle(handle, GetCurrentProcId()); 1143 SharedMemoryHandle shm_handle(handle, GetCurrentProcId());
1133 return FieldTrialList::CreateTrialsFromSharedMemoryHandle(shm_handle); 1144 return FieldTrialList::CreateTrialsFromSharedMemoryHandle(shm_handle);
1134 } 1145 }
1135 #endif 1146 #endif
(...skipping 16 matching lines...) Expand all
1152 bool FieldTrialList::CreateTrialsFromSharedMemory( 1163 bool FieldTrialList::CreateTrialsFromSharedMemory(
1153 std::unique_ptr<SharedMemory> shm) { 1164 std::unique_ptr<SharedMemory> shm) {
1154 global_->field_trial_allocator_.reset( 1165 global_->field_trial_allocator_.reset(
1155 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, true)); 1166 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, true));
1156 FieldTrialAllocator* shalloc = global_->field_trial_allocator_.get(); 1167 FieldTrialAllocator* shalloc = global_->field_trial_allocator_.get();
1157 FieldTrialAllocator::Iterator mem_iter(shalloc); 1168 FieldTrialAllocator::Iterator mem_iter(shalloc);
1158 1169
1159 FieldTrial::FieldTrialRef ref; 1170 FieldTrial::FieldTrialRef ref;
1160 while ((ref = mem_iter.GetNextOfType(kFieldTrialType)) != 1171 while ((ref = mem_iter.GetNextOfType(kFieldTrialType)) !=
1161 FieldTrialAllocator::kReferenceNull) { 1172 FieldTrialAllocator::kReferenceNull) {
1162 const FieldTrialEntry* entry = 1173 const FieldTrial::FieldTrialEntry* entry =
1163 shalloc->GetAsObject<const FieldTrialEntry>(ref, kFieldTrialType); 1174 shalloc->GetAsObject<const FieldTrial::FieldTrialEntry>(
1175 ref, kFieldTrialType);
1164 1176
1165 StringPiece trial_name; 1177 StringPiece trial_name;
1166 StringPiece group_name; 1178 StringPiece group_name;
1167 if (!entry->GetTrialAndGroupName(&trial_name, &group_name)) 1179 if (!entry->GetTrialAndGroupName(&trial_name, &group_name))
1168 return false; 1180 return false;
1169 1181
1170 // TODO(lawrencewu): Convert the API for CreateFieldTrial to take 1182 // TODO(lawrencewu): Convert the API for CreateFieldTrial to take
1171 // StringPieces. 1183 // StringPieces.
1172 FieldTrial* trial = 1184 FieldTrial* trial =
1173 CreateFieldTrial(trial_name.as_string(), group_name.as_string()); 1185 CreateFieldTrial(trial_name.as_string(), group_name.as_string());
(...skipping 29 matching lines...) Expand all
1203 1215
1204 if (!shm->Map(kFieldTrialAllocationSize)) 1216 if (!shm->Map(kFieldTrialAllocationSize))
1205 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); 1217 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize);
1206 1218
1207 global_->field_trial_allocator_.reset( 1219 global_->field_trial_allocator_.reset(
1208 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, false)); 1220 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, false));
1209 global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName); 1221 global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName);
1210 1222
1211 // Add all existing field trials. 1223 // Add all existing field trials.
1212 for (const auto& registered : global_->registered_) { 1224 for (const auto& registered : global_->registered_) {
1213 AddToAllocatorWhileLocked(registered.second); 1225 AddToAllocatorWhileLocked(global_->field_trial_allocator_.get(),
1226 registered.second);
1214 } 1227 }
1215 1228
1216 // Add all existing features. 1229 // Add all existing features.
1217 FeatureList::GetInstance()->AddFeaturesToAllocator( 1230 FeatureList::GetInstance()->AddFeaturesToAllocator(
1218 global_->field_trial_allocator_.get()); 1231 global_->field_trial_allocator_.get());
1219 1232
1220 #if defined(OS_WIN) || defined(POSIX_WITH_ZYGOTE) 1233 #if defined(OS_WIN) || defined(POSIX_WITH_ZYGOTE)
1221 // Set |readonly_allocator_handle_| so we can pass it to be inherited and 1234 // Set |readonly_allocator_handle_| so we can pass it to be inherited and
1222 // via the command line. 1235 // via the command line.
1223 global_->readonly_allocator_handle_ = 1236 global_->readonly_allocator_handle_ =
1224 CreateReadOnlyHandle(global_->field_trial_allocator_.get()); 1237 CreateReadOnlyHandle(global_->field_trial_allocator_.get());
1225 #endif 1238 #endif
1226 } 1239 }
1227 #endif 1240 #endif
1228 1241
1229 // static 1242 // static
1230 void FieldTrialList::AddToAllocatorWhileLocked(FieldTrial* field_trial) { 1243 void FieldTrialList::AddToAllocatorWhileLocked(
1231 FieldTrialAllocator* allocator = global_->field_trial_allocator_.get(); 1244 PersistentMemoryAllocator* allocator,
1232 1245 FieldTrial* field_trial) {
1233 // Don't do anything if the allocator hasn't been instantiated yet. 1246 // Don't do anything if the allocator hasn't been instantiated yet.
1234 if (allocator == nullptr) 1247 if (allocator == nullptr)
1235 return; 1248 return;
1236 1249
1237 // Or if the allocator is read only, which means we are in a child process and 1250 // Or if the allocator is read only, which means we are in a child process and
1238 // shouldn't be writing to it. 1251 // shouldn't be writing to it.
1239 if (allocator->IsReadonly()) 1252 if (allocator->IsReadonly())
1240 return; 1253 return;
1241 1254
1242 FieldTrial::State trial_state; 1255 FieldTrial::State trial_state;
1243 if (!field_trial->GetStateWhileLocked(&trial_state)) 1256 if (!field_trial->GetStateWhileLocked(&trial_state))
1244 return; 1257 return;
1245 1258
1246 // Or if we've already added it. We must check after GetState since it can 1259 // Or if we've already added it. We must check after GetState since it can
1247 // also add to the allocator. 1260 // also add to the allocator.
1248 if (field_trial->ref_) 1261 if (field_trial->ref_)
1249 return; 1262 return;
1250 1263
1251 Pickle pickle; 1264 Pickle pickle;
1252 if (!PickleFieldTrial(trial_state, &pickle)) { 1265 if (!PickleFieldTrial(trial_state, &pickle)) {
1253 NOTREACHED(); 1266 NOTREACHED();
1254 return; 1267 return;
1255 } 1268 }
1256 1269
1257 size_t total_size = sizeof(FieldTrialEntry) + pickle.size(); 1270 size_t total_size = sizeof(FieldTrial::FieldTrialEntry) + pickle.size();
1258 FieldTrial::FieldTrialRef ref = 1271 FieldTrial::FieldTrialRef ref =
1259 allocator->Allocate(total_size, kFieldTrialType); 1272 allocator->Allocate(total_size, kFieldTrialType);
1260 if (ref == FieldTrialAllocator::kReferenceNull) { 1273 if (ref == FieldTrialAllocator::kReferenceNull) {
1261 NOTREACHED(); 1274 NOTREACHED();
1262 return; 1275 return;
1263 } 1276 }
1264 1277
1265 FieldTrialEntry* entry = 1278 FieldTrial::FieldTrialEntry* entry =
1266 allocator->GetAsObject<FieldTrialEntry>(ref, kFieldTrialType); 1279 allocator->GetAsObject<FieldTrial::FieldTrialEntry>(ref, kFieldTrialType);
1267 entry->activated = trial_state.activated; 1280 entry->activated = trial_state.activated;
1268 entry->pickle_size = pickle.size(); 1281 entry->pickle_size = pickle.size();
1269 1282
1270 // TODO(lawrencewu): Modify base::Pickle to be able to write over a section in 1283 // TODO(lawrencewu): Modify base::Pickle to be able to write over a section in
1271 // memory, so we can avoid this memcpy. 1284 // memory, so we can avoid this memcpy.
1272 char* dst = reinterpret_cast<char*>(entry) + sizeof(FieldTrialEntry); 1285 char* dst =
1286 reinterpret_cast<char*>(entry) + sizeof(FieldTrial::FieldTrialEntry);
1273 memcpy(dst, pickle.data(), pickle.size()); 1287 memcpy(dst, pickle.data(), pickle.size());
1274 1288
1275 allocator->MakeIterable(ref); 1289 allocator->MakeIterable(ref);
1276 field_trial->ref_ = ref; 1290 field_trial->ref_ = ref;
1277 } 1291 }
1278 1292
1279 // static 1293 // static
1280 void FieldTrialList::ActivateFieldTrialEntryWhileLocked( 1294 void FieldTrialList::ActivateFieldTrialEntryWhileLocked(
1281 FieldTrial* field_trial) { 1295 FieldTrial* field_trial) {
1282 FieldTrialAllocator* allocator = global_->field_trial_allocator_.get(); 1296 FieldTrialAllocator* allocator = global_->field_trial_allocator_.get();
1283 1297
1284 // Check if we're in the child process and return early if so. 1298 // Check if we're in the child process and return early if so.
1285 if (allocator && allocator->IsReadonly()) 1299 if (allocator && allocator->IsReadonly())
1286 return; 1300 return;
1287 1301
1288 FieldTrial::FieldTrialRef ref = field_trial->ref_; 1302 FieldTrial::FieldTrialRef ref = field_trial->ref_;
1289 if (ref == FieldTrialAllocator::kReferenceNull) { 1303 if (ref == FieldTrialAllocator::kReferenceNull) {
1290 // It's fine to do this even if the allocator hasn't been instantiated 1304 // It's fine to do this even if the allocator hasn't been instantiated
1291 // yet -- it'll just return early. 1305 // yet -- it'll just return early.
1292 AddToAllocatorWhileLocked(field_trial); 1306 AddToAllocatorWhileLocked(global_->field_trial_allocator_.get(),
1307 field_trial);
1293 } else { 1308 } else {
1294 // It's also okay to do this even though the callee doesn't have a lock -- 1309 // 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 1310 // the only thing that happens on a stale read here is a slight performance
1296 // hit from the child re-synchronizing activation state. 1311 // hit from the child re-synchronizing activation state.
1297 FieldTrialEntry* entry = 1312 FieldTrial::FieldTrialEntry* entry =
1298 allocator->GetAsObject<FieldTrialEntry>(ref, kFieldTrialType); 1313 allocator->GetAsObject<FieldTrial::FieldTrialEntry>(ref,
1314 kFieldTrialType);
1299 entry->activated = true; 1315 entry->activated = true;
1300 } 1316 }
1301 } 1317 }
1302 1318
1303 // static 1319 // static
1304 const FieldTrial::EntropyProvider* 1320 const FieldTrial::EntropyProvider*
1305 FieldTrialList::GetEntropyProviderForOneTimeRandomization() { 1321 FieldTrialList::GetEntropyProviderForOneTimeRandomization() {
1306 if (!global_) { 1322 if (!global_) {
1307 used_without_global_ = true; 1323 used_without_global_ = true;
1308 return NULL; 1324 return NULL;
(...skipping 16 matching lines...) Expand all
1325 return; 1341 return;
1326 } 1342 }
1327 AutoLock auto_lock(global_->lock_); 1343 AutoLock auto_lock(global_->lock_);
1328 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); 1344 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name();
1329 trial->AddRef(); 1345 trial->AddRef();
1330 trial->SetTrialRegistered(); 1346 trial->SetTrialRegistered();
1331 global_->registered_[trial->trial_name()] = trial; 1347 global_->registered_[trial->trial_name()] = trial;
1332 } 1348 }
1333 1349
1334 } // namespace base 1350 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698