1// Copyright 2014 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/predictors/resource_prefetch_common.h"
6
7#include "base/command_line.h"
8#include "base/metrics/field_trial.h"
9#include "base/prefs/pref_service.h"
10#include "chrome/browser/profiles/profile.h"
11#include "chrome/common/chrome_switches.h"
12#include "chrome/common/pref_names.h"
13#include "content/public/browser/render_process_host.h"
14#include "content/public/browser/render_view_host.h"
15#include "content/public/browser/web_contents.h"
16
17namespace predictors {
18
19const char kSpeculativePrefetchingTrialName[] =
20    "SpeculativeResourcePrefetching";
21
22bool IsSpeculativeResourcePrefetchingEnabled(
23    Profile* profile,
24    ResourcePrefetchPredictorConfig* config) {
25  DCHECK(config);
26
27  // Off the record - disabled.
28  if (!profile || profile->IsOffTheRecord())
29    return false;
30
31  // If the user has explicitly disabled "predictive actions" - disabled.
32  if (!profile->GetPrefs() ||
33      !profile->GetPrefs()->GetBoolean(prefs::kNetworkPredictionEnabled)) {
34    return false;
35  }
36
37  // The config has the default params already set. The command line with just
38  // enable them with the default params.
39  if (CommandLine::ForCurrentProcess()->HasSwitch(
40          switches::kSpeculativeResourcePrefetching)) {
41    const std::string value =
42        CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
43            switches::kSpeculativeResourcePrefetching);
44
45    if (value == switches::kSpeculativeResourcePrefetchingDisabled) {
46      return false;
47    } else if (value == switches::kSpeculativeResourcePrefetchingLearning) {
48      config->mode |= ResourcePrefetchPredictorConfig::URL_LEARNING;
49      config->mode |= ResourcePrefetchPredictorConfig::HOST_LEARNING;
50      return true;
51    } else if (value == switches::kSpeculativeResourcePrefetchingEnabled) {
52      config->mode |= ResourcePrefetchPredictorConfig::URL_LEARNING;
53      config->mode |= ResourcePrefetchPredictorConfig::HOST_LEARNING;
54      config->mode |= ResourcePrefetchPredictorConfig::URL_PREFETCHING;
55      config->mode |= ResourcePrefetchPredictorConfig::HOST_PRFETCHING;
56      return true;
57    }
58  }
59
60  std::string trial = base::FieldTrialList::FindFullName(
61      kSpeculativePrefetchingTrialName);
62
63  if (trial == "LearningHost") {
64    config->mode |= ResourcePrefetchPredictorConfig::HOST_LEARNING;
65    return true;
66  } else if (trial == "LearningURL") {
67    config->mode |= ResourcePrefetchPredictorConfig::URL_LEARNING;
68    return true;
69  } else if (trial == "Learning") {
70    config->mode |= ResourcePrefetchPredictorConfig::URL_LEARNING;
71    config->mode |= ResourcePrefetchPredictorConfig::HOST_LEARNING;
72    return true;
73  } else if (trial == "PrefetchingHost") {
74    config->mode |= ResourcePrefetchPredictorConfig::HOST_LEARNING;
75    config->mode |= ResourcePrefetchPredictorConfig::HOST_PRFETCHING;
76    return true;
77  } else if (trial == "PrefetchingURL") {
78    config->mode |= ResourcePrefetchPredictorConfig::URL_LEARNING;
79    config->mode |= ResourcePrefetchPredictorConfig::URL_PREFETCHING;
80    return true;
81  } else if (trial == "Prefetching") {
82    config->mode |= ResourcePrefetchPredictorConfig::URL_LEARNING;
83    config->mode |= ResourcePrefetchPredictorConfig::HOST_LEARNING;
84    config->mode |= ResourcePrefetchPredictorConfig::URL_PREFETCHING;
85    config->mode |= ResourcePrefetchPredictorConfig::HOST_PRFETCHING;
86    return true;
87  } else if (trial == "PrefetchingLowConfidence") {
88    config->mode |= ResourcePrefetchPredictorConfig::URL_LEARNING;
89    config->mode |= ResourcePrefetchPredictorConfig::HOST_LEARNING;
90    config->mode |= ResourcePrefetchPredictorConfig::URL_PREFETCHING;
91    config->mode |= ResourcePrefetchPredictorConfig::HOST_PRFETCHING;
92
93    config->min_url_visit_count = 1;
94    config->min_resource_confidence_to_trigger_prefetch = 0.5f;
95    config->min_resource_hits_to_trigger_prefetch = 1;
96    return true;
97  } else if (trial == "PrefetchingHighConfidence") {
98    config->mode |= ResourcePrefetchPredictorConfig::URL_LEARNING;
99    config->mode |= ResourcePrefetchPredictorConfig::HOST_LEARNING;
100    config->mode |= ResourcePrefetchPredictorConfig::URL_PREFETCHING;
101    config->mode |= ResourcePrefetchPredictorConfig::HOST_PRFETCHING;
102
103    config->min_url_visit_count = 3;
104    config->min_resource_confidence_to_trigger_prefetch = 0.9f;
105    config->min_resource_hits_to_trigger_prefetch = 3;
106    return true;
107  } else if (trial == "PrefetchingMoreResources") {
108    config->mode |= ResourcePrefetchPredictorConfig::URL_LEARNING;
109    config->mode |= ResourcePrefetchPredictorConfig::HOST_LEARNING;
110    config->mode |= ResourcePrefetchPredictorConfig::URL_PREFETCHING;
111    config->mode |= ResourcePrefetchPredictorConfig::HOST_PRFETCHING;
112
113    config->max_resources_per_entry = 100;
114    return true;
115  } else if (trial == "LearningSmallDB") {
116    config->mode |= ResourcePrefetchPredictorConfig::URL_LEARNING;
117    config->mode |= ResourcePrefetchPredictorConfig::HOST_LEARNING;
118
119    config->max_urls_to_track = 200;
120    config->max_hosts_to_track = 100;
121    return true;
122  } else if (trial == "PrefetchingSmallDB") {
123    config->mode |= ResourcePrefetchPredictorConfig::URL_LEARNING;
124    config->mode |= ResourcePrefetchPredictorConfig::HOST_LEARNING;
125    config->mode |= ResourcePrefetchPredictorConfig::URL_PREFETCHING;
126    config->mode |= ResourcePrefetchPredictorConfig::HOST_PRFETCHING;
127
128    config->max_urls_to_track = 200;
129    config->max_hosts_to_track = 100;
130    return true;
131  } else if (trial == "PrefetchingSmallDBLowConfidence") {
132    config->mode |= ResourcePrefetchPredictorConfig::URL_LEARNING;
133    config->mode |= ResourcePrefetchPredictorConfig::HOST_LEARNING;
134    config->mode |= ResourcePrefetchPredictorConfig::URL_PREFETCHING;
135    config->mode |= ResourcePrefetchPredictorConfig::HOST_PRFETCHING;
136
137    config->max_urls_to_track = 200;
138    config->max_hosts_to_track = 100;
139    config->min_url_visit_count = 1;
140    config->min_resource_confidence_to_trigger_prefetch = 0.5f;
141    config->min_resource_hits_to_trigger_prefetch = 1;
142    return true;
143  } else if (trial == "PrefetchingSmallDBHighConfidence") {
144    config->mode |= ResourcePrefetchPredictorConfig::URL_LEARNING;
145    config->mode |= ResourcePrefetchPredictorConfig::HOST_LEARNING;
146    config->mode |= ResourcePrefetchPredictorConfig::URL_PREFETCHING;
147    config->mode |= ResourcePrefetchPredictorConfig::HOST_PRFETCHING;
148
149    config->max_urls_to_track = 200;
150    config->max_hosts_to_track = 100;
151    config->min_url_visit_count = 3;
152    config->min_resource_confidence_to_trigger_prefetch = 0.9f;
153    config->min_resource_hits_to_trigger_prefetch = 3;
154    return true;
155  }
156
157  return false;
158}
159
160NavigationID::NavigationID()
161    : render_process_id(-1),
162      render_frame_id(-1) {
163}
164
165NavigationID::NavigationID(const NavigationID& other)
166    : render_process_id(other.render_process_id),
167      render_frame_id(other.render_frame_id),
168      main_frame_url(other.main_frame_url),
169      creation_time(other.creation_time) {
170}
171
172NavigationID::NavigationID(content::WebContents* web_contents)
173    : render_process_id(web_contents->GetRenderProcessHost()->GetID()),
174      render_frame_id(web_contents->GetRenderViewHost()->GetRoutingID()),
175      main_frame_url(web_contents->GetURL()) {
176}
177
178bool NavigationID::is_valid() const {
179  return render_process_id != -1 && render_frame_id != -1 &&
180      !main_frame_url.is_empty();
181}
182
183bool NavigationID::operator<(const NavigationID& rhs) const {
184  DCHECK(is_valid() && rhs.is_valid());
185  if (render_process_id != rhs.render_process_id)
186    return render_process_id < rhs.render_process_id;
187  else if (render_frame_id != rhs.render_frame_id)
188    return render_frame_id < rhs.render_frame_id;
189  else
190    return main_frame_url < rhs.main_frame_url;
191}
192
193bool NavigationID::operator==(const NavigationID& rhs) const {
194  DCHECK(is_valid() && rhs.is_valid());
195  return IsSameRenderer(rhs) && main_frame_url == rhs.main_frame_url;
196}
197
198bool NavigationID::IsSameRenderer(const NavigationID& other) const {
199  DCHECK(is_valid() && other.is_valid());
200  return render_process_id == other.render_process_id &&
201      render_frame_id == other.render_frame_id;
202}
203
204ResourcePrefetchPredictorConfig::ResourcePrefetchPredictorConfig()
205    : mode(0),
206      max_navigation_lifetime_seconds(60),
207      max_urls_to_track(500),
208      max_hosts_to_track(200),
209      min_url_visit_count(2),
210      max_resources_per_entry(50),
211      max_consecutive_misses(3),
212      min_resource_confidence_to_trigger_prefetch(0.8f),
213      min_resource_hits_to_trigger_prefetch(3),
214      max_prefetches_inflight_per_navigation(24),
215      max_prefetches_inflight_per_host_per_navigation(3) {
216}
217
218ResourcePrefetchPredictorConfig::~ResourcePrefetchPredictorConfig() {
219}
220
221bool ResourcePrefetchPredictorConfig::IsLearningEnabled() const {
222  return IsURLLearningEnabled() || IsHostLearningEnabled();
223}
224
225bool ResourcePrefetchPredictorConfig::IsPrefetchingEnabled() const {
226  return IsURLPrefetchingEnabled() || IsHostPrefetchingEnabled();
227}
228
229bool ResourcePrefetchPredictorConfig::IsURLLearningEnabled() const {
230  return (mode & URL_LEARNING) > 0;
231}
232
233bool ResourcePrefetchPredictorConfig::IsHostLearningEnabled() const {
234  return (mode & HOST_LEARNING) > 0;
235}
236
237bool ResourcePrefetchPredictorConfig::IsURLPrefetchingEnabled() const {
238  return (mode & URL_PREFETCHING) > 0;
239}
240
241bool ResourcePrefetchPredictorConfig::IsHostPrefetchingEnabled() const {
242  return (mode & HOST_PRFETCHING) > 0;
243}
244
245}  // namespace predictors
246