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

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

Issue 2530573002: Share field trial allocator on zygote-using Linuxes (Closed)
Patch Set: git rebase-update 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 #if defined(POSIX_WITH_ZYGOTE)
25 #include "base/posix/global_descriptors.h"
26 #endif
27
24 namespace base { 28 namespace base {
25 29
26 namespace { 30 namespace {
27 31
28 // Define a separator character to use when creating a persistent form of an 32 // 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 33 // 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). 34 // second process to mimic our state (i.e., provide the same group name).
31 const char kPersistentStringSeparator = '/'; // Currently a slash. 35 const char kPersistentStringSeparator = '/'; // Currently a slash.
32 36
33 // Define a marker character to be used as a prefix to a trial name on the 37 // 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 } 229 }
226 } 230 }
227 231
228 #if defined(OS_WIN) 232 #if defined(OS_WIN)
229 HANDLE CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) { 233 HANDLE CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) {
230 HANDLE src = allocator->shared_memory()->handle().GetHandle(); 234 HANDLE src = allocator->shared_memory()->handle().GetHandle();
231 ProcessHandle process = GetCurrentProcess(); 235 ProcessHandle process = GetCurrentProcess();
232 DWORD access = SECTION_MAP_READ | SECTION_QUERY; 236 DWORD access = SECTION_MAP_READ | SECTION_QUERY;
233 HANDLE dst; 237 HANDLE dst;
234 if (!::DuplicateHandle(process, src, process, &dst, access, true, 0)) 238 if (!::DuplicateHandle(process, src, process, &dst, access, true, 0))
235 return nullptr; 239 return kInvalidPlatformFile;
236 return dst; 240 return dst;
237 } 241 }
238 #endif 242 #endif
239 243
244 #if defined(POSIX_WITH_ZYGOTE)
245 int CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) {
246 SharedMemoryHandle new_handle;
247 allocator->shared_memory()->ShareReadOnlyToProcess(GetCurrentProcessHandle(),
248 &new_handle);
249 return SharedMemory::GetFdFromSharedMemoryHandle(new_handle);
250 }
251 #endif
252
240 } // namespace 253 } // namespace
241 254
242 // statics 255 // statics
243 const int FieldTrial::kNotFinalized = -1; 256 const int FieldTrial::kNotFinalized = -1;
244 const int FieldTrial::kDefaultGroupNumber = 0; 257 const int FieldTrial::kDefaultGroupNumber = 0;
245 bool FieldTrial::enable_benchmarking_ = false; 258 bool FieldTrial::enable_benchmarking_ = false;
246 259
247 int FieldTrialList::kNoExpirationYear = 0; 260 int FieldTrialList::kNoExpirationYear = 0;
248 261
249 //------------------------------------------------------------------------------ 262 //------------------------------------------------------------------------------
(...skipping 479 matching lines...) Expand 10 before | Expand all | Expand 10 after
729 // processes are properly reported in crash reports. 742 // processes are properly reported in crash reports.
730 trial->group(); 743 trial->group();
731 } 744 }
732 } 745 }
733 return true; 746 return true;
734 } 747 }
735 748
736 // static 749 // static
737 void FieldTrialList::CreateTrialsFromCommandLine( 750 void FieldTrialList::CreateTrialsFromCommandLine(
738 const CommandLine& cmd_line, 751 const CommandLine& cmd_line,
739 const char* field_trial_handle_switch) { 752 const char* field_trial_handle_switch,
753 const int field_trial_handle) {
740 global_->create_trials_from_command_line_called_ = true; 754 global_->create_trials_from_command_line_called_ = true;
741 755
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)) { 756 if (cmd_line.HasSwitch(switches::kForceFieldTrials)) {
753 bool result = FieldTrialList::CreateTrialsFromString( 757 bool result = FieldTrialList::CreateTrialsFromString(
754 cmd_line.GetSwitchValueASCII(switches::kForceFieldTrials), 758 cmd_line.GetSwitchValueASCII(switches::kForceFieldTrials),
755 std::set<std::string>()); 759 std::set<std::string>());
756 DCHECK(result); 760 DCHECK(result);
761 return;
757 } 762 }
763
764 #if defined(POSIX_WITH_ZYGOTE)
765 if (kUseSharedMemoryForFieldTrials) {
766 bool result = CreateTrialsFromFdKey(field_trial_handle);
767 DCHECK(result);
768 return;
769 }
770 #endif
771
772 #if defined(OS_WIN)
773 if (cmd_line.HasSwitch(field_trial_handle_switch)) {
774 std::string handle_switch =
775 cmd_line.GetSwitchValueASCII(field_trial_handle_switch);
776 bool result = CreateTrialsFromHandleSwitch(handle_switch);
777 DCHECK(result);
778 return;
779 }
780 #endif
758 } 781 }
759 782
760 #if defined(OS_WIN) 783 #if defined(OS_WIN)
761 // static 784 // static
762 void FieldTrialList::AppendFieldTrialHandleIfNeeded( 785 void FieldTrialList::AppendFieldTrialHandleIfNeeded(
763 HandlesToInheritVector* handles) { 786 HandlesToInheritVector* handles) {
764 if (!global_) 787 if (!global_)
765 return; 788 return;
766 if (kUseSharedMemoryForFieldTrials) { 789 if (kUseSharedMemoryForFieldTrials) {
767 InstantiateFieldTrialAllocatorIfNeeded(); 790 InstantiateFieldTrialAllocatorIfNeeded();
768 if (global_->readonly_allocator_handle_) 791 if (global_->readonly_allocator_handle_)
769 handles->push_back(global_->readonly_allocator_handle_); 792 handles->push_back(global_->readonly_allocator_handle_);
770 } 793 }
771 } 794 }
772 #endif 795 #endif
773 796
797 #if defined(OS_POSIX) && !defined(OS_NACL)
798 // static
799 int FieldTrialList::GetFieldTrialHandle() {
800 if (!global_)
801 return kInvalidPlatformFile;
802 if (kUseSharedMemoryForFieldTrials) {
803 InstantiateFieldTrialAllocatorIfNeeded();
804 // We check for an invalid handle where this gets called.
805 return global_->readonly_allocator_handle_;
806 }
807 return kInvalidPlatformFile;
808 }
809 #endif
810
774 // static 811 // static
775 void FieldTrialList::CopyFieldTrialStateToFlags( 812 void FieldTrialList::CopyFieldTrialStateToFlags(
776 const char* field_trial_handle_switch, 813 const char* field_trial_handle_switch,
777 CommandLine* cmd_line) { 814 CommandLine* cmd_line) {
778 // TODO(lawrencewu): Ideally, having the global would be guaranteed. However, 815 // TODO(lawrencewu): Ideally, having the global would be guaranteed. However,
779 // content browser tests currently don't create a FieldTrialList because they 816 // content browser tests currently don't create a FieldTrialList because they
780 // don't run ChromeBrowserMainParts code where it's done for Chrome. 817 // don't run ChromeBrowserMainParts code where it's done for Chrome.
781 if (!global_) 818 if (!global_)
782 return; 819 return;
783 820
784 #if defined(OS_WIN) 821 #if defined(OS_WIN)
785 // Use shared memory to pass the state if the feature is enabled, otherwise 822 // 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. 823 // fallback to passing it via the command line as a string.
787 if (kUseSharedMemoryForFieldTrials) { 824 if (kUseSharedMemoryForFieldTrials) {
788 InstantiateFieldTrialAllocatorIfNeeded(); 825 InstantiateFieldTrialAllocatorIfNeeded();
789 // If the readonly handle didn't get duplicated properly, then fallback to 826 // If the readonly handle didn't get duplicated properly, then fallback to
790 // original behavior. 827 // original behavior.
791 if (!global_->readonly_allocator_handle_) { 828 if (global_->readonly_allocator_handle_ == kInvalidPlatformFile) {
792 AddForceFieldTrialsFlag(cmd_line); 829 AddForceFieldTrialsFlag(cmd_line);
793 return; 830 return;
794 } 831 }
795 832
796 // HANDLE is just typedef'd to void *. We basically cast the handle into an 833 // PlatformFile is typedef'd to HANDLE which is typedef'd to void *. We
797 // int (uintptr_t, to be exact), stringify the int, and pass it as a 834 // basically cast the handle into an int (uintptr_t, to be exact), stringify
798 // command-line flag. The child process will do the reverse conversions to 835 // the int, and pass it as a command-line flag. The child process will do
799 // retrieve the handle. See http://stackoverflow.com/a/153077 836 // the reverse conversions to retrieve the handle. See
837 // http://stackoverflow.com/a/153077
800 auto uintptr_handle = 838 auto uintptr_handle =
801 reinterpret_cast<uintptr_t>(global_->readonly_allocator_handle_); 839 reinterpret_cast<uintptr_t>(global_->readonly_allocator_handle_);
802 std::string field_trial_handle = std::to_string(uintptr_handle); 840 std::string field_trial_handle = std::to_string(uintptr_handle);
803 cmd_line->AppendSwitchASCII(field_trial_handle_switch, field_trial_handle); 841 cmd_line->AppendSwitchASCII(field_trial_handle_switch, field_trial_handle);
804 global_->field_trial_allocator_->UpdateTrackingHistograms(); 842 global_->field_trial_allocator_->UpdateTrackingHistograms();
Alexei Svitkine (slow) 2016/11/28 16:56:13 We should also log this histogram on Linux.
lawrencewu 2016/11/29 14:38:07 Done.
805 return; 843 return;
806 } 844 }
807 #endif 845 #endif
808 846
809 AddForceFieldTrialsFlag(cmd_line); 847 AddForceFieldTrialsFlag(cmd_line);
Alexei Svitkine (slow) 2016/11/28 16:56:13 This results in force field trials flag always bei
lawrencewu 2016/11/29 14:38:07 Fixed.
810 } 848 }
811 849
812 // static 850 // static
813 FieldTrial* FieldTrialList::CreateFieldTrial( 851 FieldTrial* FieldTrialList::CreateFieldTrial(
814 const std::string& name, 852 const std::string& name,
815 const std::string& group_name) { 853 const std::string& group_name) {
816 DCHECK(global_); 854 DCHECK(global_);
817 DCHECK_GE(name.size(), 0u); 855 DCHECK_GE(name.size(), 0u);
818 DCHECK_GE(group_name.size(), 0u); 856 DCHECK_GE(group_name.size(), 0u);
819 if (name.empty() || group_name.empty() || !global_) 857 if (name.empty() || group_name.empty() || !global_)
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
887 // static 925 // static
888 size_t FieldTrialList::GetFieldTrialCount() { 926 size_t FieldTrialList::GetFieldTrialCount() {
889 if (!global_) 927 if (!global_)
890 return 0; 928 return 0;
891 AutoLock auto_lock(global_->lock_); 929 AutoLock auto_lock(global_->lock_);
892 return global_->registered_.size(); 930 return global_->registered_.size();
893 } 931 }
894 932
895 #if defined(OS_WIN) 933 #if defined(OS_WIN)
896 // static 934 // static
897 bool FieldTrialList::CreateTrialsFromWindowsHandle(HANDLE handle) { 935 bool FieldTrialList::CreateTrialsFromHandleSwitch(
936 const std::string& handle_switch) {
937 int field_trial_handle = std::stoi(handle_switch);
938 HANDLE handle = reinterpret_cast<HANDLE>(field_trial_handle);
898 SharedMemoryHandle shm_handle(handle, GetCurrentProcId()); 939 SharedMemoryHandle shm_handle(handle, GetCurrentProcId());
940 return FieldTrialList::CreateTrialsFromSharedMemoryHandle(shm_handle);
941 }
942 #endif
899 943
944 #if defined(POSIX_WITH_ZYGOTE)
945 // static
946 bool FieldTrialList::CreateTrialsFromFdKey(const int fd_key) {
947 int fd = GlobalDescriptors::GetInstance()->Get(fd_key);
948 SharedMemoryHandle shm_handle(fd, true);
949 return FieldTrialList::CreateTrialsFromSharedMemoryHandle(shm_handle);
950 }
951 #endif
952
953 #if !defined(OS_NACL)
954 // static
955 bool FieldTrialList::CreateTrialsFromSharedMemoryHandle(
956 SharedMemoryHandle shm_handle) {
900 // shm gets deleted when it gets out of scope, but that's OK because we need 957 // 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. 958 // it only for the duration of this method.
902 std::unique_ptr<SharedMemory> shm(new SharedMemory(shm_handle, true)); 959 std::unique_ptr<SharedMemory> shm(new SharedMemory(shm_handle, true));
903 if (!shm.get()->Map(kFieldTrialAllocationSize)) 960 if (!shm.get()->Map(kFieldTrialAllocationSize))
904 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); 961 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize);
905 962
906 return FieldTrialList::CreateTrialsFromSharedMemory(std::move(shm)); 963 return FieldTrialList::CreateTrialsFromSharedMemory(std::move(shm));
907 } 964 }
908 #endif 965 #endif
909 966
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
979 #if !defined(OS_NACL) 1036 #if !defined(OS_NACL)
980 // static 1037 // static
981 void FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded() { 1038 void FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded() {
982 if (!global_) 1039 if (!global_)
983 return; 1040 return;
984 AutoLock auto_lock(global_->lock_); 1041 AutoLock auto_lock(global_->lock_);
985 // Create the allocator if not already created and add all existing trials. 1042 // Create the allocator if not already created and add all existing trials.
986 if (global_->field_trial_allocator_ != nullptr) 1043 if (global_->field_trial_allocator_ != nullptr)
987 return; 1044 return;
988 1045
1046 SharedMemoryCreateOptions options;
1047 options.size = kFieldTrialAllocationSize;
1048 options.share_read_only = true;
1049
989 std::unique_ptr<SharedMemory> shm(new SharedMemory()); 1050 std::unique_ptr<SharedMemory> shm(new SharedMemory());
990 if (!shm->CreateAndMapAnonymous(kFieldTrialAllocationSize)) 1051 if (!shm->Create(options))
1052 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize);
1053
1054 if (!shm->Map(kFieldTrialAllocationSize))
991 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); 1055 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize);
992 1056
993 global_->field_trial_allocator_.reset( 1057 global_->field_trial_allocator_.reset(
994 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, false)); 1058 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, false));
995 global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName); 1059 global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName);
996 1060
997 // Add all existing field trials. 1061 // Add all existing field trials.
998 for (const auto& registered : global_->registered_) { 1062 for (const auto& registered : global_->registered_) {
999 AddToAllocatorWhileLocked(registered.second); 1063 AddToAllocatorWhileLocked(registered.second);
1000 } 1064 }
1001 1065
1002 #if defined(OS_WIN) 1066 #if defined(OS_WIN) || defined(POSIX_WITH_ZYGOTE)
1003 // Set |readonly_allocator_handle_| so we can pass it to be inherited and 1067 // Set |readonly_allocator_handle_| so we can pass it to be inherited and
1004 // via the command line. 1068 // via the command line.
1005 global_->readonly_allocator_handle_ = 1069 global_->readonly_allocator_handle_ =
1006 CreateReadOnlyHandle(global_->field_trial_allocator_.get()); 1070 CreateReadOnlyHandle(global_->field_trial_allocator_.get());
1007 #endif 1071 #endif
1008 } 1072 }
1009 #endif 1073 #endif
1010 1074
1011 // static 1075 // static
1012 void FieldTrialList::AddToAllocatorWhileLocked(FieldTrial* field_trial) { 1076 void FieldTrialList::AddToAllocatorWhileLocked(FieldTrial* field_trial) {
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
1107 return; 1171 return;
1108 } 1172 }
1109 AutoLock auto_lock(global_->lock_); 1173 AutoLock auto_lock(global_->lock_);
1110 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); 1174 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name();
1111 trial->AddRef(); 1175 trial->AddRef();
1112 trial->SetTrialRegistered(); 1176 trial->SetTrialRegistered();
1113 global_->registered_[trial->trial_name()] = trial; 1177 global_->registered_[trial->trial_name()] = trial;
1114 } 1178 }
1115 1179
1116 } // namespace base 1180 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698