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 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
59 // This also doesn't allocate all 128 KiB at once -- the pages only get mapped | 59 // This also doesn't allocate all 128 KiB at once -- the pages only get mapped |
60 // to physical memory when they are touched. If the size of the allocated field | 60 // to physical memory when they are touched. If the size of the allocated field |
61 // trials does get larger than 128 KiB, then we will drop some field trials in | 61 // trials does get larger than 128 KiB, then we will drop some field trials in |
62 // child processes, leading to an inconsistent view between browser and child | 62 // child processes, leading to an inconsistent view between browser and child |
63 // processes and possibly causing crashes (see crbug.com/661617). | 63 // processes and possibly causing crashes (see crbug.com/661617). |
64 #if !defined(OS_NACL) | 64 #if !defined(OS_NACL) |
65 const size_t kFieldTrialAllocationSize = 128 << 10; // 128 KiB | 65 const size_t kFieldTrialAllocationSize = 128 << 10; // 128 KiB |
66 #endif | 66 #endif |
67 | 67 |
68 // We create one FieldTrialEntry per field trial in shared memory, via | 68 // We create one FieldTrialEntry per field trial in shared memory, via |
69 // AddToAllocatorWhileLocked. The FieldTrialEntry is followed by a base::Pickle | 69 // AddTrialToAllocatorWhileLocked. The FieldTrialEntry is followed by a |
70 // object that we unpickle and read from. Any changes to this structure requires | 70 // base::Pickle object that we unpickle and read from. Any changes to this |
71 // a bump in kFieldTrialType id defined above. | 71 // structure requires a bump in kFieldTrialType id defined above. |
72 struct FieldTrialEntry { | 72 struct FieldTrialEntry { |
73 // Expected size for 32/64-bit check. | 73 // Expected size for 32/64-bit check. |
74 static constexpr size_t kExpectedInstanceSize = 8; | 74 static constexpr size_t kExpectedInstanceSize = 8; |
75 | 75 |
76 // Whether or not this field trial is activated. This is really just a boolean | 76 // Whether or not this field trial is activated. This is really just a boolean |
77 // but marked as a uint32_t for portability reasons. | 77 // but marked as a uint32_t for portability reasons. |
78 uint32_t activated; | 78 uint32_t activated; |
79 | 79 |
80 // Size of the pickled structure, NOT the total size of this entry. | 80 // Size of the pickled structure, NOT the total size of this entry. |
81 uint32_t size; | 81 uint32_t size; |
(...skipping 650 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
732 if (CreateTrialsFromDescriptor(fd_key)) | 732 if (CreateTrialsFromDescriptor(fd_key)) |
733 return; | 733 return; |
734 #endif | 734 #endif |
735 | 735 |
736 if (cmd_line.HasSwitch(switches::kForceFieldTrials)) { | 736 if (cmd_line.HasSwitch(switches::kForceFieldTrials)) { |
737 bool result = FieldTrialList::CreateTrialsFromString( | 737 bool result = FieldTrialList::CreateTrialsFromString( |
738 cmd_line.GetSwitchValueASCII(switches::kForceFieldTrials), | 738 cmd_line.GetSwitchValueASCII(switches::kForceFieldTrials), |
739 std::set<std::string>()); | 739 std::set<std::string>()); |
740 DCHECK(result); | 740 DCHECK(result); |
741 } | 741 } |
| 742 |
| 743 // TODO(lawrencewu): rename CreateTrialsFromCommandLine to |
| 744 // CreateTrialsAndFeaturesFromCommandLine, cause that's what we're doing. |
| 745 FeatureList::GetInstance()->InitializeFromSharedMemory( |
| 746 global_->field_trial_allocator_.get()); |
742 } | 747 } |
743 | 748 |
744 #if defined(POSIX_WITH_ZYGOTE) | 749 #if defined(POSIX_WITH_ZYGOTE) |
745 // static | 750 // static |
746 bool FieldTrialList::CreateTrialsFromDescriptor(int fd_key) { | 751 bool FieldTrialList::CreateTrialsFromDescriptor(int fd_key) { |
747 if (!kUseSharedMemoryForFieldTrials) | 752 if (!kUseSharedMemoryForFieldTrials) |
748 return false; | 753 return false; |
749 | 754 |
750 if (fd_key == -1) | 755 if (fd_key == -1) |
751 return false; | 756 return false; |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
872 if (!global_) | 877 if (!global_) |
873 return; | 878 return; |
874 global_->observer_list_->RemoveObserver(observer); | 879 global_->observer_list_->RemoveObserver(observer); |
875 } | 880 } |
876 | 881 |
877 // static | 882 // static |
878 void FieldTrialList::OnGroupFinalized(bool is_locked, FieldTrial* field_trial) { | 883 void FieldTrialList::OnGroupFinalized(bool is_locked, FieldTrial* field_trial) { |
879 if (!global_) | 884 if (!global_) |
880 return; | 885 return; |
881 if (is_locked) { | 886 if (is_locked) { |
882 AddToAllocatorWhileLocked(field_trial); | 887 AddTrialToAllocatorWhileLocked(field_trial); |
883 } else { | 888 } else { |
884 AutoLock auto_lock(global_->lock_); | 889 AutoLock auto_lock(global_->lock_); |
885 AddToAllocatorWhileLocked(field_trial); | 890 AddTrialToAllocatorWhileLocked(field_trial); |
886 } | 891 } |
887 } | 892 } |
888 | 893 |
889 // static | 894 // static |
890 void FieldTrialList::NotifyFieldTrialGroupSelection(FieldTrial* field_trial) { | 895 void FieldTrialList::NotifyFieldTrialGroupSelection(FieldTrial* field_trial) { |
891 if (!global_) | 896 if (!global_) |
892 return; | 897 return; |
893 | 898 |
894 { | 899 { |
895 AutoLock auto_lock(global_->lock_); | 900 AutoLock auto_lock(global_->lock_); |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
997 | 1002 |
998 if (!shm->Map(kFieldTrialAllocationSize)) | 1003 if (!shm->Map(kFieldTrialAllocationSize)) |
999 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); | 1004 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); |
1000 | 1005 |
1001 global_->field_trial_allocator_.reset( | 1006 global_->field_trial_allocator_.reset( |
1002 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, false)); | 1007 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, false)); |
1003 global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName); | 1008 global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName); |
1004 | 1009 |
1005 // Add all existing field trials. | 1010 // Add all existing field trials. |
1006 for (const auto& registered : global_->registered_) { | 1011 for (const auto& registered : global_->registered_) { |
1007 AddToAllocatorWhileLocked(registered.second); | 1012 AddTrialToAllocatorWhileLocked(registered.second); |
1008 } | 1013 } |
1009 | 1014 |
| 1015 // Add all existing features. |
| 1016 FeatureList::GetInstance()->AddFeaturesToAllocator( |
| 1017 global_->field_trial_allocator_.get()); |
| 1018 |
1010 #if defined(OS_WIN) || defined(POSIX_WITH_ZYGOTE) | 1019 #if defined(OS_WIN) || defined(POSIX_WITH_ZYGOTE) |
1011 // Set |readonly_allocator_handle_| so we can pass it to be inherited and | 1020 // Set |readonly_allocator_handle_| so we can pass it to be inherited and |
1012 // via the command line. | 1021 // via the command line. |
1013 global_->readonly_allocator_handle_ = | 1022 global_->readonly_allocator_handle_ = |
1014 CreateReadOnlyHandle(global_->field_trial_allocator_.get()); | 1023 CreateReadOnlyHandle(global_->field_trial_allocator_.get()); |
1015 #endif | 1024 #endif |
1016 } | 1025 } |
1017 #endif | 1026 #endif |
1018 | 1027 |
1019 // static | 1028 // static |
1020 void FieldTrialList::AddToAllocatorWhileLocked(FieldTrial* field_trial) { | 1029 void FieldTrialList::AddTrialToAllocatorWhileLocked(FieldTrial* field_trial) { |
1021 FieldTrialAllocator* allocator = global_->field_trial_allocator_.get(); | 1030 FieldTrialAllocator* allocator = global_->field_trial_allocator_.get(); |
1022 | 1031 |
1023 // Don't do anything if the allocator hasn't been instantiated yet. | 1032 // Don't do anything if the allocator hasn't been instantiated yet. |
1024 if (allocator == nullptr) | 1033 if (allocator == nullptr) |
1025 return; | 1034 return; |
1026 | 1035 |
1027 // Or if the allocator is read only, which means we are in a child process and | 1036 // Or if the allocator is read only, which means we are in a child process and |
1028 // shouldn't be writing to it. | 1037 // shouldn't be writing to it. |
1029 if (allocator->IsReadonly()) | 1038 if (allocator->IsReadonly()) |
1030 return; | 1039 return; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1068 FieldTrialAllocator* allocator = global_->field_trial_allocator_.get(); | 1077 FieldTrialAllocator* allocator = global_->field_trial_allocator_.get(); |
1069 | 1078 |
1070 // Check if we're in the child process and return early if so. | 1079 // Check if we're in the child process and return early if so. |
1071 if (allocator && allocator->IsReadonly()) | 1080 if (allocator && allocator->IsReadonly()) |
1072 return; | 1081 return; |
1073 | 1082 |
1074 FieldTrial::FieldTrialRef ref = field_trial->ref_; | 1083 FieldTrial::FieldTrialRef ref = field_trial->ref_; |
1075 if (ref == FieldTrialAllocator::kReferenceNull) { | 1084 if (ref == FieldTrialAllocator::kReferenceNull) { |
1076 // It's fine to do this even if the allocator hasn't been instantiated | 1085 // It's fine to do this even if the allocator hasn't been instantiated |
1077 // yet -- it'll just return early. | 1086 // yet -- it'll just return early. |
1078 AddToAllocatorWhileLocked(field_trial); | 1087 AddTrialToAllocatorWhileLocked(field_trial); |
1079 } else { | 1088 } else { |
1080 // It's also okay to do this even though the callee doesn't have a lock -- | 1089 // It's also okay to do this even though the callee doesn't have a lock -- |
1081 // the only thing that happens on a stale read here is a slight performance | 1090 // the only thing that happens on a stale read here is a slight performance |
1082 // hit from the child re-synchronizing activation state. | 1091 // hit from the child re-synchronizing activation state. |
1083 FieldTrialEntry* entry = | 1092 FieldTrialEntry* entry = |
1084 allocator->GetAsObject<FieldTrialEntry>(ref, kFieldTrialType); | 1093 allocator->GetAsObject<FieldTrialEntry>(ref, kFieldTrialType); |
1085 entry->activated = true; | 1094 entry->activated = true; |
1086 } | 1095 } |
1087 } | 1096 } |
1088 | 1097 |
(...skipping 22 matching lines...) Expand all Loading... |
1111 return; | 1120 return; |
1112 } | 1121 } |
1113 AutoLock auto_lock(global_->lock_); | 1122 AutoLock auto_lock(global_->lock_); |
1114 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); | 1123 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); |
1115 trial->AddRef(); | 1124 trial->AddRef(); |
1116 trial->SetTrialRegistered(); | 1125 trial->SetTrialRegistered(); |
1117 global_->registered_[trial->trial_name()] = trial; | 1126 global_->registered_[trial->trial_name()] = trial; |
1118 } | 1127 } |
1119 | 1128 |
1120 } // namespace base | 1129 } // namespace base |
OLD | NEW |