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

Side by Side Diff: components/variations/variations_seed_simulator.cc

Issue 41623002: Simulate field trial assignments with new variations seed. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 6 years, 12 months 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/variations/variations_seed_simulator.h"
6
7 #include <map>
8
9 #include "base/metrics/field_trial.h"
10 #include "components/variations/processed_study.h"
11 #include "components/variations/proto/study.pb.h"
12 #include "components/variations/variations_associated_data.h"
13
14 namespace chrome_variations {
15
16 namespace {
17
18 // Fills in |current_state| with the current process' active field trials, as a
19 // map of trial names to group names.
20 void GetCurrentTrialState(std::map<std::string, std::string>* current_state) {
21 base::FieldTrial::ActiveGroups trial_groups;
22 base::FieldTrialList::GetActiveFieldTrialGroups(&trial_groups);
23 for (size_t i = 0; i < trial_groups.size(); ++i)
24 (*current_state)[trial_groups[i].trial_name] = trial_groups[i].group_name;
25 }
26
27 // Simulate group assignment for the specified study with PERMANENT consistency.
28 // Returns the experiment group that will be selected. Mirrors logic in
29 // VariationsSeedProcessor::CreateTrialFromStudy().
30 std::string SimulateGroupAssignment(
31 const base::FieldTrial::EntropyProvider& entropy_provider,
32 const ProcessedStudy& processed_study) {
33 const Study& study = *processed_study.study();
34 DCHECK_EQ(Study_Consistency_PERMANENT, study.consistency());
35
36 const double entropy_value =
37 entropy_provider.GetEntropyForTrial(study.name(),
38 study.randomization_seed());
39 scoped_refptr<base::FieldTrial> trial(
40 base::FieldTrial::CreateSimulatedFieldTrial(
41 study.name(), processed_study.total_probability(),
42 study.default_experiment_name(), entropy_value));
43
44 for (int i = 0; i < study.experiment_size(); ++i) {
45 const Study_Experiment& experiment = study.experiment(i);
46 if (!experiment.has_forcing_flag() &&
Mathieu 2013/12/30 15:21:37 what happens if the current version of the running
Alexei Svitkine (slow) 2014/01/06 19:22:40 You're right that it's currently not handled. And
mathp 2014/01/06 19:37:47 Sounds good. In the meantime it's possible this fu
Alexei Svitkine (slow) 2014/01/06 19:47:58 Right. Also, even though this CL adds the class, i
47 experiment.name() != study.default_experiment_name()) {
48 trial->AppendGroup(experiment.name(), experiment.probability_weight());
49 }
50 }
51 if (processed_study.is_expired())
52 trial->Disable();
53 return trial->group_name();
54 }
55
56 // Finds an experiment in |study| with name |experiment_name| and returns it,
57 // or NULL if it does not exist.
58 const Study_Experiment* FindExperiment(const Study& study,
59 const std::string& experiment_name) {
60 for (int i = 0; i < study.experiment_size(); ++i) {
61 if (study.experiment(i).name() == experiment_name)
62 return &study.experiment(i);
63 }
64 return NULL;
65 }
66
67 // Checks whether experiment params set for |experiment| on |study| are exactly
68 // equal to the params registered for the corresponding field trial in the
69 // current process.
70 bool VariationParamsAreEqual(const Study& study,
71 const Study_Experiment& experiment) {
72 std::map<std::string, std::string> params;
73 GetVariationParams(study.name(), &params);
74
75 if (static_cast<int>(params.size()) != experiment.param_size())
76 return false;
77
78 for (int i = 0; i < experiment.param_size(); ++i) {
79 std::map<std::string, std::string>::const_iterator it =
80 params.find(experiment.param(i).name());
81 if (it == params.end() || it->second != experiment.param(i).value())
82 return false;
83 }
84
85 return true;
86 }
87
88 } // namespace
89
90 VariationsSeedSimulator::VariationsSeedSimulator(
91 const base::FieldTrial::EntropyProvider& entropy_provider)
92 : entropy_provider_(entropy_provider) {
93 }
94
95 VariationsSeedSimulator::~VariationsSeedSimulator() {
96 }
97
98 int VariationsSeedSimulator::ComputeDifferences(
99 const std::vector<ProcessedStudy>& processed_studies) {
100 std::map<std::string, std::string> current_state;
101 GetCurrentTrialState(&current_state);
102 int group_change_count = 0;
103
104 for (size_t i = 0; i < processed_studies.size(); ++i) {
105 const Study& study = *processed_studies[i].study();
106 std::map<std::string, std::string>::const_iterator it =
107 current_state.find(study.name());
108
109 // Skip studies that aren't activated in the current state.
110 // TODO(asvitkine): This should be handled more intelligently. There are
111 // several cases that fall into this category:
112 // 1) There's an existing field trial with this name but it is not active.
113 // 2) There's an existing expired field trial with this name, which is
114 // also not considered as active.
115 // 3) This is a new study config that previously didn't exist.
116 // The above cases should be differentiated and handled explicitly.
117 if (it == current_state.end())
118 continue;
119
120 // Study exists in the current state, check whether its group will change.
121 const std::string& selected_group = it->second;
122 if (study.consistency() == Study_Consistency_PERMANENT) {
123 if (PermanentStudyGroupChanged(processed_studies[i], selected_group))
124 ++group_change_count;
125 } else if (study.consistency() == Study_Consistency_SESSION) {
126 if (SessionStudyGroupChanged(processed_studies[i], selected_group))
127 ++group_change_count;
128 }
129 }
130
131 // TODO(asvitkine): Handle removed studies (i.e. studies that existed in the
132 // old seed, but were removed). This will require tracking the set of studies
133 // that were created from the original seed.
134
135 return group_change_count;
136 }
137
138 bool VariationsSeedSimulator::PermanentStudyGroupChanged(
139 const ProcessedStudy& processed_study,
140 const std::string& selected_group) {
141 const Study& study = *processed_study.study();
142 DCHECK_EQ(Study_Consistency_PERMANENT, study.consistency());
143
144 const std::string simulated_group = SimulateGroupAssignment(entropy_provider_,
145 processed_study);
146 // TODO(asvitkine): Sometimes group names are changed without changing any
147 // behavior (e.g. if the behavior is control entirely via params). Support a
Mathieu 2013/12/30 15:21:37 *controlled
Alexei Svitkine (slow) 2014/01/06 19:22:40 Done.
148 // mechanism to bypass this check.
149 if (simulated_group != selected_group)
150 return true;
151
152 const Study_Experiment* experiment = FindExperiment(study, selected_group);
153 DCHECK(experiment);
154 return !VariationParamsAreEqual(study, *experiment);
155 }
156
157 bool VariationsSeedSimulator::SessionStudyGroupChanged(
158 const ProcessedStudy& processed_study,
159 const std::string& selected_group) {
160 const Study& study = *processed_study.study();
161 DCHECK_EQ(Study_Consistency_SESSION, study.consistency());
162
163 if (processed_study.is_expired() &&
164 selected_group != study.default_experiment_name()) {
Mathieu 2013/12/30 15:21:37 Tests are well commented but this isn't. Can you a
Alexei Svitkine (slow) 2014/01/06 19:22:40 Done.
165 return true;
166 }
167
168 const Study_Experiment* experiment = FindExperiment(study, selected_group);
169 if (!experiment)
170 return true;
171 if (experiment->probability_weight() == 0 &&
172 !experiment->has_forcing_flag()) {
173 return true;
174 }
175
176 // Current group exists in the study - check whether its params changed.
177 return !VariationParamsAreEqual(study, *experiment);
178 }
179
180 } // namespace chrome_variations
OLDNEW
« no previous file with comments | « components/variations/variations_seed_simulator.h ('k') | components/variations/variations_seed_simulator_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698