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