prerender_field_trial.cc revision 90dce4d38c5ff5333bea97d859d4e484e27edf0c
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
3// found in the LICENSE file.
4
5#include "chrome/browser/prerender/prerender_field_trial.h"
6
7#include "base/command_line.h"
8#include "base/logging.h"
9#include "base/metrics/field_trial.h"
10#include "base/metrics/histogram.h"
11#include "base/prefs/pref_service.h"
12#include "chrome/browser/metrics/metrics_service.h"
13#include "chrome/browser/predictors/autocomplete_action_predictor.h"
14#include "chrome/browser/prerender/prerender_manager.h"
15#include "chrome/browser/profiles/profile.h"
16#include "chrome/common/chrome_switches.h"
17#include "chrome/common/chrome_version_info.h"
18
19using base::FieldTrial;
20using base::FieldTrialList;
21
22namespace prerender {
23
24namespace {
25
26const char kOmniboxTrialName[] = "PrerenderFromOmnibox";
27int g_omnibox_trial_default_group_number = kint32min;
28
29const char kLocalPredictorTrialName[] = "PrerenderLocalPredictor";
30const char kLocalPredictorEnabledGroup[] = "Enabled";
31const char kLocalPredictorDisabledGroup[] = "Disabled";
32
33const char kLoggedInPredictorTrialName[] = "PrerenderLoggedInPredictor";
34const char kLoggedInPredictorEnabledGroup[] = "Enabled";
35const char kLoggedInPredictorDisabledGroup[] = "Disabled";
36
37const char kSideEffectFreeWhitelistTrialName[] = "SideEffectFreeWhitelist";
38const char kSideEffectFreeWhitelistEnabledGroup[] = "Enabled";
39const char kSideEffectFreeWhitelistDisabledGroup[] = "Disabled";
40
41void SetupPrefetchFieldTrial() {
42  chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel();
43  if (channel == chrome::VersionInfo::CHANNEL_STABLE ||
44      channel == chrome::VersionInfo::CHANNEL_BETA) {
45    return;
46  }
47
48  const FieldTrial::Probability divisor = 1000;
49  const FieldTrial::Probability prefetch_probability = 500;
50  scoped_refptr<FieldTrial> trial(
51      FieldTrialList::FactoryGetFieldTrial(
52          "Prefetch", divisor, "ContentPrefetchPrefetchOff",
53          2013, 12, 31, NULL));
54  const int kPrefetchOnGroup = trial->AppendGroup("ContentPrefetchPrefetchOn",
55                                                  prefetch_probability);
56  PrerenderManager::SetIsPrefetchEnabled(trial->group() == kPrefetchOnGroup);
57}
58
59void SetupPrerenderFieldTrial() {
60  const FieldTrial::Probability divisor = 1000;
61
62  FieldTrial::Probability control_probability;
63  FieldTrial::Probability experiment_multi_prerender_probability;
64  FieldTrial::Probability experiment_15min_ttl_probability;
65  FieldTrial::Probability experiment_no_use_probability;
66
67  chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel();
68  if (channel == chrome::VersionInfo::CHANNEL_STABLE ||
69      channel == chrome::VersionInfo::CHANNEL_BETA) {
70    // Use very conservatives and stable settings in beta and stable.
71    const FieldTrial::Probability release_prerender_enabled_probability = 980;
72    const FieldTrial::Probability release_control_probability = 10;
73    const FieldTrial::Probability
74        release_experiment_multi_prerender_probability = 0;
75    const FieldTrial::Probability release_experiment_15min_ttl_probability = 10;
76    const FieldTrial::Probability release_experiment_no_use_probability = 0;
77    COMPILE_ASSERT(
78        release_prerender_enabled_probability + release_control_probability +
79        release_experiment_multi_prerender_probability +
80        release_experiment_15min_ttl_probability +
81        release_experiment_no_use_probability == divisor,
82        release_experiment_probabilities_must_equal_divisor);
83
84    control_probability = release_control_probability;
85    experiment_multi_prerender_probability =
86        release_experiment_multi_prerender_probability;
87    experiment_15min_ttl_probability = release_experiment_15min_ttl_probability;
88    experiment_no_use_probability = release_experiment_no_use_probability;
89  } else {
90    // In testing channels, use more experiments and a larger control group to
91    // improve quality of data.
92    const FieldTrial::Probability dev_prerender_enabled_probability = 250;
93    const FieldTrial::Probability dev_control_probability = 250;
94    const FieldTrial::Probability
95        dev_experiment_multi_prerender_probability = 250;
96    const FieldTrial::Probability dev_experiment_15min_ttl_probability = 125;
97    const FieldTrial::Probability dev_experiment_no_use_probability = 125;
98    COMPILE_ASSERT(dev_prerender_enabled_probability + dev_control_probability +
99                   dev_experiment_multi_prerender_probability +
100                   dev_experiment_15min_ttl_probability +
101                   dev_experiment_no_use_probability == divisor,
102                   dev_experiment_probabilities_must_equal_divisor);
103
104    control_probability = dev_control_probability;
105    experiment_multi_prerender_probability =
106        dev_experiment_multi_prerender_probability;
107    experiment_15min_ttl_probability = dev_experiment_15min_ttl_probability;
108    experiment_no_use_probability = dev_experiment_no_use_probability;
109  }
110
111  int prerender_enabled_group = -1;
112  scoped_refptr<FieldTrial> trial(
113      FieldTrialList::FactoryGetFieldTrial(
114          "Prerender", divisor, "PrerenderEnabled",
115          2013, 12, 31, &prerender_enabled_group));
116  const int control_group =
117      trial->AppendGroup("PrerenderControl",
118                         control_probability);
119  const int experiment_multi_prerender_group =
120      trial->AppendGroup("PrerenderMulti",
121                         experiment_multi_prerender_probability);
122  const int experiment_15_min_TTL_group =
123      trial->AppendGroup("Prerender15minTTL",
124                         experiment_15min_ttl_probability);
125  const int experiment_no_use_group =
126      trial->AppendGroup("PrerenderNoUse",
127                         experiment_no_use_probability);
128
129  const int trial_group = trial->group();
130  if (trial_group == prerender_enabled_group) {
131    PrerenderManager::SetMode(
132        PrerenderManager::PRERENDER_MODE_EXPERIMENT_PRERENDER_GROUP);
133  } else if (trial_group == control_group) {
134    PrerenderManager::SetMode(
135        PrerenderManager::PRERENDER_MODE_EXPERIMENT_CONTROL_GROUP);
136  } else if (trial_group == experiment_multi_prerender_group) {
137    PrerenderManager::SetMode(
138        PrerenderManager::PRERENDER_MODE_EXPERIMENT_MULTI_PRERENDER_GROUP);
139  } else if (trial_group == experiment_15_min_TTL_group) {
140    PrerenderManager::SetMode(
141        PrerenderManager::PRERENDER_MODE_EXPERIMENT_15MIN_TTL_GROUP);
142  } else if (trial_group == experiment_no_use_group) {
143    PrerenderManager::SetMode(
144        PrerenderManager::PRERENDER_MODE_EXPERIMENT_NO_USE_GROUP);
145  } else {
146    NOTREACHED();
147  }
148}
149
150}  // end namespace
151
152void ConfigureOmniboxPrerender();
153void ConfigureLocalPredictor();
154void ConfigureLoggedInPredictor();
155void ConfigureSideEffectFreeWhitelist();
156
157void ConfigurePrefetchAndPrerender(const CommandLine& command_line) {
158  enum PrerenderOption {
159    PRERENDER_OPTION_AUTO,
160    PRERENDER_OPTION_DISABLED,
161    PRERENDER_OPTION_ENABLED,
162    PRERENDER_OPTION_PREFETCH_ONLY,
163  };
164
165  PrerenderOption prerender_option = PRERENDER_OPTION_AUTO;
166  if (command_line.HasSwitch(switches::kPrerenderMode)) {
167    const std::string switch_value =
168        command_line.GetSwitchValueASCII(switches::kPrerenderMode);
169
170    if (switch_value == switches::kPrerenderModeSwitchValueAuto) {
171      prerender_option = PRERENDER_OPTION_AUTO;
172    } else if (switch_value == switches::kPrerenderModeSwitchValueDisabled) {
173      prerender_option = PRERENDER_OPTION_DISABLED;
174    } else if (switch_value.empty() ||
175               switch_value == switches::kPrerenderModeSwitchValueEnabled) {
176      // The empty string means the option was provided with no value, and that
177      // means enable.
178      prerender_option = PRERENDER_OPTION_ENABLED;
179    } else if (switch_value ==
180               switches::kPrerenderModeSwitchValuePrefetchOnly) {
181      prerender_option = PRERENDER_OPTION_PREFETCH_ONLY;
182    } else {
183      prerender_option = PRERENDER_OPTION_DISABLED;
184      LOG(ERROR) << "Invalid --prerender option received on command line: "
185                 << switch_value;
186      LOG(ERROR) << "Disabling prerendering!";
187    }
188  }
189
190  switch (prerender_option) {
191    case PRERENDER_OPTION_AUTO:
192      SetupPrefetchFieldTrial();
193      SetupPrerenderFieldTrial();
194      break;
195    case PRERENDER_OPTION_DISABLED:
196      PrerenderManager::SetIsPrefetchEnabled(false);
197      PrerenderManager::SetMode(PrerenderManager::PRERENDER_MODE_DISABLED);
198      break;
199    case PRERENDER_OPTION_ENABLED:
200      PrerenderManager::SetIsPrefetchEnabled(true);
201      PrerenderManager::SetMode(PrerenderManager::PRERENDER_MODE_ENABLED);
202      break;
203    case PRERENDER_OPTION_PREFETCH_ONLY:
204      PrerenderManager::SetIsPrefetchEnabled(true);
205      PrerenderManager::SetMode(PrerenderManager::PRERENDER_MODE_DISABLED);
206      break;
207    default:
208      NOTREACHED();
209  }
210
211  ConfigureOmniboxPrerender();
212  ConfigureLocalPredictor();
213  ConfigureLoggedInPredictor();
214  ConfigureSideEffectFreeWhitelist();
215}
216
217void ConfigureOmniboxPrerender() {
218  // Field trial to see if we're enabled.
219  const FieldTrial::Probability kDivisor = 100;
220
221  FieldTrial::Probability kDisabledProbability = 10;
222  chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel();
223  if (channel == chrome::VersionInfo::CHANNEL_STABLE ||
224      channel == chrome::VersionInfo::CHANNEL_BETA) {
225    kDisabledProbability = 1;
226  }
227  scoped_refptr<FieldTrial> omnibox_prerender_trial(
228      FieldTrialList::FactoryGetFieldTrial(
229          kOmniboxTrialName, kDivisor, "OmniboxPrerenderEnabled",
230          2013, 12, 31, &g_omnibox_trial_default_group_number));
231  omnibox_prerender_trial->AppendGroup("OmniboxPrerenderDisabled",
232                                       kDisabledProbability);
233}
234
235void ConfigureLocalPredictor() {
236  chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel();
237  if (channel == chrome::VersionInfo::CHANNEL_STABLE ||
238      channel == chrome::VersionInfo::CHANNEL_BETA) {
239    return;
240  }
241  scoped_refptr<FieldTrial> local_predictor_trial(
242      FieldTrialList::FactoryGetFieldTrial(
243          kLocalPredictorTrialName, 100,
244          kLocalPredictorDisabledGroup, 2013, 12, 31, NULL));
245  local_predictor_trial->AppendGroup(kLocalPredictorEnabledGroup, 100);
246}
247
248void ConfigureLoggedInPredictor() {
249  chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel();
250  if (channel == chrome::VersionInfo::CHANNEL_STABLE ||
251      channel == chrome::VersionInfo::CHANNEL_BETA) {
252    return;
253  }
254  scoped_refptr<FieldTrial> logged_in_predictor_trial(
255      FieldTrialList::FactoryGetFieldTrial(
256          kLoggedInPredictorTrialName, 100,
257          kLoggedInPredictorDisabledGroup, 2013, 12, 31, NULL));
258  logged_in_predictor_trial->AppendGroup(kLoggedInPredictorEnabledGroup, 100);
259}
260
261void ConfigureSideEffectFreeWhitelist() {
262  scoped_refptr<FieldTrial> side_effect_free_whitelist_trial(
263      FieldTrialList::FactoryGetFieldTrial(
264          kSideEffectFreeWhitelistTrialName, 100,
265          kSideEffectFreeWhitelistDisabledGroup, 2013, 12, 31, NULL));
266  chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel();
267  if (channel == chrome::VersionInfo::CHANNEL_STABLE ||
268      channel == chrome::VersionInfo::CHANNEL_BETA) {
269    return;
270  }
271  side_effect_free_whitelist_trial->AppendGroup(
272      kSideEffectFreeWhitelistEnabledGroup, 100);
273}
274
275bool IsOmniboxEnabled(Profile* profile) {
276  if (!profile)
277    return false;
278
279  if (!PrerenderManager::IsPrerenderingPossible())
280    return false;
281
282  // Override any field trial groups if the user has set a command line flag.
283  if (CommandLine::ForCurrentProcess()->HasSwitch(
284      switches::kPrerenderFromOmnibox)) {
285    const std::string switch_value =
286        CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
287            switches::kPrerenderFromOmnibox);
288
289    if (switch_value == switches::kPrerenderFromOmniboxSwitchValueEnabled)
290      return true;
291
292    if (switch_value == switches::kPrerenderFromOmniboxSwitchValueDisabled)
293      return false;
294
295    DCHECK(switch_value == switches::kPrerenderFromOmniboxSwitchValueAuto);
296  }
297
298  const int group = FieldTrialList::FindValue(kOmniboxTrialName);
299  return group == FieldTrial::kNotFinalized ||
300         group == g_omnibox_trial_default_group_number;
301}
302
303bool IsLocalPredictorEnabled() {
304#if defined(OS_ANDROID) || defined(OS_IOS)
305  return false;
306#endif
307  if (CommandLine::ForCurrentProcess()->HasSwitch(
308          switches::kDisablePrerenderLocalPredictor)) {
309    return false;
310  }
311  return base::FieldTrialList::FindFullName(kLocalPredictorTrialName) ==
312      kLocalPredictorEnabledGroup;
313}
314
315bool IsLoggedInPredictorEnabled() {
316  return base::FieldTrialList::FindFullName(kLoggedInPredictorTrialName) ==
317      kLoggedInPredictorEnabledGroup;
318}
319
320bool IsSideEffectFreeWhitelistEnabled() {
321  return base::FieldTrialList::FindFullName(kSideEffectFreeWhitelistTrialName)
322      == kSideEffectFreeWhitelistEnabledGroup;
323}
324
325}  // namespace prerender
326