Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 76 if (!pickle->WriteString(string2)) | 76 if (!pickle->WriteString(string2)) |
| 77 return false; | 77 return false; |
| 78 return true; | 78 return true; |
| 79 } | 79 } |
| 80 | 80 |
| 81 // Writes out the field trial's contents (via trial_state) to the pickle. The | 81 // Writes out the field trial's contents (via trial_state) to the pickle. The |
| 82 // format of the pickle looks like: | 82 // format of the pickle looks like: |
| 83 // TrialName, GroupName, ParamKey1, ParamValue1, ParamKey2, ParamValue2, ... | 83 // TrialName, GroupName, ParamKey1, ParamValue1, ParamKey2, ParamValue2, ... |
| 84 // If there are no parameters, then it just ends at GroupName. | 84 // If there are no parameters, then it just ends at GroupName. |
| 85 bool PickleFieldTrial(const FieldTrial::State& trial_state, Pickle* pickle) { | 85 bool PickleFieldTrial(const FieldTrial::State& trial_state, Pickle* pickle) { |
| 86 if (!WriteStringPair(pickle, trial_state.trial_name, trial_state.group_name)) | 86 if (!WriteStringPair(pickle, *trial_state.trial_name, |
| 87 *trial_state.group_name)) { | |
| 87 return false; | 88 return false; |
| 89 } | |
| 88 | 90 |
| 89 // Get field trial params. | 91 // Get field trial params. |
| 90 std::map<std::string, std::string> params; | 92 std::map<std::string, std::string> params; |
| 91 FieldTrialParamAssociator::GetInstance()->GetFieldTrialParamsWithoutFallback( | 93 FieldTrialParamAssociator::GetInstance()->GetFieldTrialParamsWithoutFallback( |
| 92 trial_state.trial_name.as_string(), trial_state.group_name.as_string(), | 94 *trial_state.trial_name, *trial_state.group_name, ¶ms); |
| 93 ¶ms); | |
| 94 | 95 |
| 95 // Write params to pickle. | 96 // Write params to pickle. |
| 96 for (const auto& param : params) { | 97 for (const auto& param : params) { |
| 97 if (!WriteStringPair(pickle, param.first, param.second)) | 98 if (!WriteStringPair(pickle, param.first, param.second)) |
| 98 return false; | 99 return false; |
| 99 } | 100 } |
| 100 return true; | 101 return true; |
| 101 } | 102 } |
| 102 | 103 |
| 103 // Created a time value based on |year|, |month| and |day_of_month| parameters. | 104 // Created a time value based on |year|, |month| and |day_of_month| parameters. |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 139 // static_cast<FieldTrial::Probability>(100 * 0.57) == 56 | 140 // static_cast<FieldTrial::Probability>(100 * 0.57) == 56 |
| 140 // static_cast<FieldTrial::Probability>(100 * 0.58) == 57 | 141 // static_cast<FieldTrial::Probability>(100 * 0.58) == 57 |
| 141 // static_cast<FieldTrial::Probability>(100 * 0.59) == 59 | 142 // static_cast<FieldTrial::Probability>(100 * 0.59) == 59 |
| 142 const double kEpsilon = 1e-8; | 143 const double kEpsilon = 1e-8; |
| 143 const FieldTrial::Probability result = | 144 const FieldTrial::Probability result = |
| 144 static_cast<FieldTrial::Probability>(divisor * entropy_value + kEpsilon); | 145 static_cast<FieldTrial::Probability>(divisor * entropy_value + kEpsilon); |
| 145 // Ensure that adding the epsilon still results in a value < |divisor|. | 146 // Ensure that adding the epsilon still results in a value < |divisor|. |
| 146 return std::min(result, divisor - 1); | 147 return std::min(result, divisor - 1); |
| 147 } | 148 } |
| 148 | 149 |
| 150 // Separate type from FieldTrial::State so that it can use StringPieces. | |
| 151 struct FieldTrialStringEntry { | |
| 152 StringPiece trial_name; | |
| 153 StringPiece group_name; | |
| 154 bool activated; | |
| 155 }; | |
| 156 | |
| 149 // Parses the --force-fieldtrials string |trials_string| into |entries|. | 157 // Parses the --force-fieldtrials string |trials_string| into |entries|. |
| 150 // Returns true if the string was parsed correctly. On failure, the |entries| | 158 // Returns true if the string was parsed correctly. On failure, the |entries| |
| 151 // array may end up being partially filled. | 159 // array may end up being partially filled. |
| 152 bool ParseFieldTrialsString(const std::string& trials_string, | 160 bool ParseFieldTrialsString(const std::string& trials_string, |
| 153 std::vector<FieldTrial::State>* entries) { | 161 std::vector<FieldTrialStringEntry>* entries) { |
| 154 const StringPiece trials_string_piece(trials_string); | 162 const StringPiece trials_string_piece(trials_string); |
| 155 | 163 |
| 156 size_t next_item = 0; | 164 size_t next_item = 0; |
| 157 while (next_item < trials_string.length()) { | 165 while (next_item < trials_string.length()) { |
| 158 size_t name_end = trials_string.find(kPersistentStringSeparator, next_item); | 166 size_t name_end = trials_string.find(kPersistentStringSeparator, next_item); |
| 159 if (name_end == trials_string.npos || next_item == name_end) | 167 if (name_end == trials_string.npos || next_item == name_end) |
| 160 return false; | 168 return false; |
| 161 size_t group_name_end = | 169 size_t group_name_end = |
| 162 trials_string.find(kPersistentStringSeparator, name_end + 1); | 170 trials_string.find(kPersistentStringSeparator, name_end + 1); |
| 163 if (name_end + 1 == group_name_end) | 171 if (name_end + 1 == group_name_end) |
| 164 return false; | 172 return false; |
| 165 if (group_name_end == trials_string.npos) | 173 if (group_name_end == trials_string.npos) |
| 166 group_name_end = trials_string.length(); | 174 group_name_end = trials_string.length(); |
| 167 | 175 |
| 168 FieldTrial::State entry; | 176 FieldTrialStringEntry entry; |
| 169 // Verify if the trial should be activated or not. | 177 // Verify if the trial should be activated or not. |
| 170 if (trials_string[next_item] == kActivationMarker) { | 178 if (trials_string[next_item] == kActivationMarker) { |
| 171 // Name cannot be only the indicator. | 179 // Name cannot be only the indicator. |
| 172 if (name_end - next_item == 1) | 180 if (name_end - next_item == 1) |
| 173 return false; | 181 return false; |
| 174 next_item++; | 182 next_item++; |
| 175 entry.activated = true; | 183 entry.activated = true; |
| 176 } | 184 } |
| 177 entry.trial_name = | 185 entry.trial_name = |
| 178 trials_string_piece.substr(next_item, name_end - next_item); | 186 trials_string_piece.substr(next_item, name_end - next_item); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 235 bool FieldTrial::enable_benchmarking_ = false; | 243 bool FieldTrial::enable_benchmarking_ = false; |
| 236 | 244 |
| 237 int FieldTrialList::kNoExpirationYear = 0; | 245 int FieldTrialList::kNoExpirationYear = 0; |
| 238 | 246 |
| 239 //------------------------------------------------------------------------------ | 247 //------------------------------------------------------------------------------ |
| 240 // FieldTrial methods and members. | 248 // FieldTrial methods and members. |
| 241 | 249 |
| 242 FieldTrial::EntropyProvider::~EntropyProvider() { | 250 FieldTrial::EntropyProvider::~EntropyProvider() { |
| 243 } | 251 } |
| 244 | 252 |
| 245 FieldTrial::State::State() : activated(false) {} | 253 FieldTrial::State::State() |
| 254 : trial_name(nullptr), group_name(nullptr), activated(false) {} | |
|
brucedawson
2017/01/24 00:44:14
See comment in header file and consider removing t
Alexei Svitkine (slow)
2017/01/24 16:40:19
Done.
| |
| 246 | 255 |
| 247 FieldTrial::State::State(const State& other) = default; | 256 FieldTrial::State::State(const State& other) = default; |
| 248 | 257 |
| 249 FieldTrial::State::~State() {} | 258 FieldTrial::State::~State() {} |
| 250 | 259 |
| 251 bool FieldTrial::FieldTrialEntry::GetTrialAndGroupName( | 260 bool FieldTrial::FieldTrialEntry::GetTrialAndGroupName( |
| 252 StringPiece* trial_name, | 261 StringPiece* trial_name, |
| 253 StringPiece* group_name) const { | 262 StringPiece* group_name) const { |
| 254 PickleIterator iter = GetPickleIterator(); | 263 PickleIterator iter = GetPickleIterator(); |
| 255 return ReadStringPair(&iter, trial_name, group_name); | 264 return ReadStringPair(&iter, trial_name, group_name); |
| (...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 449 DCHECK_NE(group_, kNotFinalized); | 458 DCHECK_NE(group_, kNotFinalized); |
| 450 active_group->trial_name = trial_name_; | 459 active_group->trial_name = trial_name_; |
| 451 active_group->group_name = group_name_; | 460 active_group->group_name = group_name_; |
| 452 return true; | 461 return true; |
| 453 } | 462 } |
| 454 | 463 |
| 455 bool FieldTrial::GetState(State* field_trial_state) { | 464 bool FieldTrial::GetState(State* field_trial_state) { |
| 456 if (!enable_field_trial_) | 465 if (!enable_field_trial_) |
| 457 return false; | 466 return false; |
| 458 FinalizeGroupChoice(); | 467 FinalizeGroupChoice(); |
| 459 field_trial_state->trial_name = trial_name_; | 468 field_trial_state->trial_name = &trial_name_; |
| 460 field_trial_state->group_name = group_name_; | 469 field_trial_state->group_name = &group_name_; |
| 461 field_trial_state->activated = group_reported_; | 470 field_trial_state->activated = group_reported_; |
| 462 return true; | 471 return true; |
| 463 } | 472 } |
| 464 | 473 |
| 465 bool FieldTrial::GetStateWhileLocked(State* field_trial_state) { | 474 bool FieldTrial::GetStateWhileLocked(State* field_trial_state) { |
| 466 if (!enable_field_trial_) | 475 if (!enable_field_trial_) |
| 467 return false; | 476 return false; |
| 468 FinalizeGroupChoiceImpl(true); | 477 FinalizeGroupChoiceImpl(true); |
| 469 field_trial_state->trial_name = trial_name_; | 478 field_trial_state->trial_name = &trial_name_; |
| 470 field_trial_state->group_name = group_name_; | 479 field_trial_state->group_name = &group_name_; |
| 471 field_trial_state->activated = group_reported_; | 480 field_trial_state->activated = group_reported_; |
| 472 return true; | 481 return true; |
| 473 } | 482 } |
| 474 | 483 |
| 475 //------------------------------------------------------------------------------ | 484 //------------------------------------------------------------------------------ |
| 476 // FieldTrialList methods and members. | 485 // FieldTrialList methods and members. |
| 477 | 486 |
| 478 // static | 487 // static |
| 479 FieldTrialList* FieldTrialList::global_ = NULL; | 488 FieldTrialList* FieldTrialList::global_ = NULL; |
| 480 | 489 |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 648 void FieldTrialList::AllStatesToString(std::string* output) { | 657 void FieldTrialList::AllStatesToString(std::string* output) { |
| 649 if (!global_) | 658 if (!global_) |
| 650 return; | 659 return; |
| 651 AutoLock auto_lock(global_->lock_); | 660 AutoLock auto_lock(global_->lock_); |
| 652 | 661 |
| 653 for (const auto& registered : global_->registered_) { | 662 for (const auto& registered : global_->registered_) { |
| 654 FieldTrial::State trial; | 663 FieldTrial::State trial; |
| 655 if (!registered.second->GetStateWhileLocked(&trial)) | 664 if (!registered.second->GetStateWhileLocked(&trial)) |
| 656 continue; | 665 continue; |
| 657 DCHECK_EQ(std::string::npos, | 666 DCHECK_EQ(std::string::npos, |
| 658 trial.trial_name.find(kPersistentStringSeparator)); | 667 trial.trial_name->find(kPersistentStringSeparator)); |
| 659 DCHECK_EQ(std::string::npos, | 668 DCHECK_EQ(std::string::npos, |
| 660 trial.group_name.find(kPersistentStringSeparator)); | 669 trial.group_name->find(kPersistentStringSeparator)); |
| 661 if (trial.activated) | 670 if (trial.activated) |
| 662 output->append(1, kActivationMarker); | 671 output->append(1, kActivationMarker); |
| 663 trial.trial_name.AppendToString(output); | 672 output->append(*trial.trial_name); |
|
brucedawson
2017/01/24 00:44:14
This reads much cleaner, as a minor side effect.
Alexei Svitkine (slow)
2017/01/24 16:40:19
Acknowledged.
| |
| 664 output->append(1, kPersistentStringSeparator); | 673 output->append(1, kPersistentStringSeparator); |
| 665 trial.group_name.AppendToString(output); | 674 output->append(*trial.group_name); |
| 666 output->append(1, kPersistentStringSeparator); | 675 output->append(1, kPersistentStringSeparator); |
| 667 } | 676 } |
| 668 } | 677 } |
| 669 | 678 |
| 670 // static | 679 // static |
| 671 void FieldTrialList::GetActiveFieldTrialGroups( | 680 void FieldTrialList::GetActiveFieldTrialGroups( |
| 672 FieldTrial::ActiveGroups* active_groups) { | 681 FieldTrial::ActiveGroups* active_groups) { |
| 673 DCHECK(active_groups->empty()); | 682 DCHECK(active_groups->empty()); |
| 674 if (!global_) | 683 if (!global_) |
| 675 return; | 684 return; |
| 676 AutoLock auto_lock(global_->lock_); | 685 AutoLock auto_lock(global_->lock_); |
| 677 | 686 |
| 678 for (RegistrationMap::iterator it = global_->registered_.begin(); | 687 for (RegistrationMap::iterator it = global_->registered_.begin(); |
| 679 it != global_->registered_.end(); ++it) { | 688 it != global_->registered_.end(); ++it) { |
| 680 FieldTrial::ActiveGroup active_group; | 689 FieldTrial::ActiveGroup active_group; |
| 681 if (it->second->GetActiveGroup(&active_group)) | 690 if (it->second->GetActiveGroup(&active_group)) |
| 682 active_groups->push_back(active_group); | 691 active_groups->push_back(active_group); |
| 683 } | 692 } |
| 684 } | 693 } |
| 685 | 694 |
| 686 // static | 695 // static |
| 687 void FieldTrialList::GetActiveFieldTrialGroupsFromString( | 696 void FieldTrialList::GetActiveFieldTrialGroupsFromString( |
| 688 const std::string& trials_string, | 697 const std::string& trials_string, |
| 689 FieldTrial::ActiveGroups* active_groups) { | 698 FieldTrial::ActiveGroups* active_groups) { |
| 690 std::vector<FieldTrial::State> entries; | 699 std::vector<FieldTrialStringEntry> entries; |
| 691 if (!ParseFieldTrialsString(trials_string, &entries)) | 700 if (!ParseFieldTrialsString(trials_string, &entries)) |
| 692 return; | 701 return; |
| 693 | 702 |
| 694 for (const auto& entry : entries) { | 703 for (const auto& entry : entries) { |
| 695 if (entry.activated) { | 704 if (entry.activated) { |
| 696 FieldTrial::ActiveGroup group; | 705 FieldTrial::ActiveGroup group; |
| 697 group.trial_name = entry.trial_name.as_string(); | 706 group.trial_name = entry.trial_name.as_string(); |
| 698 group.group_name = entry.group_name.as_string(); | 707 group.group_name = entry.group_name.as_string(); |
| 699 active_groups->push_back(group); | 708 active_groups->push_back(group); |
| 700 } | 709 } |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 732 } | 741 } |
| 733 | 742 |
| 734 // static | 743 // static |
| 735 bool FieldTrialList::CreateTrialsFromString( | 744 bool FieldTrialList::CreateTrialsFromString( |
| 736 const std::string& trials_string, | 745 const std::string& trials_string, |
| 737 const std::set<std::string>& ignored_trial_names) { | 746 const std::set<std::string>& ignored_trial_names) { |
| 738 DCHECK(global_); | 747 DCHECK(global_); |
| 739 if (trials_string.empty() || !global_) | 748 if (trials_string.empty() || !global_) |
| 740 return true; | 749 return true; |
| 741 | 750 |
| 742 std::vector<FieldTrial::State> entries; | 751 std::vector<FieldTrialStringEntry> entries; |
| 743 if (!ParseFieldTrialsString(trials_string, &entries)) | 752 if (!ParseFieldTrialsString(trials_string, &entries)) |
| 744 return false; | 753 return false; |
| 745 | 754 |
| 746 for (const auto& entry : entries) { | 755 for (const auto& entry : entries) { |
| 747 const std::string trial_name = entry.trial_name.as_string(); | 756 const std::string trial_name = entry.trial_name.as_string(); |
| 748 const std::string group_name = entry.group_name.as_string(); | 757 const std::string group_name = entry.group_name.as_string(); |
| 749 | 758 |
| 750 if (ContainsKey(ignored_trial_names, trial_name)) | 759 if (ContainsKey(ignored_trial_names, trial_name)) |
| 751 continue; | 760 continue; |
| 752 | 761 |
| (...skipping 590 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1343 return; | 1352 return; |
| 1344 } | 1353 } |
| 1345 AutoLock auto_lock(global_->lock_); | 1354 AutoLock auto_lock(global_->lock_); |
| 1346 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); | 1355 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); |
| 1347 trial->AddRef(); | 1356 trial->AddRef(); |
| 1348 trial->SetTrialRegistered(); | 1357 trial->SetTrialRegistered(); |
| 1349 global_->registered_[trial->trial_name()] = trial; | 1358 global_->registered_[trial->trial_name()] = trial; |
| 1350 } | 1359 } |
| 1351 | 1360 |
| 1352 } // namespace base | 1361 } // namespace base |
| OLD | NEW |