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

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

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