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

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

Issue 2501283002: Refactor field_trial.cc (Closed)
Patch Set: keep flag the same Created 4 years, 1 month 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') | no next file » | 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"
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after
175 void AddForceFieldTrialsFlag(CommandLine* cmd_line) { 175 void AddForceFieldTrialsFlag(CommandLine* cmd_line) {
176 std::string field_trial_states; 176 std::string field_trial_states;
177 FieldTrialList::AllStatesToString(&field_trial_states); 177 FieldTrialList::AllStatesToString(&field_trial_states);
178 if (!field_trial_states.empty()) { 178 if (!field_trial_states.empty()) {
179 cmd_line->AppendSwitchASCII(switches::kForceFieldTrials, 179 cmd_line->AppendSwitchASCII(switches::kForceFieldTrials,
180 field_trial_states); 180 field_trial_states);
181 } 181 }
182 } 182 }
183 183
184 #if defined(OS_WIN) 184 #if defined(OS_WIN)
185 HANDLE CreateReadOnlyHandle(SharedPersistentMemoryAllocator* allocator) { 185 HANDLE CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) {
186 HANDLE src = allocator->shared_memory()->handle().GetHandle(); 186 HANDLE src = allocator->shared_memory()->handle().GetHandle();
187 ProcessHandle process = GetCurrentProcess(); 187 ProcessHandle process = GetCurrentProcess();
188 DWORD access = SECTION_MAP_READ | SECTION_QUERY; 188 DWORD access = SECTION_MAP_READ | SECTION_QUERY;
189 HANDLE dst; 189 HANDLE dst;
190 if (!::DuplicateHandle(process, src, process, &dst, access, true, 0)) 190 if (!::DuplicateHandle(process, src, process, &dst, access, true, 0))
191 return nullptr; 191 return nullptr;
192 return dst; 192 return dst;
193 } 193 }
194 #endif 194 #endif
195 195
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
318 divisor_(total_probability), 318 divisor_(total_probability),
319 default_group_name_(default_group_name), 319 default_group_name_(default_group_name),
320 random_(GetGroupBoundaryValue(total_probability, entropy_value)), 320 random_(GetGroupBoundaryValue(total_probability, entropy_value)),
321 accumulated_group_probability_(0), 321 accumulated_group_probability_(0),
322 next_group_number_(kDefaultGroupNumber + 1), 322 next_group_number_(kDefaultGroupNumber + 1),
323 group_(kNotFinalized), 323 group_(kNotFinalized),
324 enable_field_trial_(true), 324 enable_field_trial_(true),
325 forced_(false), 325 forced_(false),
326 group_reported_(false), 326 group_reported_(false),
327 trial_registered_(false), 327 trial_registered_(false),
328 ref_(SharedPersistentMemoryAllocator::kReferenceNull) { 328 ref_(FieldTrialList::FieldTrialAllocator::kReferenceNull) {
329 DCHECK_GT(total_probability, 0); 329 DCHECK_GT(total_probability, 0);
330 DCHECK(!trial_name_.empty()); 330 DCHECK(!trial_name_.empty());
331 DCHECK(!default_group_name_.empty()); 331 DCHECK(!default_group_name_.empty());
332 } 332 }
333 333
334 FieldTrial::~FieldTrial() {} 334 FieldTrial::~FieldTrial() {}
335 335
336 void FieldTrial::SetTrialRegistered() { 336 void FieldTrial::SetTrialRegistered() {
337 DCHECK_EQ(kNotFinalized, group_); 337 DCHECK_EQ(kNotFinalized, group_);
338 DCHECK(!trial_registered_); 338 DCHECK(!trial_registered_);
(...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after
658 658
659 // static 659 // static
660 void FieldTrialList::CreateTrialsFromCommandLine( 660 void FieldTrialList::CreateTrialsFromCommandLine(
661 const CommandLine& cmd_line, 661 const CommandLine& cmd_line,
662 const char* field_trial_handle_switch) { 662 const char* field_trial_handle_switch) {
663 DCHECK(global_); 663 DCHECK(global_);
664 664
665 #if defined(OS_WIN) && !defined(OS_NACL) 665 #if defined(OS_WIN) && !defined(OS_NACL)
666 if (cmd_line.HasSwitch(field_trial_handle_switch)) { 666 if (cmd_line.HasSwitch(field_trial_handle_switch)) {
667 std::string arg = cmd_line.GetSwitchValueASCII(field_trial_handle_switch); 667 std::string arg = cmd_line.GetSwitchValueASCII(field_trial_handle_switch);
668 size_t token = arg.find(","); 668 int field_trial_handle = std::stoi(arg);
669 int field_trial_handle = std::stoi(arg.substr(0, token));
670 size_t field_trial_length = std::stoi(arg.substr(token + 1, arg.length()));
671
672 HANDLE handle = reinterpret_cast<HANDLE>(field_trial_handle); 669 HANDLE handle = reinterpret_cast<HANDLE>(field_trial_handle);
673 SharedMemoryHandle shm_handle = 670 bool result = CreateTrialsFromWindowsHandle(handle);
674 SharedMemoryHandle(handle, GetCurrentProcId());
675
676 // Gets deleted when it gets out of scope, but that's OK because we need it
677 // only for the duration of this method.
678 std::unique_ptr<SharedMemory> shm(new SharedMemory(shm_handle, true));
679 if (!shm.get()->Map(field_trial_length))
680 TerminateBecauseOutOfMemory(field_trial_length);
681
682 bool result = FieldTrialList::CreateTrialsFromSharedMemory(std::move(shm));
683 DCHECK(result); 671 DCHECK(result);
684 return;
685 } 672 }
686 #endif 673 #endif
687 674
688 if (cmd_line.HasSwitch(switches::kForceFieldTrials)) { 675 if (cmd_line.HasSwitch(switches::kForceFieldTrials)) {
689 bool result = FieldTrialList::CreateTrialsFromString( 676 bool result = FieldTrialList::CreateTrialsFromString(
690 cmd_line.GetSwitchValueASCII(switches::kForceFieldTrials), 677 cmd_line.GetSwitchValueASCII(switches::kForceFieldTrials),
691 std::set<std::string>()); 678 std::set<std::string>());
692 DCHECK(result); 679 DCHECK(result);
693 } 680 }
694 } 681 }
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
728 AddForceFieldTrialsFlag(cmd_line); 715 AddForceFieldTrialsFlag(cmd_line);
729 return; 716 return;
730 } 717 }
731 718
732 // HANDLE is just typedef'd to void *. We basically cast the handle into an 719 // HANDLE is just typedef'd to void *. We basically cast the handle into an
733 // int (uintptr_t, to be exact), stringify the int, and pass it as a 720 // int (uintptr_t, to be exact), stringify the int, and pass it as a
734 // command-line flag. The child process will do the reverse conversions to 721 // command-line flag. The child process will do the reverse conversions to
735 // retrieve the handle. See http://stackoverflow.com/a/153077 722 // retrieve the handle. See http://stackoverflow.com/a/153077
736 auto uintptr_handle = 723 auto uintptr_handle =
737 reinterpret_cast<uintptr_t>(global_->readonly_allocator_handle_); 724 reinterpret_cast<uintptr_t>(global_->readonly_allocator_handle_);
738 size_t field_trial_length = 725 std::string field_trial_handle = std::to_string(uintptr_handle);
739 global_->field_trial_allocator_->shared_memory()->mapped_size();
740 std::string field_trial_handle = std::to_string(uintptr_handle) + "," +
741 std::to_string(field_trial_length);
742
743 cmd_line->AppendSwitchASCII(field_trial_handle_switch, field_trial_handle); 726 cmd_line->AppendSwitchASCII(field_trial_handle_switch, field_trial_handle);
744 global_->field_trial_allocator_->UpdateTrackingHistograms(); 727 global_->field_trial_allocator_->UpdateTrackingHistograms();
745 return; 728 return;
746 } 729 }
747 #endif 730 #endif
748 731
749 AddForceFieldTrialsFlag(cmd_line); 732 AddForceFieldTrialsFlag(cmd_line);
750 } 733 }
751 734
752 // static 735 // static
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
825 } 808 }
826 809
827 // static 810 // static
828 size_t FieldTrialList::GetFieldTrialCount() { 811 size_t FieldTrialList::GetFieldTrialCount() {
829 if (!global_) 812 if (!global_)
830 return 0; 813 return 0;
831 AutoLock auto_lock(global_->lock_); 814 AutoLock auto_lock(global_->lock_);
832 return global_->registered_.size(); 815 return global_->registered_.size();
833 } 816 }
834 817
818 #if defined(OS_WIN)
819 // static
820 bool FieldTrialList::CreateTrialsFromWindowsHandle(HANDLE handle) {
821 SharedMemoryHandle shm_handle =
822 SharedMemoryHandle(handle, GetCurrentProcId());
Alexei Svitkine (slow) 2016/11/16 01:55:12 Nit: SharedMemoryHandle shm_handle(andle, GetCurre
823
824 // shm gets deleted when it gets out of scope, but that's OK because we need
825 // it only for the duration of this method.
826 std::unique_ptr<SharedMemory> shm(new SharedMemory(shm_handle, true));
827 if (!shm.get()->Map(kFieldTrialAllocationSize))
828 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize);
829
830 return FieldTrialList::CreateTrialsFromSharedMemory(std::move(shm));
831 }
832 #endif
833
835 // static 834 // static
836 bool FieldTrialList::CreateTrialsFromSharedMemory( 835 bool FieldTrialList::CreateTrialsFromSharedMemory(
837 std::unique_ptr<SharedMemory> shm) { 836 std::unique_ptr<SharedMemory> shm) {
838 global_->field_trial_allocator_.reset(new SharedPersistentMemoryAllocator( 837 global_->field_trial_allocator_.reset(
839 std::move(shm), 0, kAllocatorName, true)); 838 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, true));
840 SharedPersistentMemoryAllocator* shalloc = 839 FieldTrialAllocator* shalloc = global_->field_trial_allocator_.get();
841 global_->field_trial_allocator_.get(); 840 FieldTrialAllocator::Iterator mem_iter(shalloc);
842 PersistentMemoryAllocator::Iterator mem_iter(shalloc);
843 841
844 SharedPersistentMemoryAllocator::Reference ref; 842 FieldTrial::FieldTrialRef ref;
845 while ((ref = mem_iter.GetNextOfType(kFieldTrialType)) != 843 while ((ref = mem_iter.GetNextOfType(kFieldTrialType)) !=
846 SharedPersistentMemoryAllocator::kReferenceNull) { 844 FieldTrialAllocator::kReferenceNull) {
847 const FieldTrialEntry* entry = 845 const FieldTrialEntry* entry =
848 shalloc->GetAsObject<const FieldTrialEntry>(ref, kFieldTrialType); 846 shalloc->GetAsObject<const FieldTrialEntry>(ref, kFieldTrialType);
849 847
850 StringPiece trial_name; 848 StringPiece trial_name;
851 StringPiece group_name; 849 StringPiece group_name;
852 if (!entry->GetTrialAndGroupName(&trial_name, &group_name)) 850 if (!entry->GetTrialAndGroupName(&trial_name, &group_name))
853 return false; 851 return false;
854 852
855 // TODO(lawrencewu): Convert the API for CreateFieldTrial to take 853 // TODO(lawrencewu): Convert the API for CreateFieldTrial to take
856 // StringPieces. 854 // StringPieces.
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
893 return; 891 return;
894 AutoLock auto_lock(global_->lock_); 892 AutoLock auto_lock(global_->lock_);
895 // Create the allocator if not already created and add all existing trials. 893 // Create the allocator if not already created and add all existing trials.
896 if (global_->field_trial_allocator_ != nullptr) 894 if (global_->field_trial_allocator_ != nullptr)
897 return; 895 return;
898 896
899 std::unique_ptr<SharedMemory> shm(new SharedMemory()); 897 std::unique_ptr<SharedMemory> shm(new SharedMemory());
900 if (!shm->CreateAndMapAnonymous(kFieldTrialAllocationSize)) 898 if (!shm->CreateAndMapAnonymous(kFieldTrialAllocationSize))
901 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); 899 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize);
902 900
903 global_->field_trial_allocator_.reset(new SharedPersistentMemoryAllocator( 901 global_->field_trial_allocator_.reset(
904 std::move(shm), 0, kAllocatorName, false)); 902 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, false));
905 global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName); 903 global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName);
906 904
907 // Add all existing field trials. 905 // Add all existing field trials.
908 for (const auto& registered : global_->registered_) { 906 for (const auto& registered : global_->registered_) {
909 AddToAllocatorWhileLocked(registered.second); 907 AddToAllocatorWhileLocked(registered.second);
910 } 908 }
911 909
912 #if defined(OS_WIN) 910 #if defined(OS_WIN)
913 // Set |readonly_allocator_handle_| so we can pass it to be inherited and 911 // Set |readonly_allocator_handle_| so we can pass it to be inherited and
914 // via the command line. 912 // via the command line.
915 global_->readonly_allocator_handle_ = 913 global_->readonly_allocator_handle_ =
916 CreateReadOnlyHandle(global_->field_trial_allocator_.get()); 914 CreateReadOnlyHandle(global_->field_trial_allocator_.get());
917 #endif 915 #endif
918 } 916 }
919 #endif 917 #endif
920 918
921 // static 919 // static
922 void FieldTrialList::AddToAllocatorWhileLocked(FieldTrial* field_trial) { 920 void FieldTrialList::AddToAllocatorWhileLocked(FieldTrial* field_trial) {
923 SharedPersistentMemoryAllocator* allocator = 921 FieldTrialAllocator* allocator = global_->field_trial_allocator_.get();
924 global_->field_trial_allocator_.get();
925 922
926 // Don't do anything if the allocator hasn't been instantiated yet. 923 // Don't do anything if the allocator hasn't been instantiated yet.
927 if (allocator == nullptr) 924 if (allocator == nullptr)
928 return; 925 return;
929 926
930 // Or if the allocator is read only, which means we are in a child process and 927 // Or if the allocator is read only, which means we are in a child process and
931 // shouldn't be writing to it. 928 // shouldn't be writing to it.
932 if (allocator->IsReadonly()) 929 if (allocator->IsReadonly())
933 return; 930 return;
934 931
935 FieldTrial::State trial_state; 932 FieldTrial::State trial_state;
936 if (!field_trial->GetStateWhileLocked(&trial_state)) 933 if (!field_trial->GetStateWhileLocked(&trial_state))
937 return; 934 return;
938 935
939 // Or if we've already added it. We must check after GetState since it can 936 // Or if we've already added it. We must check after GetState since it can
940 // also add to the allocator. 937 // also add to the allocator.
941 if (field_trial->ref_) 938 if (field_trial->ref_)
942 return; 939 return;
943 940
944 Pickle pickle; 941 Pickle pickle;
945 pickle.WriteString(trial_state.trial_name); 942 pickle.WriteString(trial_state.trial_name);
946 pickle.WriteString(trial_state.group_name); 943 pickle.WriteString(trial_state.group_name);
947 944
948 size_t total_size = sizeof(FieldTrialEntry) + pickle.size(); 945 size_t total_size = sizeof(FieldTrialEntry) + pickle.size();
949 SharedPersistentMemoryAllocator::Reference ref = 946 FieldTrial::FieldTrialRef ref =
950 allocator->Allocate(total_size, kFieldTrialType); 947 allocator->Allocate(total_size, kFieldTrialType);
951 if (ref == SharedPersistentMemoryAllocator::kReferenceNull) 948 if (ref == FieldTrialAllocator::kReferenceNull)
952 return; 949 return;
953 950
954 FieldTrialEntry* entry = 951 FieldTrialEntry* entry =
955 allocator->GetAsObject<FieldTrialEntry>(ref, kFieldTrialType); 952 allocator->GetAsObject<FieldTrialEntry>(ref, kFieldTrialType);
956 entry->activated = trial_state.activated; 953 entry->activated = trial_state.activated;
957 entry->size = pickle.size(); 954 entry->size = pickle.size();
958 955
959 // TODO(lawrencewu): Modify base::Pickle to be able to write over a section in 956 // TODO(lawrencewu): Modify base::Pickle to be able to write over a section in
960 // memory, so we can avoid this memcpy. 957 // memory, so we can avoid this memcpy.
961 char* dst = reinterpret_cast<char*>(entry) + sizeof(FieldTrialEntry); 958 char* dst = reinterpret_cast<char*>(entry) + sizeof(FieldTrialEntry);
962 memcpy(dst, pickle.data(), pickle.size()); 959 memcpy(dst, pickle.data(), pickle.size());
963 960
964 allocator->MakeIterable(ref); 961 allocator->MakeIterable(ref);
965 field_trial->ref_ = ref; 962 field_trial->ref_ = ref;
966 } 963 }
967 964
968 // static 965 // static
969 void FieldTrialList::ActivateFieldTrialEntryWhileLocked( 966 void FieldTrialList::ActivateFieldTrialEntryWhileLocked(
970 FieldTrial* field_trial) { 967 FieldTrial* field_trial) {
971 SharedPersistentMemoryAllocator* allocator = 968 FieldTrialAllocator* allocator = global_->field_trial_allocator_.get();
972 global_->field_trial_allocator_.get();
973 969
974 // Check if we're in the child process and return early if so. 970 // Check if we're in the child process and return early if so.
975 if (allocator && allocator->IsReadonly()) 971 if (allocator && allocator->IsReadonly())
976 return; 972 return;
977 973
978 SharedPersistentMemoryAllocator::Reference ref = field_trial->ref_; 974 FieldTrial::FieldTrialRef ref = field_trial->ref_;
979 if (ref == SharedPersistentMemoryAllocator::kReferenceNull) { 975 if (ref == FieldTrialAllocator::kReferenceNull) {
980 // It's fine to do this even if the allocator hasn't been instantiated 976 // It's fine to do this even if the allocator hasn't been instantiated
981 // yet -- it'll just return early. 977 // yet -- it'll just return early.
982 AddToAllocatorWhileLocked(field_trial); 978 AddToAllocatorWhileLocked(field_trial);
983 } else { 979 } else {
984 // It's also okay to do this even though the callee doesn't have a lock -- 980 // It's also okay to do this even though the callee doesn't have a lock --
985 // the only thing that happens on a stale read here is a slight performance 981 // the only thing that happens on a stale read here is a slight performance
986 // hit from the child re-synchronizing activation state. 982 // hit from the child re-synchronizing activation state.
987 FieldTrialEntry* entry = 983 FieldTrialEntry* entry =
988 allocator->GetAsObject<FieldTrialEntry>(ref, kFieldTrialType); 984 allocator->GetAsObject<FieldTrialEntry>(ref, kFieldTrialType);
989 entry->activated = true; 985 entry->activated = true;
(...skipping 25 matching lines...) Expand all
1015 return; 1011 return;
1016 } 1012 }
1017 AutoLock auto_lock(global_->lock_); 1013 AutoLock auto_lock(global_->lock_);
1018 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); 1014 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name();
1019 trial->AddRef(); 1015 trial->AddRef();
1020 trial->SetTrialRegistered(); 1016 trial->SetTrialRegistered();
1021 global_->registered_[trial->trial_name()] = trial; 1017 global_->registered_[trial->trial_name()] = trial;
1022 } 1018 }
1023 1019
1024 } // namespace base 1020 } // namespace base
OLDNEW
« no previous file with comments | « base/metrics/field_trial.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698