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

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 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 479 matching lines...) Expand 10 before | Expand all | Expand 10 after
729 // processes are properly reported in crash reports. 749 // processes are properly reported in crash reports.
730 trial->group(); 750 trial->group();
731 } 751 }
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,
760 int fd_key) {
740 global_->create_trials_from_command_line_called_ = true; 761 global_->create_trials_from_command_line_called_ = true;
741 762
742 #if defined(OS_WIN) && !defined(OS_NACL) 763 #if defined(OS_WIN)
743 if (cmd_line.HasSwitch(field_trial_handle_switch)) { 764 if (cmd_line.HasSwitch(field_trial_handle_switch)) {
744 std::string arg = cmd_line.GetSwitchValueASCII(field_trial_handle_switch); 765 std::string handle_switch =
745 int field_trial_handle = std::stoi(arg); 766 cmd_line.GetSwitchValueASCII(field_trial_handle_switch);
746 HANDLE handle = reinterpret_cast<HANDLE>(field_trial_handle); 767 bool result = CreateTrialsFromHandleSwitch(handle_switch);
747 bool result = CreateTrialsFromWindowsHandle(handle);
748 DCHECK(result); 768 DCHECK(result);
749 } 769 }
750 #endif 770 #endif
751 771
772 #if defined(POSIX_WITH_ZYGOTE)
773 // If we failed to create trials from the descriptor, fallback to the command
774 // line. Otherwise we're good -- return.
775 if (CreateTrialsFromDescriptor(fd_key))
776 return;
777 #endif
778
752 if (cmd_line.HasSwitch(switches::kForceFieldTrials)) { 779 if (cmd_line.HasSwitch(switches::kForceFieldTrials)) {
753 bool result = FieldTrialList::CreateTrialsFromString( 780 bool result = FieldTrialList::CreateTrialsFromString(
754 cmd_line.GetSwitchValueASCII(switches::kForceFieldTrials), 781 cmd_line.GetSwitchValueASCII(switches::kForceFieldTrials),
755 std::set<std::string>()); 782 std::set<std::string>());
756 DCHECK(result); 783 DCHECK(result);
757 } 784 }
758 } 785 }
759 786
787 #if defined(POSIX_WITH_ZYGOTE)
788 // static
789 bool FieldTrialList::CreateTrialsFromDescriptor(int fd_key) {
790 if (!kUseSharedMemoryForFieldTrials)
791 return false;
792
793 if (fd_key == -1)
794 return false;
795
796 int fd = GlobalDescriptors::GetInstance()->MaybeGet(fd_key);
797 if (fd == -1)
798 return false;
799
800 SharedMemoryHandle shm_handle(fd, true);
801 bool result = FieldTrialList::CreateTrialsFromSharedMemoryHandle(shm_handle);
802 DCHECK(result);
803 return true;
804 }
805 #endif
806
760 #if defined(OS_WIN) 807 #if defined(OS_WIN)
761 // static 808 // static
762 void FieldTrialList::AppendFieldTrialHandleIfNeeded( 809 void FieldTrialList::AppendFieldTrialHandleIfNeeded(
763 HandlesToInheritVector* handles) { 810 HandlesToInheritVector* handles) {
764 if (!global_) 811 if (!global_)
765 return; 812 return;
766 if (kUseSharedMemoryForFieldTrials) { 813 if (kUseSharedMemoryForFieldTrials) {
767 InstantiateFieldTrialAllocatorIfNeeded(); 814 InstantiateFieldTrialAllocatorIfNeeded();
768 if (global_->readonly_allocator_handle_) 815 if (global_->readonly_allocator_handle_)
769 handles->push_back(global_->readonly_allocator_handle_); 816 handles->push_back(global_->readonly_allocator_handle_);
770 } 817 }
771 } 818 }
772 #endif 819 #endif
773 820
821 #if defined(OS_POSIX) && !defined(OS_NACL)
822 // static
823 int FieldTrialList::GetFieldTrialHandle() {
824 if (!global_)
825 return kInvalidPlatformFile;
826 if (kUseSharedMemoryForFieldTrials) {
827 InstantiateFieldTrialAllocatorIfNeeded();
828 // We check for an invalid handle where this gets called.
829 return global_->readonly_allocator_handle_;
830 }
831 return kInvalidPlatformFile;
832 }
833 #endif
834
774 // static 835 // static
775 void FieldTrialList::CopyFieldTrialStateToFlags( 836 void FieldTrialList::CopyFieldTrialStateToFlags(
776 const char* field_trial_handle_switch, 837 const char* field_trial_handle_switch,
777 CommandLine* cmd_line) { 838 CommandLine* cmd_line) {
778 // TODO(lawrencewu): Ideally, having the global would be guaranteed. However, 839 // TODO(lawrencewu): Ideally, having the global would be guaranteed. However,
779 // content browser tests currently don't create a FieldTrialList because they 840 // content browser tests currently don't create a FieldTrialList because they
780 // don't run ChromeBrowserMainParts code where it's done for Chrome. 841 // don't run ChromeBrowserMainParts code where it's done for Chrome.
781 if (!global_) 842 if (!global_)
782 return; 843 return;
783 844
784 #if defined(OS_WIN) 845 #if defined(OS_WIN) || defined(POSIX_WITH_ZYGOTE)
785 // Use shared memory to pass the state if the feature is enabled, otherwise 846 // 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. 847 // fallback to passing it via the command line as a string.
787 if (kUseSharedMemoryForFieldTrials) { 848 if (kUseSharedMemoryForFieldTrials) {
788 InstantiateFieldTrialAllocatorIfNeeded(); 849 InstantiateFieldTrialAllocatorIfNeeded();
789 // If the readonly handle didn't get duplicated properly, then fallback to 850 // If the readonly handle didn't get duplicated properly, then fallback to
790 // original behavior. 851 // original behavior.
791 if (!global_->readonly_allocator_handle_) { 852 if (global_->readonly_allocator_handle_ == kInvalidPlatformFile) {
792 AddForceFieldTrialsFlag(cmd_line); 853 AddForceFieldTrialsFlag(cmd_line);
793 return; 854 return;
794 } 855 }
795 856
796 // HANDLE is just typedef'd to void *. We basically cast the handle into an 857 global_->field_trial_allocator_->UpdateTrackingHistograms();
797 // int (uintptr_t, to be exact), stringify the int, and pass it as a 858
798 // command-line flag. The child process will do the reverse conversions to 859 // We need to pass a named anonymous handle to shared memory over the
799 // retrieve the handle. See http://stackoverflow.com/a/153077 860 // command line on Windows, since the child doesn't know which of the
861 // handles it inherited it should open. On POSIX, we don't need to do this
862 // -- we dup the fd into a fixed fd kFieldTrialDescriptor, so we can just
863 // look it up there.
864 #if defined(OS_WIN)
865 // PlatformFile is typedef'd to HANDLE which is typedef'd to void *. We
866 // basically cast the handle into an int (uintptr_t, to be exact), stringify
867 // the int, and pass it as a command-line flag. The child process will do
868 // the reverse conversions to retrieve the handle. See
869 // http://stackoverflow.com/a/153077
800 auto uintptr_handle = 870 auto uintptr_handle =
801 reinterpret_cast<uintptr_t>(global_->readonly_allocator_handle_); 871 reinterpret_cast<uintptr_t>(global_->readonly_allocator_handle_);
802 std::string field_trial_handle = std::to_string(uintptr_handle); 872 std::string field_trial_handle = std::to_string(uintptr_handle);
803 cmd_line->AppendSwitchASCII(field_trial_handle_switch, field_trial_handle); 873 cmd_line->AppendSwitchASCII(field_trial_handle_switch, field_trial_handle);
804 global_->field_trial_allocator_->UpdateTrackingHistograms(); 874 #endif
805 return; 875 return;
806 } 876 }
807 #endif 877 #endif
808 878
809 AddForceFieldTrialsFlag(cmd_line); 879 AddForceFieldTrialsFlag(cmd_line);
810 } 880 }
811 881
812 // static 882 // static
813 FieldTrial* FieldTrialList::CreateFieldTrial( 883 FieldTrial* FieldTrialList::CreateFieldTrial(
814 const std::string& name, 884 const std::string& name,
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
887 // static 957 // static
888 size_t FieldTrialList::GetFieldTrialCount() { 958 size_t FieldTrialList::GetFieldTrialCount() {
889 if (!global_) 959 if (!global_)
890 return 0; 960 return 0;
891 AutoLock auto_lock(global_->lock_); 961 AutoLock auto_lock(global_->lock_);
892 return global_->registered_.size(); 962 return global_->registered_.size();
893 } 963 }
894 964
895 #if defined(OS_WIN) 965 #if defined(OS_WIN)
896 // static 966 // static
897 bool FieldTrialList::CreateTrialsFromWindowsHandle(HANDLE handle) { 967 bool FieldTrialList::CreateTrialsFromHandleSwitch(
968 const std::string& handle_switch) {
969 int field_trial_handle = std::stoi(handle_switch);
970 HANDLE handle = reinterpret_cast<HANDLE>(field_trial_handle);
898 SharedMemoryHandle shm_handle(handle, GetCurrentProcId()); 971 SharedMemoryHandle shm_handle(handle, GetCurrentProcId());
972 return FieldTrialList::CreateTrialsFromSharedMemoryHandle(shm_handle);
973 }
974 #endif
899 975
976 #if !defined(OS_NACL)
977 // static
978 bool FieldTrialList::CreateTrialsFromSharedMemoryHandle(
979 SharedMemoryHandle shm_handle) {
900 // shm gets deleted when it gets out of scope, but that's OK because we need 980 // 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. 981 // it only for the duration of this method.
902 std::unique_ptr<SharedMemory> shm(new SharedMemory(shm_handle, true)); 982 std::unique_ptr<SharedMemory> shm(new SharedMemory(shm_handle, true));
903 if (!shm.get()->Map(kFieldTrialAllocationSize)) 983 if (!shm.get()->Map(kFieldTrialAllocationSize))
904 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); 984 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize);
905 985
906 return FieldTrialList::CreateTrialsFromSharedMemory(std::move(shm)); 986 return FieldTrialList::CreateTrialsFromSharedMemory(std::move(shm));
907 } 987 }
908 #endif 988 #endif
909 989
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
979 #if !defined(OS_NACL) 1059 #if !defined(OS_NACL)
980 // static 1060 // static
981 void FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded() { 1061 void FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded() {
982 if (!global_) 1062 if (!global_)
983 return; 1063 return;
984 AutoLock auto_lock(global_->lock_); 1064 AutoLock auto_lock(global_->lock_);
985 // Create the allocator if not already created and add all existing trials. 1065 // Create the allocator if not already created and add all existing trials.
986 if (global_->field_trial_allocator_ != nullptr) 1066 if (global_->field_trial_allocator_ != nullptr)
987 return; 1067 return;
988 1068
1069 SharedMemoryCreateOptions options;
1070 options.size = kFieldTrialAllocationSize;
1071 options.share_read_only = true;
1072
989 std::unique_ptr<SharedMemory> shm(new SharedMemory()); 1073 std::unique_ptr<SharedMemory> shm(new SharedMemory());
990 if (!shm->CreateAndMapAnonymous(kFieldTrialAllocationSize)) 1074 if (!shm->Create(options))
1075 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize);
1076
1077 if (!shm->Map(kFieldTrialAllocationSize))
991 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); 1078 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize);
992 1079
993 global_->field_trial_allocator_.reset( 1080 global_->field_trial_allocator_.reset(
994 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, false)); 1081 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, false));
995 global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName); 1082 global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName);
996 1083
997 // Add all existing field trials. 1084 // Add all existing field trials.
998 for (const auto& registered : global_->registered_) { 1085 for (const auto& registered : global_->registered_) {
999 AddToAllocatorWhileLocked(registered.second); 1086 AddToAllocatorWhileLocked(registered.second);
1000 } 1087 }
1001 1088
1002 #if defined(OS_WIN) 1089 #if defined(OS_WIN) || defined(POSIX_WITH_ZYGOTE)
1003 // Set |readonly_allocator_handle_| so we can pass it to be inherited and 1090 // Set |readonly_allocator_handle_| so we can pass it to be inherited and
1004 // via the command line. 1091 // via the command line.
1005 global_->readonly_allocator_handle_ = 1092 global_->readonly_allocator_handle_ =
1006 CreateReadOnlyHandle(global_->field_trial_allocator_.get()); 1093 CreateReadOnlyHandle(global_->field_trial_allocator_.get());
1007 #endif 1094 #endif
1008 } 1095 }
1009 #endif 1096 #endif
1010 1097
1011 // static 1098 // static
1012 void FieldTrialList::AddToAllocatorWhileLocked(FieldTrial* field_trial) { 1099 void FieldTrialList::AddToAllocatorWhileLocked(FieldTrial* field_trial) {
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
1107 return; 1194 return;
1108 } 1195 }
1109 AutoLock auto_lock(global_->lock_); 1196 AutoLock auto_lock(global_->lock_);
1110 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); 1197 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name();
1111 trial->AddRef(); 1198 trial->AddRef();
1112 trial->SetTrialRegistered(); 1199 trial->SetTrialRegistered();
1113 global_->registered_[trial->trial_name()] = trial; 1200 global_->registered_[trial->trial_name()] = trial;
1114 } 1201 }
1115 1202
1116 } // namespace base 1203 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698