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

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

Issue 2530573002: Share field trial allocator on zygote-using Linuxes (Closed)
Patch Set: address comments 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/debug/alias.h" 13 #include "base/debug/alias.h"
14 #include "base/feature_list.h" 14 #include "base/feature_list.h"
15 #include "base/logging.h" 15 #include "base/logging.h"
16 #include "base/pickle.h" 16 #include "base/pickle.h"
17 #include "base/process/memory.h" 17 #include "base/process/memory.h"
18 #include "base/rand_util.h" 18 #include "base/rand_util.h"
19 #include "base/strings/string_number_conversions.h" 19 #include "base/strings/string_number_conversions.h"
20 #include "base/strings/string_util.h" 20 #include "base/strings/string_util.h"
21 #include "base/strings/stringprintf.h" 21 #include "base/strings/stringprintf.h"
22 #include "base/strings/utf_string_conversions.h" 22 #include "base/strings/utf_string_conversions.h"
23 23
24 // On systems that use the zygote process to spawn child processes, we must
25 // retrieve the correct fd using the mapping in GlobalDescriptors.
26 #if defined(OS_POSIX) && !defined(OS_NACL) && !defined(OS_MACOSX) && \
27 !defined(OS_ANDROID)
28 #define POSIX_WITH_ZYGOTE 1
29 #endif
30
31 #if defined(POSIX_WITH_ZYGOTE)
32 #include "base/posix/global_descriptors.h"
33 #endif
34
24 namespace base { 35 namespace base {
25 36
26 namespace { 37 namespace {
27 38
28 // Define a separator character to use when creating a persistent form of an 39 // Define a separator character to use when creating a persistent form of an
29 // instance. This is intended for use as a command line argument, passed to a 40 // instance. This is intended for use as a command line argument, passed to a
30 // second process to mimic our state (i.e., provide the same group name). 41 // second process to mimic our state (i.e., provide the same group name).
31 const char kPersistentStringSeparator = '/'; // Currently a slash. 42 const char kPersistentStringSeparator = '/'; // Currently a slash.
32 43
33 // Define a marker character to be used as a prefix to a trial name on the 44 // Define a marker character to be used as a prefix to a trial name on the
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after
226 } 237 }
227 } 238 }
228 239
229 #if defined(OS_WIN) 240 #if defined(OS_WIN)
230 HANDLE CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) { 241 HANDLE CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) {
231 HANDLE src = allocator->shared_memory()->handle().GetHandle(); 242 HANDLE src = allocator->shared_memory()->handle().GetHandle();
232 ProcessHandle process = GetCurrentProcess(); 243 ProcessHandle process = GetCurrentProcess();
233 DWORD access = SECTION_MAP_READ | SECTION_QUERY; 244 DWORD access = SECTION_MAP_READ | SECTION_QUERY;
234 HANDLE dst; 245 HANDLE dst;
235 if (!::DuplicateHandle(process, src, process, &dst, access, true, 0)) 246 if (!::DuplicateHandle(process, src, process, &dst, access, true, 0))
236 return nullptr; 247 return kInvalidPlatformHandle;
237 return dst; 248 return dst;
238 } 249 }
239 #endif 250 #endif
240 251
252 #if defined(POSIX_WITH_ZYGOTE)
253 int CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) {
254 SharedMemoryHandle new_handle;
255 allocator->shared_memory()->ShareReadOnlyToProcess(GetCurrentProcessHandle(),
256 &new_handle);
257 return SharedMemory::GetFdFromSharedMemoryHandle(new_handle);
258 }
259 #endif
260
241 } // namespace 261 } // namespace
242 262
243 // statics 263 // statics
244 const int FieldTrial::kNotFinalized = -1; 264 const int FieldTrial::kNotFinalized = -1;
245 const int FieldTrial::kDefaultGroupNumber = 0; 265 const int FieldTrial::kDefaultGroupNumber = 0;
246 bool FieldTrial::enable_benchmarking_ = false; 266 bool FieldTrial::enable_benchmarking_ = false;
247 267
248 int FieldTrialList::kNoExpirationYear = 0; 268 int FieldTrialList::kNoExpirationYear = 0;
249 269
250 //------------------------------------------------------------------------------ 270 //------------------------------------------------------------------------------
(...skipping 482 matching lines...) Expand 10 before | Expand all | Expand 10 after
733 } 753 }
734 return true; 754 return true;
735 } 755 }
736 756
737 // static 757 // static
738 void FieldTrialList::CreateTrialsFromCommandLine( 758 void FieldTrialList::CreateTrialsFromCommandLine(
739 const CommandLine& cmd_line, 759 const CommandLine& cmd_line,
740 const char* field_trial_handle_switch) { 760 const char* field_trial_handle_switch) {
741 global_->create_trials_from_command_line_called_ = true; 761 global_->create_trials_from_command_line_called_ = true;
742 762
743 #if defined(OS_WIN) && !defined(OS_NACL)
744 if (cmd_line.HasSwitch(field_trial_handle_switch)) { 763 if (cmd_line.HasSwitch(field_trial_handle_switch)) {
745 std::string arg = cmd_line.GetSwitchValueASCII(field_trial_handle_switch); 764 std::string handle_switch =
746 int field_trial_handle = std::stoi(arg); 765 cmd_line.GetSwitchValueASCII(field_trial_handle_switch);
747 HANDLE handle = reinterpret_cast<HANDLE>(field_trial_handle); 766 bool result = CreateTrialsFromHandleSwitch(handle_switch);
748 bool result = CreateTrialsFromWindowsHandle(handle);
749 DCHECK(result); 767 DCHECK(result);
750 } 768 }
751 #endif
752 769
753 if (cmd_line.HasSwitch(switches::kForceFieldTrials)) { 770 if (cmd_line.HasSwitch(switches::kForceFieldTrials)) {
754 bool result = FieldTrialList::CreateTrialsFromString( 771 bool result = FieldTrialList::CreateTrialsFromString(
755 cmd_line.GetSwitchValueASCII(switches::kForceFieldTrials), 772 cmd_line.GetSwitchValueASCII(switches::kForceFieldTrials),
756 std::set<std::string>()); 773 std::set<std::string>());
757 DCHECK(result); 774 DCHECK(result);
758 } 775 }
759 } 776 }
760 777
761 #if defined(OS_WIN) 778 #if defined(OS_WIN)
762 // static 779 // static
763 void FieldTrialList::AppendFieldTrialHandleIfNeeded( 780 void FieldTrialList::AppendFieldTrialHandleIfNeeded(
764 HandlesToInheritVector* handles) { 781 HandlesToInheritVector* handles) {
765 if (!global_) 782 if (!global_)
766 return; 783 return;
767 if (kUseSharedMemoryForFieldTrials) { 784 if (kUseSharedMemoryForFieldTrials) {
768 InstantiateFieldTrialAllocatorIfNeeded(); 785 InstantiateFieldTrialAllocatorIfNeeded();
769 if (global_->readonly_allocator_handle_) 786 if (global_->readonly_allocator_handle_)
770 handles->push_back(global_->readonly_allocator_handle_); 787 handles->push_back(global_->readonly_allocator_handle_);
771 } 788 }
772 } 789 }
773 #endif 790 #endif
774 791
792 #if defined(OS_POSIX) && !defined(OS_NACL)
793 // static
794 int FieldTrialList::GetFieldTrialHandle() {
795 if (!global_)
796 return kInvalidPlatformFile;
797 if (kUseSharedMemoryForFieldTrials) {
798 InstantiateFieldTrialAllocatorIfNeeded();
799 if (global_->readonly_allocator_handle_ != kInvalidPlatformFile)
800 return global_->readonly_allocator_handle_;
801 }
802 return kInvalidPlatformFile;
803 }
804 #endif
805
775 // static 806 // static
776 void FieldTrialList::CopyFieldTrialStateToFlags( 807 void FieldTrialList::CopyFieldTrialStateToFlags(
777 const char* field_trial_handle_switch, 808 const char* field_trial_handle_switch,
778 CommandLine* cmd_line) { 809 CommandLine* cmd_line) {
779 // TODO(lawrencewu): Ideally, having the global would be guaranteed. However, 810 // TODO(lawrencewu): Ideally, having the global would be guaranteed. However,
780 // content browser tests currently don't create a FieldTrialList because they 811 // content browser tests currently don't create a FieldTrialList because they
781 // don't run ChromeBrowserMainParts code where it's done for Chrome. 812 // don't run ChromeBrowserMainParts code where it's done for Chrome.
782 if (!global_) 813 if (!global_)
783 return; 814 return;
784 815
(...skipping 15 matching lines...) Expand all
800 // retrieve the handle. See http://stackoverflow.com/a/153077 831 // retrieve the handle. See http://stackoverflow.com/a/153077
801 auto uintptr_handle = 832 auto uintptr_handle =
802 reinterpret_cast<uintptr_t>(global_->readonly_allocator_handle_); 833 reinterpret_cast<uintptr_t>(global_->readonly_allocator_handle_);
803 std::string field_trial_handle = std::to_string(uintptr_handle); 834 std::string field_trial_handle = std::to_string(uintptr_handle);
804 cmd_line->AppendSwitchASCII(field_trial_handle_switch, field_trial_handle); 835 cmd_line->AppendSwitchASCII(field_trial_handle_switch, field_trial_handle);
805 global_->field_trial_allocator_->UpdateTrackingHistograms(); 836 global_->field_trial_allocator_->UpdateTrackingHistograms();
806 return; 837 return;
807 } 838 }
808 #endif 839 #endif
809 840
841 #if defined(POSIX_WITH_ZYGOTE)
842 // Use shared memory to pass the state if the feature is enabled, otherwise
843 // fallback to passing it via the command line as a string.
844 if (kUseSharedMemoryForFieldTrials) {
Alexei Svitkine (slow) 2016/11/24 18:23:19 This block seems to be almost identical to the one
lawrencewu 2016/11/24 18:48:59 Made nearly identical, still have to do some windo
845 InstantiateFieldTrialAllocatorIfNeeded();
846 // If the readonly handle didn't get duplicated properly, then fallback to
847 // original behavior.
848 if (global_->readonly_allocator_handle_ == kInvalidPlatformFile) {
849 AddForceFieldTrialsFlag(cmd_line);
850 return;
851 }
852
853 std::string field_trial_handle =
854 std::to_string(global_->readonly_allocator_handle_);
855 cmd_line->AppendSwitchASCII(field_trial_handle_switch, field_trial_handle);
856 global_->field_trial_allocator_->UpdateTrackingHistograms();
857 return;
858 }
859 #endif
860
810 AddForceFieldTrialsFlag(cmd_line); 861 AddForceFieldTrialsFlag(cmd_line);
811 } 862 }
812 863
813 // static 864 // static
814 FieldTrial* FieldTrialList::CreateFieldTrial( 865 FieldTrial* FieldTrialList::CreateFieldTrial(
815 const std::string& name, 866 const std::string& name,
816 const std::string& group_name) { 867 const std::string& group_name) {
817 DCHECK(global_); 868 DCHECK(global_);
818 DCHECK_GE(name.size(), 0u); 869 DCHECK_GE(name.size(), 0u);
819 DCHECK_GE(group_name.size(), 0u); 870 DCHECK_GE(group_name.size(), 0u);
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
886 } 937 }
887 938
888 // static 939 // static
889 size_t FieldTrialList::GetFieldTrialCount() { 940 size_t FieldTrialList::GetFieldTrialCount() {
890 if (!global_) 941 if (!global_)
891 return 0; 942 return 0;
892 AutoLock auto_lock(global_->lock_); 943 AutoLock auto_lock(global_->lock_);
893 return global_->registered_.size(); 944 return global_->registered_.size();
894 } 945 }
895 946
947 // static
948 bool FieldTrialList::CreateTrialsFromHandleSwitch(
949 const std::string& handle_switch) {
896 #if defined(OS_WIN) 950 #if defined(OS_WIN)
951 int field_trial_handle = std::stoi(handle_switch);
952 HANDLE handle = reinterpret_cast<HANDLE>(field_trial_handle);
953 SharedMemoryHandle shm_handle(handle, GetCurrentProcId());
954 return FieldTrialList::CreateTrialsFromSharedMemoryHandle(shm_handle);
955 #endif
956
957 #if defined(POSIX_WITH_ZYGOTE)
958 int fd_key = std::stoi(handle_switch);
959 int fd = GlobalDescriptors::GetInstance()->Get(fd_key);
960 SharedMemoryHandle shm_handle(fd, true);
961 return FieldTrialList::CreateTrialsFromSharedMemoryHandle(shm_handle);
962 #endif
963
964 #if !defined(OS_WIN) && !defined(POSIX_WITH_ZYGOTE)
965 return false;
966 #endif
967 }
968
969 #if !defined(OS_NACL)
897 // static 970 // static
898 bool FieldTrialList::CreateTrialsFromWindowsHandle(HANDLE handle) { 971 bool FieldTrialList::CreateTrialsFromSharedMemoryHandle(
899 SharedMemoryHandle shm_handle(handle, GetCurrentProcId()); 972 SharedMemoryHandle shm_handle) {
900
901 // shm gets deleted when it gets out of scope, but that's OK because we need 973 // shm gets deleted when it gets out of scope, but that's OK because we need
902 // it only for the duration of this method. 974 // it only for the duration of this method.
903 std::unique_ptr<SharedMemory> shm(new SharedMemory(shm_handle, true)); 975 std::unique_ptr<SharedMemory> shm(new SharedMemory(shm_handle, true));
904 if (!shm.get()->Map(kFieldTrialAllocationSize)) 976 if (!shm.get()->Map(kFieldTrialAllocationSize))
905 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); 977 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize);
906 978
907 return FieldTrialList::CreateTrialsFromSharedMemory(std::move(shm)); 979 return FieldTrialList::CreateTrialsFromSharedMemory(std::move(shm));
908 } 980 }
909 #endif 981 #endif
910 982
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
980 #if !defined(OS_NACL) 1052 #if !defined(OS_NACL)
981 // static 1053 // static
982 void FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded() { 1054 void FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded() {
983 if (!global_) 1055 if (!global_)
984 return; 1056 return;
985 AutoLock auto_lock(global_->lock_); 1057 AutoLock auto_lock(global_->lock_);
986 // Create the allocator if not already created and add all existing trials. 1058 // Create the allocator if not already created and add all existing trials.
987 if (global_->field_trial_allocator_ != nullptr) 1059 if (global_->field_trial_allocator_ != nullptr)
988 return; 1060 return;
989 1061
1062 SharedMemoryCreateOptions options;
1063 options.size = kFieldTrialAllocationSize;
1064 options.share_read_only = true;
1065
990 std::unique_ptr<SharedMemory> shm(new SharedMemory()); 1066 std::unique_ptr<SharedMemory> shm(new SharedMemory());
991 if (!shm->CreateAndMapAnonymous(kFieldTrialAllocationSize)) 1067 if (!shm->Create(options))
1068 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize);
1069
1070 if (!shm->Map(kFieldTrialAllocationSize))
992 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); 1071 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize);
993 1072
994 global_->field_trial_allocator_.reset( 1073 global_->field_trial_allocator_.reset(
995 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, false)); 1074 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, false));
996 global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName); 1075 global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName);
997 1076
998 // Add all existing field trials. 1077 // Add all existing field trials.
999 for (const auto& registered : global_->registered_) { 1078 for (const auto& registered : global_->registered_) {
1000 AddToAllocatorWhileLocked(registered.second); 1079 AddToAllocatorWhileLocked(registered.second);
1001 } 1080 }
1002 1081
1003 #if defined(OS_WIN) 1082 #if defined(OS_WIN) || defined(POSIX_WITH_ZYGOTE)
1004 // Set |readonly_allocator_handle_| so we can pass it to be inherited and 1083 // Set |readonly_allocator_handle_| so we can pass it to be inherited and
1005 // via the command line. 1084 // via the command line.
1006 global_->readonly_allocator_handle_ = 1085 global_->readonly_allocator_handle_ =
1007 CreateReadOnlyHandle(global_->field_trial_allocator_.get()); 1086 CreateReadOnlyHandle(global_->field_trial_allocator_.get());
1008 #endif 1087 #endif
1009 } 1088 }
1010 #endif 1089 #endif
1011 1090
1012 // static 1091 // static
1013 void FieldTrialList::AddToAllocatorWhileLocked(FieldTrial* field_trial) { 1092 void FieldTrialList::AddToAllocatorWhileLocked(FieldTrial* field_trial) {
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
1108 return; 1187 return;
1109 } 1188 }
1110 AutoLock auto_lock(global_->lock_); 1189 AutoLock auto_lock(global_->lock_);
1111 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); 1190 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name();
1112 trial->AddRef(); 1191 trial->AddRef();
1113 trial->SetTrialRegistered(); 1192 trial->SetTrialRegistered();
1114 global_->registered_[trial->trial_name()] = trial; 1193 global_->registered_[trial->trial_name()] = trial;
1115 } 1194 }
1116 1195
1117 } // namespace base 1196 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698