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

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

Issue 2530573002: Share field trial allocator on zygote-using Linuxes (Closed)
Patch Set: revert to excluding nacl in ifdef 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 191 matching lines...) Expand 10 before | Expand all | Expand 10 after
225 } 236 }
226 } 237 }
227 238
228 #if defined(OS_WIN) 239 #if defined(OS_WIN)
229 HANDLE CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) { 240 HANDLE CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) {
230 HANDLE src = allocator->shared_memory()->handle().GetHandle(); 241 HANDLE src = allocator->shared_memory()->handle().GetHandle();
231 ProcessHandle process = GetCurrentProcess(); 242 ProcessHandle process = GetCurrentProcess();
232 DWORD access = SECTION_MAP_READ | SECTION_QUERY; 243 DWORD access = SECTION_MAP_READ | SECTION_QUERY;
233 HANDLE dst; 244 HANDLE dst;
234 if (!::DuplicateHandle(process, src, process, &dst, access, true, 0)) 245 if (!::DuplicateHandle(process, src, process, &dst, access, true, 0))
235 return nullptr; 246 return kInvalidPlatformFile;
236 return dst; 247 return dst;
237 } 248 }
238 #endif 249 #endif
239 250
251 #if defined(POSIX_WITH_ZYGOTE)
252 int CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) {
253 SharedMemoryHandle new_handle;
254 allocator->shared_memory()->ShareReadOnlyToProcess(GetCurrentProcessHandle(),
255 &new_handle);
256 return SharedMemory::GetFdFromSharedMemoryHandle(new_handle);
257 }
258 #endif
259
240 } // namespace 260 } // namespace
241 261
242 // statics 262 // statics
243 const int FieldTrial::kNotFinalized = -1; 263 const int FieldTrial::kNotFinalized = -1;
244 const int FieldTrial::kDefaultGroupNumber = 0; 264 const int FieldTrial::kDefaultGroupNumber = 0;
245 bool FieldTrial::enable_benchmarking_ = false; 265 bool FieldTrial::enable_benchmarking_ = false;
246 266
247 int FieldTrialList::kNoExpirationYear = 0; 267 int FieldTrialList::kNoExpirationYear = 0;
248 268
249 //------------------------------------------------------------------------------ 269 //------------------------------------------------------------------------------
(...skipping 482 matching lines...) Expand 10 before | Expand all | Expand 10 after
732 } 752 }
733 return true; 753 return true;
734 } 754 }
735 755
736 // static 756 // static
737 void FieldTrialList::CreateTrialsFromCommandLine( 757 void FieldTrialList::CreateTrialsFromCommandLine(
738 const CommandLine& cmd_line, 758 const CommandLine& cmd_line,
739 const char* field_trial_handle_switch) { 759 const char* field_trial_handle_switch) {
740 global_->create_trials_from_command_line_called_ = true; 760 global_->create_trials_from_command_line_called_ = true;
741 761
742 #if defined(OS_WIN) && !defined(OS_NACL)
743 if (cmd_line.HasSwitch(field_trial_handle_switch)) {
744 std::string arg = cmd_line.GetSwitchValueASCII(field_trial_handle_switch);
745 int field_trial_handle = std::stoi(arg);
746 HANDLE handle = reinterpret_cast<HANDLE>(field_trial_handle);
747 bool result = CreateTrialsFromWindowsHandle(handle);
748 DCHECK(result);
749 }
750 #endif
751
752 if (cmd_line.HasSwitch(switches::kForceFieldTrials)) { 762 if (cmd_line.HasSwitch(switches::kForceFieldTrials)) {
753 bool result = FieldTrialList::CreateTrialsFromString( 763 bool result = FieldTrialList::CreateTrialsFromString(
754 cmd_line.GetSwitchValueASCII(switches::kForceFieldTrials), 764 cmd_line.GetSwitchValueASCII(switches::kForceFieldTrials),
755 std::set<std::string>()); 765 std::set<std::string>());
756 DCHECK(result); 766 DCHECK(result);
757 } 767 }
768
769 #if defined(OS_WIN)
770 if (cmd_line.HasSwitch(field_trial_handle_switch)) {
771 std::string handle_switch =
772 cmd_line.GetSwitchValueASCII(field_trial_handle_switch);
773 bool result = CreateTrialsFromHandleSwitch(handle_switch);
774 DCHECK(result);
775 }
776 #endif
758 } 777 }
759 778
779 #if defined(POSIX_WITH_ZYGOTE)
780 // static
781 bool FieldTrialList::CreateTrialsFromDescriptor(int field_trial_descriptor_id) {
782 if (!kUseSharedMemoryForFieldTrials)
783 return false;
784
785 int fd =
786 GlobalDescriptors::GetInstance()->MaybeGet(field_trial_descriptor_id);
787 if (fd == -1)
788 return false;
789
790 global_->create_trials_from_command_line_called_ = true;
791
792 SharedMemoryHandle shm_handle(fd, true);
793 bool result = FieldTrialList::CreateTrialsFromSharedMemoryHandle(shm_handle);
794 DCHECK(result);
795 return true;
796 }
797 #endif
798
760 #if defined(OS_WIN) 799 #if defined(OS_WIN)
761 // static 800 // static
762 void FieldTrialList::AppendFieldTrialHandleIfNeeded( 801 void FieldTrialList::AppendFieldTrialHandleIfNeeded(
763 HandlesToInheritVector* handles) { 802 HandlesToInheritVector* handles) {
764 if (!global_) 803 if (!global_)
765 return; 804 return;
766 if (kUseSharedMemoryForFieldTrials) { 805 if (kUseSharedMemoryForFieldTrials) {
767 InstantiateFieldTrialAllocatorIfNeeded(); 806 InstantiateFieldTrialAllocatorIfNeeded();
768 if (global_->readonly_allocator_handle_) 807 if (global_->readonly_allocator_handle_)
769 handles->push_back(global_->readonly_allocator_handle_); 808 handles->push_back(global_->readonly_allocator_handle_);
770 } 809 }
771 } 810 }
772 #endif 811 #endif
773 812
813 #if defined(OS_POSIX) && !defined(OS_NACL)
814 // static
815 int FieldTrialList::GetFieldTrialHandle() {
816 if (!global_)
817 return kInvalidPlatformFile;
818 if (kUseSharedMemoryForFieldTrials) {
819 InstantiateFieldTrialAllocatorIfNeeded();
820 // We check for an invalid handle where this gets called.
821 return global_->readonly_allocator_handle_;
822 }
823 return kInvalidPlatformFile;
824 }
825 #endif
826
774 // static 827 // static
775 void FieldTrialList::CopyFieldTrialStateToFlags( 828 void FieldTrialList::CopyFieldTrialStateToFlags(
776 const char* field_trial_handle_switch, 829 const char* field_trial_handle_switch,
777 CommandLine* cmd_line) { 830 CommandLine* cmd_line) {
778 // TODO(lawrencewu): Ideally, having the global would be guaranteed. However, 831 // TODO(lawrencewu): Ideally, having the global would be guaranteed. However,
779 // content browser tests currently don't create a FieldTrialList because they 832 // content browser tests currently don't create a FieldTrialList because they
780 // don't run ChromeBrowserMainParts code where it's done for Chrome. 833 // don't run ChromeBrowserMainParts code where it's done for Chrome.
781 if (!global_) 834 if (!global_)
782 return; 835 return;
783 836
784 #if defined(OS_WIN) 837 #if defined(OS_WIN) || defined(POSIX_WITH_ZYGOTE)
785 // Use shared memory to pass the state if the feature is enabled, otherwise 838 // Use shared memory to pass the state if the feature is enabled, otherwise
786 // fallback to passing it via the command line as a string. 839 // fallback to passing it via the command line as a string.
787 if (kUseSharedMemoryForFieldTrials) { 840 if (kUseSharedMemoryForFieldTrials) {
788 InstantiateFieldTrialAllocatorIfNeeded(); 841 InstantiateFieldTrialAllocatorIfNeeded();
789 // If the readonly handle didn't get duplicated properly, then fallback to 842 // If the readonly handle didn't get duplicated properly, then fallback to
790 // original behavior. 843 // original behavior.
791 if (!global_->readonly_allocator_handle_) { 844 if (global_->readonly_allocator_handle_ == kInvalidPlatformFile) {
792 AddForceFieldTrialsFlag(cmd_line); 845 AddForceFieldTrialsFlag(cmd_line);
793 return; 846 return;
794 } 847 }
795 848
796 // HANDLE is just typedef'd to void *. We basically cast the handle into an 849 #if defined(OS_WIN)
Alexei Svitkine (slow) 2016/11/29 17:38:27 Add a comment above this to mention why it's win o
lawrencewu 2016/11/29 19:11:01 Done.
797 // int (uintptr_t, to be exact), stringify the int, and pass it as a 850 // PlatformFile is typedef'd to HANDLE which is typedef'd to void *. We
798 // command-line flag. The child process will do the reverse conversions to 851 // basically cast the handle into an int (uintptr_t, to be exact), stringify
799 // retrieve the handle. See http://stackoverflow.com/a/153077 852 // the int, and pass it as a command-line flag. The child process will do
853 // the reverse conversions to retrieve the handle. See
854 // http://stackoverflow.com/a/153077
800 auto uintptr_handle = 855 auto uintptr_handle =
801 reinterpret_cast<uintptr_t>(global_->readonly_allocator_handle_); 856 reinterpret_cast<uintptr_t>(global_->readonly_allocator_handle_);
802 std::string field_trial_handle = std::to_string(uintptr_handle); 857 std::string field_trial_handle = std::to_string(uintptr_handle);
803 cmd_line->AppendSwitchASCII(field_trial_handle_switch, field_trial_handle); 858 cmd_line->AppendSwitchASCII(field_trial_handle_switch, field_trial_handle);
859 #endif
804 global_->field_trial_allocator_->UpdateTrackingHistograms(); 860 global_->field_trial_allocator_->UpdateTrackingHistograms();
805 return; 861 return;
806 } 862 }
807 #endif 863 #endif
808 864
809 AddForceFieldTrialsFlag(cmd_line); 865 AddForceFieldTrialsFlag(cmd_line);
810 } 866 }
811 867
812 // static 868 // static
813 FieldTrial* FieldTrialList::CreateFieldTrial( 869 FieldTrial* FieldTrialList::CreateFieldTrial(
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
887 // static 943 // static
888 size_t FieldTrialList::GetFieldTrialCount() { 944 size_t FieldTrialList::GetFieldTrialCount() {
889 if (!global_) 945 if (!global_)
890 return 0; 946 return 0;
891 AutoLock auto_lock(global_->lock_); 947 AutoLock auto_lock(global_->lock_);
892 return global_->registered_.size(); 948 return global_->registered_.size();
893 } 949 }
894 950
895 #if defined(OS_WIN) 951 #if defined(OS_WIN)
896 // static 952 // static
897 bool FieldTrialList::CreateTrialsFromWindowsHandle(HANDLE handle) { 953 bool FieldTrialList::CreateTrialsFromHandleSwitch(
954 const std::string& handle_switch) {
955 int field_trial_handle = std::stoi(handle_switch);
956 HANDLE handle = reinterpret_cast<HANDLE>(field_trial_handle);
898 SharedMemoryHandle shm_handle(handle, GetCurrentProcId()); 957 SharedMemoryHandle shm_handle(handle, GetCurrentProcId());
958 return FieldTrialList::CreateTrialsFromSharedMemoryHandle(shm_handle);
959 }
960 #endif
899 961
962 #if !defined(OS_NACL)
963 // static
964 bool FieldTrialList::CreateTrialsFromSharedMemoryHandle(
965 SharedMemoryHandle shm_handle) {
900 // shm gets deleted when it gets out of scope, but that's OK because we need 966 // shm gets deleted when it gets out of scope, but that's OK because we need
901 // it only for the duration of this method. 967 // it only for the duration of this method.
902 std::unique_ptr<SharedMemory> shm(new SharedMemory(shm_handle, true)); 968 std::unique_ptr<SharedMemory> shm(new SharedMemory(shm_handle, true));
903 if (!shm.get()->Map(kFieldTrialAllocationSize)) 969 if (!shm.get()->Map(kFieldTrialAllocationSize))
904 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); 970 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize);
905 971
906 return FieldTrialList::CreateTrialsFromSharedMemory(std::move(shm)); 972 return FieldTrialList::CreateTrialsFromSharedMemory(std::move(shm));
907 } 973 }
908 #endif 974 #endif
909 975
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
979 #if !defined(OS_NACL) 1045 #if !defined(OS_NACL)
980 // static 1046 // static
981 void FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded() { 1047 void FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded() {
982 if (!global_) 1048 if (!global_)
983 return; 1049 return;
984 AutoLock auto_lock(global_->lock_); 1050 AutoLock auto_lock(global_->lock_);
985 // Create the allocator if not already created and add all existing trials. 1051 // Create the allocator if not already created and add all existing trials.
986 if (global_->field_trial_allocator_ != nullptr) 1052 if (global_->field_trial_allocator_ != nullptr)
987 return; 1053 return;
988 1054
1055 SharedMemoryCreateOptions options;
1056 options.size = kFieldTrialAllocationSize;
1057 options.share_read_only = true;
1058
989 std::unique_ptr<SharedMemory> shm(new SharedMemory()); 1059 std::unique_ptr<SharedMemory> shm(new SharedMemory());
990 if (!shm->CreateAndMapAnonymous(kFieldTrialAllocationSize)) 1060 if (!shm->Create(options))
1061 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize);
1062
1063 if (!shm->Map(kFieldTrialAllocationSize))
991 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); 1064 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize);
992 1065
993 global_->field_trial_allocator_.reset( 1066 global_->field_trial_allocator_.reset(
994 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, false)); 1067 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, false));
995 global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName); 1068 global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName);
996 1069
997 // Add all existing field trials. 1070 // Add all existing field trials.
998 for (const auto& registered : global_->registered_) { 1071 for (const auto& registered : global_->registered_) {
999 AddToAllocatorWhileLocked(registered.second); 1072 AddToAllocatorWhileLocked(registered.second);
1000 } 1073 }
1001 1074
1002 #if defined(OS_WIN) 1075 #if defined(OS_WIN) || defined(POSIX_WITH_ZYGOTE)
1003 // Set |readonly_allocator_handle_| so we can pass it to be inherited and 1076 // Set |readonly_allocator_handle_| so we can pass it to be inherited and
1004 // via the command line. 1077 // via the command line.
1005 global_->readonly_allocator_handle_ = 1078 global_->readonly_allocator_handle_ =
1006 CreateReadOnlyHandle(global_->field_trial_allocator_.get()); 1079 CreateReadOnlyHandle(global_->field_trial_allocator_.get());
1007 #endif 1080 #endif
1008 } 1081 }
1009 #endif 1082 #endif
1010 1083
1011 // static 1084 // static
1012 void FieldTrialList::AddToAllocatorWhileLocked(FieldTrial* field_trial) { 1085 void FieldTrialList::AddToAllocatorWhileLocked(FieldTrial* field_trial) {
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
1107 return; 1180 return;
1108 } 1181 }
1109 AutoLock auto_lock(global_->lock_); 1182 AutoLock auto_lock(global_->lock_);
1110 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); 1183 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name();
1111 trial->AddRef(); 1184 trial->AddRef();
1112 trial->SetTrialRegistered(); 1185 trial->SetTrialRegistered();
1113 global_->registered_[trial->trial_name()] = trial; 1186 global_->registered_[trial->trial_name()] = trial;
1114 } 1187 }
1115 1188
1116 } // namespace base 1189 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698