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

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

Issue 2463223002: Store field trial parameters in shared memory (Closed)
Patch Set: address comments Created 4 years, 1 month 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"
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
44 const char kAllocatorName[] = "FieldTrialAllocator"; 44 const char kAllocatorName[] = "FieldTrialAllocator";
45 const uint32_t kFieldTrialType = 0xABA17E13 + 1; // SHA1(FieldTrialEntry) v1 45 const uint32_t kFieldTrialType = 0xABA17E13 + 1; // SHA1(FieldTrialEntry) v1
46 #if !defined(OS_NACL) 46 #if !defined(OS_NACL)
47 const size_t kFieldTrialAllocationSize = 4 << 10; // 4 KiB = one page 47 const size_t kFieldTrialAllocationSize = 4 << 10; // 4 KiB = one page
48 #endif 48 #endif
49 49
50 // We create one FieldTrialEntry per field trial in shared memory, via 50 // We create one FieldTrialEntry per field trial in shared memory, via
51 // AddToAllocatorWhileLocked. The FieldTrialEntry is followed by a base::Pickle 51 // AddToAllocatorWhileLocked. The FieldTrialEntry is followed by a base::Pickle
52 // object that we unpickle and read from. 52 // object that we unpickle and read from.
53 struct FieldTrialEntry { 53 struct FieldTrialEntry {
54 // Whether or not this field trial is activated.
54 bool activated; 55 bool activated;
55 56
56 // Size of the pickled structure, NOT the total size of this entry. 57 // Size of the pickled structure, NOT the total size of this entry.
57 uint32_t size; 58 uint32_t size;
58 59
60 // Returns an iterator over the data used for getting names and params.
61 PickleIterator GetPickleIterator() const {
62 char* src = reinterpret_cast<char*>(const_cast<FieldTrialEntry*>(this)) +
63 sizeof(FieldTrialEntry);
64
65 Pickle pickle(src, size);
66 return PickleIterator(pickle);
67 }
68
69 // Takes the iterator and writes out the first two items into |trial_name| and
70 // |group_name|.
71 bool ReadStringPair(PickleIterator iter,
72 StringPiece* trial_name,
73 StringPiece* group_name) const {
74 if (!iter.ReadStringPiece(trial_name))
75 return false;
76 if (!iter.ReadStringPiece(group_name))
77 return false;
78 return true;
79 }
80
59 // Calling this is only valid when the entry is initialized. That is, it 81 // Calling this is only valid when the entry is initialized. That is, it
60 // resides in shared memory and has a pickle containing the trial name and 82 // resides in shared memory and has a pickle containing the trial name and
61 // group name following it. 83 // group name following it.
62 bool GetTrialAndGroupName(StringPiece* trial_name, 84 bool GetTrialAndGroupName(StringPiece* trial_name,
63 StringPiece* group_name) const { 85 StringPiece* group_name) const {
64 char* src = reinterpret_cast<char*>(const_cast<FieldTrialEntry*>(this)) + 86 PickleIterator iter = GetPickleIterator();
65 sizeof(FieldTrialEntry); 87 return ReadStringPair(iter, trial_name, group_name);
88 }
66 89
67 Pickle pickle(src, size); 90 bool GetParams(FieldTrialParamAssociator::FieldTrialParams* params) const {
68 PickleIterator pickle_iter(pickle); 91 PickleIterator iter = GetPickleIterator();
92 StringPiece tmp;
93 if (!ReadStringPair(iter, &tmp, &tmp))
94 return false;
69 95
70 if (!pickle_iter.ReadStringPiece(trial_name)) 96 while (true) {
71 return false; 97 StringPiece key;
72 if (!pickle_iter.ReadStringPiece(group_name)) 98 StringPiece value;
73 return false; 99 if (!iter.ReadStringPiece(&key))
74 return true; 100 return true; // No more params to read.
101 if (!iter.ReadStringPiece(&value))
102 return false;
103 (*params)[key.as_string()] = value.as_string();
104 }
105
106 NOTREACHED() << "Hit field trial param limit";
107 return false;
75 } 108 }
76 }; 109 };
77 110
78 // Created a time value based on |year|, |month| and |day_of_month| parameters. 111 // Created a time value based on |year|, |month| and |day_of_month| parameters.
79 Time CreateTimeFromParams(int year, int month, int day_of_month) { 112 Time CreateTimeFromParams(int year, int month, int day_of_month) {
80 DCHECK_GT(year, 1970); 113 DCHECK_GT(year, 1970);
81 DCHECK_GT(month, 0); 114 DCHECK_GT(month, 0);
82 DCHECK_LT(month, 13); 115 DCHECK_LT(month, 13);
83 DCHECK_GT(day_of_month, 0); 116 DCHECK_GT(day_of_month, 0);
84 DCHECK_LT(day_of_month, 32); 117 DCHECK_LT(day_of_month, 32);
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
174 HANDLE src = allocator->shared_memory()->handle().GetHandle(); 207 HANDLE src = allocator->shared_memory()->handle().GetHandle();
175 ProcessHandle process = GetCurrentProcess(); 208 ProcessHandle process = GetCurrentProcess();
176 DWORD access = SECTION_MAP_READ | SECTION_QUERY; 209 DWORD access = SECTION_MAP_READ | SECTION_QUERY;
177 HANDLE dst; 210 HANDLE dst;
178 if (!::DuplicateHandle(process, src, process, &dst, access, true, 0)) 211 if (!::DuplicateHandle(process, src, process, &dst, access, true, 0))
179 return nullptr; 212 return nullptr;
180 return dst; 213 return dst;
181 } 214 }
182 #endif 215 #endif
183 216
217 bool PickleFieldTrialState(const FieldTrial::State& trial_state,
218 Pickle* pickle) {
219 pickle->WriteString(trial_state.trial_name);
220 pickle->WriteString(trial_state.group_name);
221
222 std::map<std::string, std::string> params;
223 if (!FieldTrialParamAssociator::GetInstance()
224 ->GetFieldTrialParamsWithGroupName(
225 trial_state.trial_name.as_string(),
226 trial_state.group_name.as_string(), &params)) {
227 return false;
228 }
229
230 for (const auto& param : params) {
231 pickle->WriteString(StringPiece(param.first));
232 pickle->WriteString(StringPiece(param.second));
233 }
234 return true;
235 }
236
184 } // namespace 237 } // namespace
185 238
186 // statics 239 // statics
187 const int FieldTrial::kNotFinalized = -1; 240 const int FieldTrial::kNotFinalized = -1;
188 const int FieldTrial::kDefaultGroupNumber = 0; 241 const int FieldTrial::kDefaultGroupNumber = 0;
189 bool FieldTrial::enable_benchmarking_ = false; 242 bool FieldTrial::enable_benchmarking_ = false;
190 243
191 int FieldTrialList::kNoExpirationYear = 0; 244 int FieldTrialList::kNoExpirationYear = 0;
192 245
193 //------------------------------------------------------------------------------ 246 //------------------------------------------------------------------------------
(...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after
520 573
521 // static 574 // static
522 std::string FieldTrialList::FindFullName(const std::string& trial_name) { 575 std::string FieldTrialList::FindFullName(const std::string& trial_name) {
523 FieldTrial* field_trial = Find(trial_name); 576 FieldTrial* field_trial = Find(trial_name);
524 if (field_trial) 577 if (field_trial)
525 return field_trial->group_name(); 578 return field_trial->group_name();
526 return std::string(); 579 return std::string();
527 } 580 }
528 581
529 // static 582 // static
583 bool FieldTrialList::FindParams(
584 const std::string& trial_name,
585 FieldTrialParamAssociator::FieldTrialParams* params) {
586 // Check that the allocator exists (it may not exist on Linux or macOS). This
587 // shouldn't ever happen on Windows, as child processes should get an
588 // allocator during initialization, and browser processes won't hit this
589 // function since it has the mapping in FieldTrialParamAssociator.
590 SharedPersistentMemoryAllocator* allocator =
591 global_->field_trial_allocator_.get();
592 if (allocator == nullptr)
593 return false;
594
595 // Get the field trial's corresponding reference in shared memory. This
596 // shouldn't happen for on Windows the same reasons above.
597 FieldTrial* field_trial = Find(trial_name);
598 if (field_trial->ref_ == SharedPersistentMemoryAllocator::kReferenceNull)
599 return false;
600
601 FieldTrialEntry* entry = allocator->GetAsObject<FieldTrialEntry>(
602 field_trial->ref_, kFieldTrialType);
603 return entry->GetParams(params);
604 }
605
606 // static
530 bool FieldTrialList::TrialExists(const std::string& trial_name) { 607 bool FieldTrialList::TrialExists(const std::string& trial_name) {
531 return Find(trial_name) != NULL; 608 return Find(trial_name) != NULL;
532 } 609 }
533 610
534 // static 611 // static
535 bool FieldTrialList::IsTrialActive(const std::string& trial_name) { 612 bool FieldTrialList::IsTrialActive(const std::string& trial_name) {
536 FieldTrial* field_trial = Find(trial_name); 613 FieldTrial* field_trial = Find(trial_name);
537 FieldTrial::ActiveGroup active_group; 614 FieldTrial::ActiveGroup active_group;
538 return field_trial && field_trial->GetActiveGroup(&active_group); 615 return field_trial && field_trial->GetActiveGroup(&active_group);
539 } 616 }
(...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after
816 size_t FieldTrialList::GetFieldTrialCount() { 893 size_t FieldTrialList::GetFieldTrialCount() {
817 if (!global_) 894 if (!global_)
818 return 0; 895 return 0;
819 AutoLock auto_lock(global_->lock_); 896 AutoLock auto_lock(global_->lock_);
820 return global_->registered_.size(); 897 return global_->registered_.size();
821 } 898 }
822 899
823 // static 900 // static
824 void FieldTrialList::CreateTrialsFromSharedMemory( 901 void FieldTrialList::CreateTrialsFromSharedMemory(
825 std::unique_ptr<SharedMemory> shm) { 902 std::unique_ptr<SharedMemory> shm) {
826 const SharedPersistentMemoryAllocator shalloc(std::move(shm), 0, 903 global_->field_trial_allocator_.reset(new SharedPersistentMemoryAllocator(
827 kAllocatorName, true); 904 std::move(shm), 0, kAllocatorName, true));
828 PersistentMemoryAllocator::Iterator mem_iter(&shalloc); 905 SharedPersistentMemoryAllocator* shalloc =
906 global_->field_trial_allocator_.get();
907 PersistentMemoryAllocator::Iterator mem_iter(shalloc);
829 908
830 SharedPersistentMemoryAllocator::Reference ref; 909 SharedPersistentMemoryAllocator::Reference ref;
831 while ((ref = mem_iter.GetNextOfType(kFieldTrialType)) != 910 while ((ref = mem_iter.GetNextOfType(kFieldTrialType)) !=
832 SharedPersistentMemoryAllocator::kReferenceNull) { 911 SharedPersistentMemoryAllocator::kReferenceNull) {
833 const FieldTrialEntry* entry = 912 const FieldTrialEntry* entry =
834 shalloc.GetAsObject<const FieldTrialEntry>(ref, kFieldTrialType); 913 shalloc->GetAsObject<const FieldTrialEntry>(ref, kFieldTrialType);
835 914
836 StringPiece trial_name; 915 StringPiece trial_name;
837 StringPiece group_name; 916 StringPiece group_name;
838 if (!entry->GetTrialAndGroupName(&trial_name, &group_name)) { 917 if (!entry->GetTrialAndGroupName(&trial_name, &group_name)) {
839 NOTREACHED(); 918 NOTREACHED();
840 continue; 919 continue;
841 } 920 }
842 921
843 // TODO(lawrencewu): Convert the API for CreateFieldTrial to take 922 // TODO(lawrencewu): Convert the API for CreateFieldTrial to take
844 // StringPieces. 923 // StringPieces.
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
897 976
898 // Or if we've already added it. 977 // Or if we've already added it.
899 if (field_trial->ref_ != SharedPersistentMemoryAllocator::kReferenceNull) 978 if (field_trial->ref_ != SharedPersistentMemoryAllocator::kReferenceNull)
900 return; 979 return;
901 980
902 FieldTrial::State trial_state; 981 FieldTrial::State trial_state;
903 if (!field_trial->GetState(&trial_state)) 982 if (!field_trial->GetState(&trial_state))
904 return; 983 return;
905 984
906 Pickle pickle; 985 Pickle pickle;
907 pickle.WriteString(trial_state.trial_name); 986 if (!PickleFieldTrialState(trial_state, &pickle))
908 pickle.WriteString(trial_state.group_name); 987 return;
909 988
910 size_t total_size = sizeof(FieldTrialEntry) + pickle.size(); 989 size_t total_size = sizeof(FieldTrialEntry) + pickle.size();
911 SharedPersistentMemoryAllocator::Reference ref = 990 SharedPersistentMemoryAllocator::Reference ref =
912 allocator->Allocate(total_size, kFieldTrialType); 991 allocator->Allocate(total_size, kFieldTrialType);
913 if (ref == SharedPersistentMemoryAllocator::kReferenceNull) 992 if (ref == SharedPersistentMemoryAllocator::kReferenceNull)
914 return; 993 return;
915 994
916 FieldTrialEntry* entry = 995 FieldTrialEntry* entry =
917 allocator->GetAsObject<FieldTrialEntry>(ref, kFieldTrialType); 996 allocator->GetAsObject<FieldTrialEntry>(ref, kFieldTrialType);
918 entry->activated = trial_state.activated; 997 entry->activated = trial_state.activated;
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
972 return; 1051 return;
973 } 1052 }
974 AutoLock auto_lock(global_->lock_); 1053 AutoLock auto_lock(global_->lock_);
975 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); 1054 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name();
976 trial->AddRef(); 1055 trial->AddRef();
977 trial->SetTrialRegistered(); 1056 trial->SetTrialRegistered();
978 global_->registered_[trial->trial_name()] = trial; 1057 global_->registered_[trial->trial_name()] = trial;
979 } 1058 }
980 1059
981 } // namespace base 1060 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698