Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 28 matching lines...) Expand all Loading... | |
| 39 // shared memory segment). See https://codereview.chromium.org/2365273004/ and | 39 // shared memory segment). See https://codereview.chromium.org/2365273004/ and |
| 40 // crbug.com/653874 | 40 // crbug.com/653874 |
| 41 const bool kUseSharedMemoryForFieldTrials = false; | 41 const bool kUseSharedMemoryForFieldTrials = false; |
| 42 | 42 |
| 43 // Constants for the field trial allocator. | 43 // Constants for the field trial allocator. |
| 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 const int kFieldTrialParamLimit = 1000; | |
| 49 | 50 |
| 50 // We create one FieldTrialEntry per field trial in shared memory, via | 51 // We create one FieldTrialEntry per field trial in shared memory, via |
| 51 // AddToAllocatorWhileLocked. The FieldTrialEntry is followed by a base::Pickle | 52 // AddToAllocatorWhileLocked. The FieldTrialEntry is followed by a base::Pickle |
| 52 // object that we unpickle and read from. | 53 // object that we unpickle and read from. |
| 53 struct FieldTrialEntry { | 54 struct FieldTrialEntry { |
| 55 // Whether or not this field trial is activated. | |
| 54 bool activated; | 56 bool activated; |
| 55 | 57 |
| 56 // Size of the pickled structure, NOT the total size of this entry. | 58 // Size of the pickled structure, NOT the total size of this entry. |
| 57 uint32_t size; | 59 uint32_t size; |
| 58 | 60 |
| 61 // Returns an iterator over the data used for getting names and params. | |
| 62 PickleIterator GetPickleIterator() const { | |
| 63 char* src = reinterpret_cast<char*>(const_cast<FieldTrialEntry*>(this)) + | |
| 64 sizeof(FieldTrialEntry); | |
| 65 | |
| 66 Pickle pickle(src, size); | |
| 67 return PickleIterator(pickle); | |
| 68 } | |
| 69 | |
| 59 // Calling this is only valid when the entry is initialized. That is, it | 70 // 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 | 71 // resides in shared memory and has a pickle containing the trial name and |
| 61 // group name following it. | 72 // group name following it. |
| 62 bool GetTrialAndGroupName(StringPiece* trial_name, | 73 bool GetTrialAndGroupName(StringPiece* trial_name, |
| 63 StringPiece* group_name) const { | 74 StringPiece* group_name) const { |
| 64 char* src = reinterpret_cast<char*>(const_cast<FieldTrialEntry*>(this)) + | 75 PickleIterator iter = GetPickleIterator(); |
| 65 sizeof(FieldTrialEntry); | 76 if (!iter.ReadStringPiece(trial_name)) |
| 66 | |
| 67 Pickle pickle(src, size); | |
| 68 PickleIterator pickle_iter(pickle); | |
| 69 | |
| 70 if (!pickle_iter.ReadStringPiece(trial_name)) | |
| 71 return false; | 77 return false; |
| 72 if (!pickle_iter.ReadStringPiece(group_name)) | 78 if (!iter.ReadStringPiece(group_name)) |
| 73 return false; | 79 return false; |
| 74 return true; | 80 return true; |
| 75 } | 81 } |
| 82 | |
| 83 bool GetParams(FieldTrialParamAssociator::FieldTrialParams* params) const { | |
| 84 PickleIterator iter = GetPickleIterator(); | |
| 85 StringPiece tmp; | |
| 86 if (!iter.ReadStringPiece(&tmp)) | |
| 87 return false; | |
| 88 if (!iter.ReadStringPiece(&tmp)) | |
| 89 return false; | |
|
Alexei Svitkine (slow)
2016/11/01 19:13:27
Can you refactor the code to re-use the GetTrialAn
lawrencewu
2016/11/01 19:59:58
Done.
| |
| 90 | |
| 91 for (int i = 0; i < kFieldTrialParamLimit; ++i) { | |
|
Alexei Svitkine (slow)
2016/11/01 19:13:27
Instead of having an arbitrary limit, I suggest ju
lawrencewu
2016/11/01 19:59:58
Done.
| |
| 92 StringPiece key; | |
| 93 StringPiece value; | |
| 94 if (!iter.ReadStringPiece(&key)) | |
| 95 return true; // No more params to read. | |
| 96 if (!iter.ReadStringPiece(&value)) | |
| 97 return false; | |
| 98 (*params)[key.as_string()] = value.as_string(); | |
| 99 } | |
| 100 | |
| 101 NOTREACHED() << "Hit field trial param limit"; | |
| 102 return false; | |
| 103 } | |
| 76 }; | 104 }; |
| 77 | 105 |
| 78 // Created a time value based on |year|, |month| and |day_of_month| parameters. | 106 // Created a time value based on |year|, |month| and |day_of_month| parameters. |
| 79 Time CreateTimeFromParams(int year, int month, int day_of_month) { | 107 Time CreateTimeFromParams(int year, int month, int day_of_month) { |
| 80 DCHECK_GT(year, 1970); | 108 DCHECK_GT(year, 1970); |
| 81 DCHECK_GT(month, 0); | 109 DCHECK_GT(month, 0); |
| 82 DCHECK_LT(month, 13); | 110 DCHECK_LT(month, 13); |
| 83 DCHECK_GT(day_of_month, 0); | 111 DCHECK_GT(day_of_month, 0); |
| 84 DCHECK_LT(day_of_month, 32); | 112 DCHECK_LT(day_of_month, 32); |
| 85 | 113 |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 174 HANDLE src = allocator->shared_memory()->handle().GetHandle(); | 202 HANDLE src = allocator->shared_memory()->handle().GetHandle(); |
| 175 ProcessHandle process = GetCurrentProcess(); | 203 ProcessHandle process = GetCurrentProcess(); |
| 176 DWORD access = SECTION_MAP_READ | SECTION_QUERY; | 204 DWORD access = SECTION_MAP_READ | SECTION_QUERY; |
| 177 HANDLE dst; | 205 HANDLE dst; |
| 178 if (!::DuplicateHandle(process, src, process, &dst, access, true, 0)) | 206 if (!::DuplicateHandle(process, src, process, &dst, access, true, 0)) |
| 179 return nullptr; | 207 return nullptr; |
| 180 return dst; | 208 return dst; |
| 181 } | 209 } |
| 182 #endif | 210 #endif |
| 183 | 211 |
| 212 bool PickleFieldTrialState(const FieldTrial::State& trial_state, | |
| 213 Pickle* pickle) { | |
| 214 pickle->WriteString(trial_state.trial_name); | |
| 215 pickle->WriteString(trial_state.group_name); | |
| 216 | |
| 217 std::map<std::string, std::string> params; | |
| 218 if (!FieldTrialParamAssociator::GetInstance()->GetFieldTrialParams( | |
| 219 trial_state.trial_name.as_string(), | |
| 220 trial_state.group_name.as_string(), ¶ms)) { | |
| 221 return false; | |
| 222 } | |
| 223 | |
| 224 for (const auto& param : params) { | |
| 225 pickle->WriteString(StringPiece(param.first)); | |
| 226 pickle->WriteString(StringPiece(param.second)); | |
| 227 } | |
| 228 return true; | |
| 229 } | |
| 230 | |
| 184 } // namespace | 231 } // namespace |
| 185 | 232 |
| 186 // statics | 233 // statics |
| 187 const int FieldTrial::kNotFinalized = -1; | 234 const int FieldTrial::kNotFinalized = -1; |
| 188 const int FieldTrial::kDefaultGroupNumber = 0; | 235 const int FieldTrial::kDefaultGroupNumber = 0; |
| 189 bool FieldTrial::enable_benchmarking_ = false; | 236 bool FieldTrial::enable_benchmarking_ = false; |
| 190 | 237 |
| 191 int FieldTrialList::kNoExpirationYear = 0; | 238 int FieldTrialList::kNoExpirationYear = 0; |
| 192 | 239 |
| 193 //------------------------------------------------------------------------------ | 240 //------------------------------------------------------------------------------ |
| (...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 520 | 567 |
| 521 // static | 568 // static |
| 522 std::string FieldTrialList::FindFullName(const std::string& trial_name) { | 569 std::string FieldTrialList::FindFullName(const std::string& trial_name) { |
| 523 FieldTrial* field_trial = Find(trial_name); | 570 FieldTrial* field_trial = Find(trial_name); |
| 524 if (field_trial) | 571 if (field_trial) |
| 525 return field_trial->group_name(); | 572 return field_trial->group_name(); |
| 526 return std::string(); | 573 return std::string(); |
| 527 } | 574 } |
| 528 | 575 |
| 529 // static | 576 // static |
| 577 bool FieldTrialList::FindParams( | |
| 578 const std::string& trial_name, | |
| 579 FieldTrialParamAssociator::FieldTrialParams* params) { | |
| 580 SharedPersistentMemoryAllocator* allocator = | |
| 581 global_->field_trial_allocator_.get(); | |
| 582 if (allocator == nullptr) | |
| 583 return false; | |
| 584 | |
| 585 FieldTrial* field_trial = Find(trial_name); | |
| 586 if (field_trial->ref_ == SharedPersistentMemoryAllocator::kReferenceNull) | |
|
Alexei Svitkine (slow)
2016/11/01 19:13:27
Please add comments above the early returns that e
lawrencewu
2016/11/01 19:59:58
Done.
| |
| 587 return false; | |
| 588 | |
| 589 FieldTrialEntry* entry = allocator->GetAsObject<FieldTrialEntry>( | |
| 590 field_trial->ref_, kFieldTrialType); | |
| 591 return entry->GetParams(params); | |
| 592 } | |
| 593 | |
| 594 // static | |
| 530 bool FieldTrialList::TrialExists(const std::string& trial_name) { | 595 bool FieldTrialList::TrialExists(const std::string& trial_name) { |
| 531 return Find(trial_name) != NULL; | 596 return Find(trial_name) != NULL; |
| 532 } | 597 } |
| 533 | 598 |
| 534 // static | 599 // static |
| 535 bool FieldTrialList::IsTrialActive(const std::string& trial_name) { | 600 bool FieldTrialList::IsTrialActive(const std::string& trial_name) { |
| 536 FieldTrial* field_trial = Find(trial_name); | 601 FieldTrial* field_trial = Find(trial_name); |
| 537 FieldTrial::ActiveGroup active_group; | 602 FieldTrial::ActiveGroup active_group; |
| 538 return field_trial && field_trial->GetActiveGroup(&active_group); | 603 return field_trial && field_trial->GetActiveGroup(&active_group); |
| 539 } | 604 } |
| (...skipping 357 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 897 | 962 |
| 898 // Or if we've already added it. | 963 // Or if we've already added it. |
| 899 if (field_trial->ref_ != SharedPersistentMemoryAllocator::kReferenceNull) | 964 if (field_trial->ref_ != SharedPersistentMemoryAllocator::kReferenceNull) |
| 900 return; | 965 return; |
| 901 | 966 |
| 902 FieldTrial::State trial_state; | 967 FieldTrial::State trial_state; |
| 903 if (!field_trial->GetState(&trial_state)) | 968 if (!field_trial->GetState(&trial_state)) |
| 904 return; | 969 return; |
| 905 | 970 |
| 906 Pickle pickle; | 971 Pickle pickle; |
| 907 pickle.WriteString(trial_state.trial_name); | 972 if (!PickleFieldTrialState(trial_state, &pickle)) |
| 908 pickle.WriteString(trial_state.group_name); | 973 return; |
| 909 | 974 |
| 910 size_t total_size = sizeof(FieldTrialEntry) + pickle.size(); | 975 size_t total_size = sizeof(FieldTrialEntry) + pickle.size(); |
| 911 SharedPersistentMemoryAllocator::Reference ref = | 976 SharedPersistentMemoryAllocator::Reference ref = |
| 912 allocator->Allocate(total_size, kFieldTrialType); | 977 allocator->Allocate(total_size, kFieldTrialType); |
| 913 if (ref == SharedPersistentMemoryAllocator::kReferenceNull) | 978 if (ref == SharedPersistentMemoryAllocator::kReferenceNull) |
| 914 return; | 979 return; |
| 915 | 980 |
| 916 FieldTrialEntry* entry = | 981 FieldTrialEntry* entry = |
| 917 allocator->GetAsObject<FieldTrialEntry>(ref, kFieldTrialType); | 982 allocator->GetAsObject<FieldTrialEntry>(ref, kFieldTrialType); |
| 918 entry->activated = trial_state.activated; | 983 entry->activated = trial_state.activated; |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 972 return; | 1037 return; |
| 973 } | 1038 } |
| 974 AutoLock auto_lock(global_->lock_); | 1039 AutoLock auto_lock(global_->lock_); |
| 975 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); | 1040 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); |
| 976 trial->AddRef(); | 1041 trial->AddRef(); |
| 977 trial->SetTrialRegistered(); | 1042 trial->SetTrialRegistered(); |
| 978 global_->registered_[trial->trial_name()] = trial; | 1043 global_->registered_[trial->trial_name()] = trial; |
| 979 } | 1044 } |
| 980 | 1045 |
| 981 } // namespace base | 1046 } // namespace base |
| OLD | NEW |