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

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

Issue 2546653002: Store and retrieve features from shared memory (Closed)
Patch Set: add comment 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/feature_list.h"
14 #include "base/logging.h" 13 #include "base/logging.h"
15 #include "base/metrics/field_trial_param_associator.h" 14 #include "base/metrics/field_trial_param_associator.h"
16 #include "base/pickle.h" 15 #include "base/pickle.h"
17 #include "base/process/memory.h" 16 #include "base/process/memory.h"
18 #include "base/rand_util.h" 17 #include "base/rand_util.h"
19 #include "base/strings/string_number_conversions.h" 18 #include "base/strings/string_number_conversions.h"
20 #include "base/strings/string_util.h" 19 #include "base/strings/string_util.h"
21 #include "base/strings/stringprintf.h" 20 #include "base/strings/stringprintf.h"
22 #include "base/strings/utf_string_conversions.h" 21 #include "base/strings/utf_string_conversions.h"
23 22
(...skipping 18 matching lines...) Expand all
42 const char kPersistentStringSeparator = '/'; // Currently a slash. 41 const char kPersistentStringSeparator = '/'; // Currently a slash.
43 42
44 // Define a marker character to be used as a prefix to a trial name on the 43 // Define a marker character to be used as a prefix to a trial name on the
45 // command line which forces its activation. 44 // command line which forces its activation.
46 const char kActivationMarker = '*'; 45 const char kActivationMarker = '*';
47 46
48 // Use shared memory to communicate field trial (experiment) state. Set to false 47 // Use shared memory to communicate field trial (experiment) state. Set to false
49 // for now while the implementation is fleshed out (e.g. data format, single 48 // for now while the implementation is fleshed out (e.g. data format, single
50 // shared memory segment). See https://codereview.chromium.org/2365273004/ and 49 // shared memory segment). See https://codereview.chromium.org/2365273004/ and
51 // crbug.com/653874 50 // crbug.com/653874
51 // The browser is the only process that has write access to the shared memory.
52 // This is safe from race conditions because MakeIterable is a release operation
53 // and GetNextOfType is an acquire operation, so memory writes before
54 // MakeIterable happen before memory reads after GetNextOfType.
52 const bool kUseSharedMemoryForFieldTrials = true; 55 const bool kUseSharedMemoryForFieldTrials = true;
53 56
54 // Constants for the field trial allocator. 57 // Constants for the field trial allocator.
55 const char kAllocatorName[] = "FieldTrialAllocator"; 58 const char kAllocatorName[] = "FieldTrialAllocator";
56 const uint32_t kFieldTrialType = 0xABA17E13 + 2; // SHA1(FieldTrialEntry) v2 59 const uint32_t kFieldTrialType = 0xABA17E13 + 2; // SHA1(FieldTrialEntry) v2
57 60
58 // We allocate 128 KiB to hold all the field trial data. This should be enough, 61 // We allocate 128 KiB to hold all the field trial data. This should be enough,
59 // as most people use 3 - 25 KiB for field trials (as of 11/25/2016). 62 // as most people use 3 - 25 KiB for field trials (as of 11/25/2016).
60 // This also doesn't allocate all 128 KiB at once -- the pages only get mapped 63 // This also doesn't allocate all 128 KiB at once -- the pages only get mapped
61 // to physical memory when they are touched. If the size of the allocated field 64 // to physical memory when they are touched. If the size of the allocated field
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after
241 trials_string_piece.substr(next_item, name_end - next_item); 244 trials_string_piece.substr(next_item, name_end - next_item);
242 entry.group_name = 245 entry.group_name =
243 trials_string_piece.substr(name_end + 1, group_name_end - name_end - 1); 246 trials_string_piece.substr(name_end + 1, group_name_end - name_end - 1);
244 next_item = group_name_end + 1; 247 next_item = group_name_end + 1;
245 248
246 entries->push_back(std::move(entry)); 249 entries->push_back(std::move(entry));
247 } 250 }
248 return true; 251 return true;
249 } 252 }
250 253
251 void AddForceFieldTrialsFlag(CommandLine* cmd_line) { 254 void AddFeatureAndFieldTrialFlags(const char* enable_features_switch,
255 const char* disable_features_switch,
256 CommandLine* cmd_line) {
257 std::string enabled_features;
258 std::string disabled_features;
259 FeatureList::GetInstance()->GetFeatureOverrides(&enabled_features,
260 &disabled_features);
261
262 if (!enabled_features.empty())
263 cmd_line->AppendSwitchASCII(enable_features_switch, enabled_features);
264 if (!disabled_features.empty())
265 cmd_line->AppendSwitchASCII(disable_features_switch, disabled_features);
266
252 std::string field_trial_states; 267 std::string field_trial_states;
253 FieldTrialList::AllStatesToString(&field_trial_states); 268 FieldTrialList::AllStatesToString(&field_trial_states);
254 if (!field_trial_states.empty()) { 269 if (!field_trial_states.empty()) {
255 cmd_line->AppendSwitchASCII(switches::kForceFieldTrials, 270 cmd_line->AppendSwitchASCII(switches::kForceFieldTrials,
256 field_trial_states); 271 field_trial_states);
257 } 272 }
258 } 273 }
259 274
260 #if defined(OS_WIN) 275 #if defined(OS_WIN)
261 HANDLE CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) { 276 HANDLE CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) {
(...skipping 536 matching lines...) Expand 10 before | Expand all | Expand 10 after
798 #endif 813 #endif
799 814
800 if (cmd_line.HasSwitch(switches::kForceFieldTrials)) { 815 if (cmd_line.HasSwitch(switches::kForceFieldTrials)) {
801 bool result = FieldTrialList::CreateTrialsFromString( 816 bool result = FieldTrialList::CreateTrialsFromString(
802 cmd_line.GetSwitchValueASCII(switches::kForceFieldTrials), 817 cmd_line.GetSwitchValueASCII(switches::kForceFieldTrials),
803 std::set<std::string>()); 818 std::set<std::string>());
804 DCHECK(result); 819 DCHECK(result);
805 } 820 }
806 } 821 }
807 822
823 // static
824 void FieldTrialList::CreateFeaturesFromCommandLine(
825 const base::CommandLine& command_line,
826 const char* enable_features_switch,
827 const char* disable_features_switch,
828 FeatureList* feature_list) {
829 // Fallback to command line if not using shared memory.
830 if (!kUseSharedMemoryForFieldTrials ||
831 !global_->field_trial_allocator_.get()) {
832 return feature_list->InitializeFromCommandLine(
833 command_line.GetSwitchValueASCII(enable_features_switch),
834 command_line.GetSwitchValueASCII(disable_features_switch));
835 }
836
837 feature_list->InitializeFromSharedMemory(
838 global_->field_trial_allocator_.get());
839 }
840
808 #if defined(POSIX_WITH_ZYGOTE) 841 #if defined(POSIX_WITH_ZYGOTE)
809 // static 842 // static
810 bool FieldTrialList::CreateTrialsFromDescriptor(int fd_key) { 843 bool FieldTrialList::CreateTrialsFromDescriptor(int fd_key) {
811 if (!kUseSharedMemoryForFieldTrials) 844 if (!kUseSharedMemoryForFieldTrials)
812 return false; 845 return false;
813 846
814 if (fd_key == -1) 847 if (fd_key == -1)
815 return false; 848 return false;
816 849
817 int fd = GlobalDescriptors::GetInstance()->MaybeGet(fd_key); 850 int fd = GlobalDescriptors::GetInstance()->MaybeGet(fd_key);
(...skipping 29 matching lines...) Expand all
847 // We check for an invalid handle where this gets called. 880 // We check for an invalid handle where this gets called.
848 return global_->readonly_allocator_handle_; 881 return global_->readonly_allocator_handle_;
849 } 882 }
850 return kInvalidPlatformFile; 883 return kInvalidPlatformFile;
851 } 884 }
852 #endif 885 #endif
853 886
854 // static 887 // static
855 void FieldTrialList::CopyFieldTrialStateToFlags( 888 void FieldTrialList::CopyFieldTrialStateToFlags(
856 const char* field_trial_handle_switch, 889 const char* field_trial_handle_switch,
890 const char* enable_features_switch,
891 const char* disable_features_switch,
857 CommandLine* cmd_line) { 892 CommandLine* cmd_line) {
858 // TODO(lawrencewu): Ideally, having the global would be guaranteed. However, 893 // TODO(lawrencewu): Ideally, having the global would be guaranteed. However,
859 // content browser tests currently don't create a FieldTrialList because they 894 // content browser tests currently don't create a FieldTrialList because they
860 // don't run ChromeBrowserMainParts code where it's done for Chrome. 895 // don't run ChromeBrowserMainParts code where it's done for Chrome.
861 if (!global_) 896 // Some tests depend on the enable and disable features flag switch, though,
897 // so we can still add those even though AllStatesToString() will be a no-op.
898 if (!global_) {
899 AddFeatureAndFieldTrialFlags(enable_features_switch,
900 disable_features_switch, cmd_line);
862 return; 901 return;
902 }
863 903
864 #if defined(OS_WIN) || defined(POSIX_WITH_ZYGOTE) 904 #if defined(OS_WIN) || defined(POSIX_WITH_ZYGOTE)
865 // Use shared memory to pass the state if the feature is enabled, otherwise 905 // Use shared memory to pass the state if the feature is enabled, otherwise
866 // fallback to passing it via the command line as a string. 906 // fallback to passing it via the command line as a string.
867 if (kUseSharedMemoryForFieldTrials) { 907 if (kUseSharedMemoryForFieldTrials) {
868 InstantiateFieldTrialAllocatorIfNeeded(); 908 InstantiateFieldTrialAllocatorIfNeeded();
869 // If the readonly handle didn't get duplicated properly, then fallback to 909 // If the readonly handle didn't get duplicated properly, then fallback to
870 // original behavior. 910 // original behavior.
871 if (global_->readonly_allocator_handle_ == kInvalidPlatformFile) { 911 if (global_->readonly_allocator_handle_ == kInvalidPlatformFile) {
872 AddForceFieldTrialsFlag(cmd_line); 912 AddFeatureAndFieldTrialFlags(enable_features_switch,
913 disable_features_switch, cmd_line);
873 return; 914 return;
874 } 915 }
875 916
876 global_->field_trial_allocator_->UpdateTrackingHistograms(); 917 global_->field_trial_allocator_->UpdateTrackingHistograms();
877 918
878 #if defined(OS_WIN) 919 #if defined(OS_WIN)
879 // We need to pass a named anonymous handle to shared memory over the 920 // We need to pass a named anonymous handle to shared memory over the
880 // command line on Windows, since the child doesn't know which of the 921 // command line on Windows, since the child doesn't know which of the
881 // handles it inherited it should open. On POSIX, we don't need to do this 922 // handles it inherited it should open. On POSIX, we don't need to do this
882 // -- we dup the fd into a fixed fd kFieldTrialDescriptor, so we can just 923 // -- we dup the fd into a fixed fd kFieldTrialDescriptor, so we can just
883 // look it up there. 924 // look it up there.
884 // PlatformFile is typedef'd to HANDLE which is typedef'd to void *. We 925 // PlatformFile is typedef'd to HANDLE which is typedef'd to void *. We
885 // basically cast the handle into an int (uintptr_t, to be exact), stringify 926 // basically cast the handle into an int (uintptr_t, to be exact), stringify
886 // the int, and pass it as a command-line flag. The child process will do 927 // the int, and pass it as a command-line flag. The child process will do
887 // the reverse conversions to retrieve the handle. See 928 // the reverse conversions to retrieve the handle. See
888 // http://stackoverflow.com/a/153077 929 // http://stackoverflow.com/a/153077
889 auto uintptr_handle = 930 auto uintptr_handle =
890 reinterpret_cast<uintptr_t>(global_->readonly_allocator_handle_); 931 reinterpret_cast<uintptr_t>(global_->readonly_allocator_handle_);
891 std::string field_trial_handle = std::to_string(uintptr_handle); 932 std::string field_trial_handle = std::to_string(uintptr_handle);
892 cmd_line->AppendSwitchASCII(field_trial_handle_switch, field_trial_handle); 933 cmd_line->AppendSwitchASCII(field_trial_handle_switch, field_trial_handle);
893 #endif 934 #endif
894 return; 935 return;
895 } 936 }
896 #endif 937 #endif
897 938
898 AddForceFieldTrialsFlag(cmd_line); 939 AddFeatureAndFieldTrialFlags(enable_features_switch, disable_features_switch,
940 cmd_line);
899 } 941 }
900 942
901 // static 943 // static
902 FieldTrial* FieldTrialList::CreateFieldTrial( 944 FieldTrial* FieldTrialList::CreateFieldTrial(
903 const std::string& name, 945 const std::string& name,
904 const std::string& group_name) { 946 const std::string& group_name) {
905 DCHECK(global_); 947 DCHECK(global_);
906 DCHECK_GE(name.size(), 0u); 948 DCHECK_GE(name.size(), 0u);
907 DCHECK_GE(group_name.size(), 0u); 949 DCHECK_GE(group_name.size(), 0u);
908 if (name.empty() || group_name.empty() || !global_) 950 if (name.empty() || group_name.empty() || !global_)
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after
1164 1206
1165 global_->field_trial_allocator_.reset( 1207 global_->field_trial_allocator_.reset(
1166 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, false)); 1208 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, false));
1167 global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName); 1209 global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName);
1168 1210
1169 // Add all existing field trials. 1211 // Add all existing field trials.
1170 for (const auto& registered : global_->registered_) { 1212 for (const auto& registered : global_->registered_) {
1171 AddToAllocatorWhileLocked(registered.second); 1213 AddToAllocatorWhileLocked(registered.second);
1172 } 1214 }
1173 1215
1216 // Add all existing features.
1217 FeatureList::GetInstance()->AddFeaturesToAllocator(
1218 global_->field_trial_allocator_.get());
1219
1174 #if defined(OS_WIN) || defined(POSIX_WITH_ZYGOTE) 1220 #if defined(OS_WIN) || defined(POSIX_WITH_ZYGOTE)
1175 // Set |readonly_allocator_handle_| so we can pass it to be inherited and 1221 // Set |readonly_allocator_handle_| so we can pass it to be inherited and
1176 // via the command line. 1222 // via the command line.
1177 global_->readonly_allocator_handle_ = 1223 global_->readonly_allocator_handle_ =
1178 CreateReadOnlyHandle(global_->field_trial_allocator_.get()); 1224 CreateReadOnlyHandle(global_->field_trial_allocator_.get());
1179 #endif 1225 #endif
1180 } 1226 }
1181 #endif 1227 #endif
1182 1228
1183 // static 1229 // static
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
1279 return; 1325 return;
1280 } 1326 }
1281 AutoLock auto_lock(global_->lock_); 1327 AutoLock auto_lock(global_->lock_);
1282 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); 1328 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name();
1283 trial->AddRef(); 1329 trial->AddRef();
1284 trial->SetTrialRegistered(); 1330 trial->SetTrialRegistered();
1285 global_->registered_[trial->trial_name()] = trial; 1331 global_->registered_[trial->trial_name()] = trial;
1286 } 1332 }
1287 1333
1288 } // namespace base 1334 } // 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