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.
5 #include "chrome/browser/predictors/resource_prefetch_common.h"
9 #include "base/command_line.h"
10 #include "base/metrics/field_trial.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/strings/string_split.h"
13 #include "chrome/browser/net/prediction_options.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/common/chrome_switches.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "content/public/browser/render_frame_host.h"
18 #include "content/public/browser/render_process_host.h"
19 #include "content/public/browser/web_contents.h"
21 using base::FieldTrialList
;
25 namespace predictors
{
27 const char kSpeculativePrefetchingTrialName
[] =
28 "SpeculativeResourcePrefetching";
31 * SpeculativeResourcePrefetching is a field trial, and its value must have the
32 * following format: key1=value1:key2=value2:key3=value3
33 * e.g. "Prefetching=Enabled:Predictor=Url:Confidence=High"
34 * The function below extracts the value corresponding to a key provided from
35 * the SpeculativeResourcePrefetching field trial.
37 string
GetFiledTrialSpecValue(string key
) {
38 vector
<string
> elements
;
40 FieldTrialList::FindFullName(kSpeculativePrefetchingTrialName
),
43 for (int i
= 0; i
< static_cast<int>(elements
.size()); i
++) {
44 vector
<string
> key_value
;
45 base::SplitString(elements
[i
], '=', &key_value
);
46 if (key_value
.size() == 2 && key_value
[0] == key
)
52 bool IsSpeculativeResourcePrefetchingEnabled(
54 ResourcePrefetchPredictorConfig
* config
) {
57 // Off the record - disabled.
58 if (!profile
|| profile
->IsOffTheRecord())
61 // Enabled by command line switch. The config has the default params already
62 // set. The command line with just enable them with the default params.
63 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
64 switches::kSpeculativeResourcePrefetching
)) {
65 const std::string value
=
66 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
67 switches::kSpeculativeResourcePrefetching
);
69 if (value
== switches::kSpeculativeResourcePrefetchingDisabled
) {
71 } else if (value
== switches::kSpeculativeResourcePrefetchingLearning
) {
72 config
->mode
|= ResourcePrefetchPredictorConfig::URL_LEARNING
;
73 config
->mode
|= ResourcePrefetchPredictorConfig::HOST_LEARNING
;
75 } else if (value
== switches::kSpeculativeResourcePrefetchingEnabled
) {
76 config
->mode
|= ResourcePrefetchPredictorConfig::URL_LEARNING
;
77 config
->mode
|= ResourcePrefetchPredictorConfig::HOST_LEARNING
;
78 config
->mode
|= ResourcePrefetchPredictorConfig::URL_PREFETCHING
;
79 config
->mode
|= ResourcePrefetchPredictorConfig::HOST_PRFETCHING
;
84 // Disable if no field trial is specified.
85 std::string trial
= base::FieldTrialList::FindFullName(
86 kSpeculativePrefetchingTrialName
);
90 // Enabled by field trial.
91 std::string spec_prefetching
= GetFiledTrialSpecValue("Prefetching");
92 std::string spec_predictor
= GetFiledTrialSpecValue("Predictor");
93 std::string spec_confidence
= GetFiledTrialSpecValue("Confidence");
94 std::string spec_more_resources
= GetFiledTrialSpecValue("MoreResources");
95 std::string spec_small_db
= GetFiledTrialSpecValue("SmallDB");
97 if (spec_prefetching
== "Learning") {
98 if (spec_predictor
== "Url") {
99 config
->mode
|= ResourcePrefetchPredictorConfig::URL_LEARNING
;
100 } else if (spec_predictor
== "Host") {
101 config
->mode
|= ResourcePrefetchPredictorConfig::HOST_LEARNING
;
103 // Default: both Url and Host
104 config
->mode
|= ResourcePrefetchPredictorConfig::URL_LEARNING
;
105 config
->mode
|= ResourcePrefetchPredictorConfig::HOST_LEARNING
;
107 } else if (spec_prefetching
== "Enabled") {
108 if (spec_predictor
== "Url") {
109 config
->mode
|= ResourcePrefetchPredictorConfig::URL_LEARNING
;
110 config
->mode
|= ResourcePrefetchPredictorConfig::URL_PREFETCHING
;
111 } else if (spec_predictor
== "Host") {
112 config
->mode
|= ResourcePrefetchPredictorConfig::HOST_LEARNING
;
113 config
->mode
|= ResourcePrefetchPredictorConfig::HOST_PRFETCHING
;
115 // Default: both Url and Host
116 config
->mode
|= ResourcePrefetchPredictorConfig::URL_LEARNING
;
117 config
->mode
|= ResourcePrefetchPredictorConfig::HOST_LEARNING
;
118 config
->mode
|= ResourcePrefetchPredictorConfig::URL_PREFETCHING
;
119 config
->mode
|= ResourcePrefetchPredictorConfig::HOST_PRFETCHING
;
122 // Default: spec_prefetching == "Disabled"
126 if (spec_confidence
== "Low") {
127 config
->min_url_visit_count
= 1;
128 config
->min_resource_confidence_to_trigger_prefetch
= 0.5f
;
129 config
->min_resource_hits_to_trigger_prefetch
= 1;
130 } else if (spec_confidence
== "High") {
131 config
->min_url_visit_count
= 3;
132 config
->min_resource_confidence_to_trigger_prefetch
= 0.9f
;
133 config
->min_resource_hits_to_trigger_prefetch
= 3;
136 config
->min_url_visit_count
= 2;
137 config
->min_resource_confidence_to_trigger_prefetch
= 0.7f
;
138 config
->min_resource_hits_to_trigger_prefetch
= 2;
141 if (spec_more_resources
== "Enabled") {
142 config
->max_resources_per_entry
= 100;
145 if (spec_small_db
== "Enabled") {
146 config
->max_urls_to_track
= 200;
147 config
->max_hosts_to_track
= 100;
153 NavigationID::NavigationID()
154 : render_process_id(-1),
155 render_frame_id(-1) {
158 NavigationID::NavigationID(const NavigationID
& other
)
159 : render_process_id(other
.render_process_id
),
160 render_frame_id(other
.render_frame_id
),
161 main_frame_url(other
.main_frame_url
),
162 creation_time(other
.creation_time
) {
165 NavigationID::NavigationID(content::WebContents
* web_contents
)
166 : render_process_id(web_contents
->GetRenderProcessHost()->GetID()),
167 render_frame_id(web_contents
->GetMainFrame()->GetRoutingID()),
168 main_frame_url(web_contents
->GetURL()) {
171 bool NavigationID::is_valid() const {
172 return render_process_id
!= -1 && render_frame_id
!= -1 &&
173 !main_frame_url
.is_empty();
176 bool NavigationID::operator<(const NavigationID
& rhs
) const {
177 DCHECK(is_valid() && rhs
.is_valid());
178 if (render_process_id
!= rhs
.render_process_id
)
179 return render_process_id
< rhs
.render_process_id
;
180 else if (render_frame_id
!= rhs
.render_frame_id
)
181 return render_frame_id
< rhs
.render_frame_id
;
183 return main_frame_url
< rhs
.main_frame_url
;
186 bool NavigationID::operator==(const NavigationID
& rhs
) const {
187 DCHECK(is_valid() && rhs
.is_valid());
188 return IsSameRenderer(rhs
) && main_frame_url
== rhs
.main_frame_url
;
191 bool NavigationID::IsSameRenderer(const NavigationID
& other
) const {
192 DCHECK(is_valid() && other
.is_valid());
193 return render_process_id
== other
.render_process_id
&&
194 render_frame_id
== other
.render_frame_id
;
197 ResourcePrefetchPredictorConfig::ResourcePrefetchPredictorConfig()
199 max_navigation_lifetime_seconds(60),
200 max_urls_to_track(500),
201 max_hosts_to_track(200),
202 min_url_visit_count(2),
203 max_resources_per_entry(50),
204 max_consecutive_misses(3),
205 min_resource_confidence_to_trigger_prefetch(0.7f
),
206 min_resource_hits_to_trigger_prefetch(2),
207 max_prefetches_inflight_per_navigation(24),
208 max_prefetches_inflight_per_host_per_navigation(3) {
211 ResourcePrefetchPredictorConfig::~ResourcePrefetchPredictorConfig() {
214 bool ResourcePrefetchPredictorConfig::IsLearningEnabled() const {
215 return IsURLLearningEnabled() || IsHostLearningEnabled();
218 bool ResourcePrefetchPredictorConfig::IsPrefetchingEnabled(
219 Profile
* profile
) const {
220 return IsURLPrefetchingEnabled(profile
) || IsHostPrefetchingEnabled(profile
);
223 bool ResourcePrefetchPredictorConfig::IsURLLearningEnabled() const {
224 return (mode
& URL_LEARNING
) > 0;
227 bool ResourcePrefetchPredictorConfig::IsHostLearningEnabled() const {
228 return (mode
& HOST_LEARNING
) > 0;
231 bool ResourcePrefetchPredictorConfig::IsURLPrefetchingEnabled(
232 Profile
* profile
) const {
233 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
234 if (!profile
|| !profile
->GetPrefs() ||
235 !chrome_browser_net::CanPrefetchAndPrerenderUI(profile
->GetPrefs())) {
238 return (mode
& URL_PREFETCHING
) > 0;
241 bool ResourcePrefetchPredictorConfig::IsHostPrefetchingEnabled(
242 Profile
* profile
) const {
243 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
244 if (!profile
|| !profile
->GetPrefs() ||
245 !chrome_browser_net::CanPrefetchAndPrerenderUI(profile
->GetPrefs())) {
248 return (mode
& HOST_PRFETCHING
) > 0;
251 bool ResourcePrefetchPredictorConfig::IsLowConfidenceForTest() const {
252 return min_url_visit_count
== 1 &&
253 std::abs(min_resource_confidence_to_trigger_prefetch
- 0.5f
) < 1e-6 &&
254 min_resource_hits_to_trigger_prefetch
== 1;
257 bool ResourcePrefetchPredictorConfig::IsHighConfidenceForTest() const {
258 return min_url_visit_count
== 3 &&
259 std::abs(min_resource_confidence_to_trigger_prefetch
- 0.9f
) < 1e-6 &&
260 min_resource_hits_to_trigger_prefetch
== 3;
263 bool ResourcePrefetchPredictorConfig::IsMoreResourcesEnabledForTest() const {
264 return max_resources_per_entry
== 100;
267 bool ResourcePrefetchPredictorConfig::IsSmallDBEnabledForTest() const {
268 return max_urls_to_track
== 200 && max_hosts_to_track
== 100;
271 } // namespace predictors