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

Side by Side Diff: chrome/browser/net/referrer.cc

Issue 3032014: Support both preconnection, and pre-resolution for subresources... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 4 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
« no previous file with comments | « chrome/browser/net/referrer.h ('k') | chrome/browser/net/url_info.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/net/referrer.h" 5 #include "chrome/browser/net/referrer.h"
6 6
7 #include <limits.h> 7 #include <limits.h>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "chrome/browser/net/predictor.h"
10 11
11 namespace chrome_browser_net { 12 namespace chrome_browser_net {
12 13
13 //------------------------------------------------------------------------------ 14 //------------------------------------------------------------------------------
14 // Smoothing parameter for updating subresource_use_rate_. 15 // Smoothing parameter for updating subresource_use_rate_.
15 16
16 // We always combine our old expected value, weighted by some factor, with the 17 // We always combine our old expected value, weighted by some factor W (we use
17 // new expected value Enew. The new "expected value" is the number of actual 18 // kWeightingForOldExpectedValue), with the new expected value Enew. The new
18 // connections made due to the curernt navigations. 19 // "expected value" is the number of actual connections made due to the current
19 // This means the formula (in a concise form) is: 20 // navigations.
20 // Eupdated = Eold * W + Enew * (1 - W)
21 // That means that IF we end up needing to connect, we should apply the formula: 21 // That means that IF we end up needing to connect, we should apply the formula:
22 // Pupdated = Pold * W + Enew * (1 - W) 22 // Eupdated = Eold * W + Enew * (1 - W)
23 // If we visit the containing url, but don't end up needing a connection: 23 // If we visit the containing url, but don't end up needing a connection, then
24 // Pupdated = Pold * W 24 // Enew == 0, so we use the formula:
25 // To achive the above upating algorithm, we end up doing the multiplication 25 // Eupdated = Eold * W
26 // by W every time we contemplate doing a preconneciton (i.e., when we navigate 26 // To achieve the above updating algorithm, we end up doing the multiplication
27 // by W every time we contemplate doing a preconnection (i.e., when we navigate
27 // to the containing URL, and consider doing a preconnection), and then IFF we 28 // to the containing URL, and consider doing a preconnection), and then IFF we
28 // learn that we really needed a connection to the subresource, we complete the 29 // learn that we really needed a connection to the subresource, we complete the
29 // above algorithm by adding the (1 - W) for each connection we make. 30 // above algorithm by adding the (1 - W) for each connection we make.
30 31
31 // We weight the new expected value by a factor which is in the range of 0.0 to 32 // We weight the new expected value by a factor which is in the range of 0.0 to
32 // 1.0. 33 // 1.0.
33 static const double kWeightingForOldExpectedValue = 0.66; 34 static const double kWeightingForOldExpectedValue = 0.66;
34 35
35 // The expected value needed before we actually do a preconnection. 36 // To estimate the expected value of the number of connections that we'll need
36 static const double kPreconnectWorthyExpectedValue = 0.7; 37 // when a referrer is navigated to, we start with the following rather low
37 38 // initial value. Each time we do indeed (again) need the subresource, this
38 // The expected value that we'll need a preconnection when we first see the 39 // value will get increased. Each time we navigate to the refererrer but never
39 // subresource getting fetched. Very conservative is 0.0, which will mean that 40 // end up needing this subresource, the value will decrease.
40 // we have to wait for a while before using preconnection... but we do persist 41 // Very conservative is 0.0, which will mean that we have to wait for a while
41 // results, so we'll have the learned answer in the long run. 42 // before doing much speculative acvtivity... but we do persist results, so
43 // we'll save the asymptotic (correct?) learned answer in the long run.
42 static const double kInitialExpectedValue = 0.0; 44 static const double kInitialExpectedValue = 0.0;
43 45
44 // static 46 // static
45 bool Referrer::use_preconnect_valuations_ = false; 47 bool Referrer::use_preconnect_valuations_ = false;
46 48
47 void Referrer::SuggestHost(const GURL& url) { 49 void Referrer::SuggestHost(const GURL& url) {
48 // Limit how large our list can get, in case we make mistakes about what 50 // Limit how large our list can get, in case we make mistakes about what
49 // hostnames are in sub-resources (example: Some advertisments have a link to 51 // hostnames are in sub-resources (example: Some advertisments have a link to
50 // the ad agency, and then provide a "surprising" redirect to the advertised 52 // the ad agency, and then provide a "surprising" redirect to the advertised
51 // entity, which then (mistakenly) appears to be a subresource on the page 53 // entity, which then (mistakenly) appears to be a subresource on the page
(...skipping 12 matching lines...) Expand all
64 66
65 if (kMaxSuggestions <= size()) { 67 if (kMaxSuggestions <= size()) {
66 DeleteLeastUseful(); 68 DeleteLeastUseful();
67 DCHECK(kMaxSuggestions > size()); 69 DCHECK(kMaxSuggestions > size());
68 } 70 }
69 (*this)[url].SubresourceIsNeeded(); 71 (*this)[url].SubresourceIsNeeded();
70 } 72 }
71 73
72 void Referrer::DeleteLeastUseful() { 74 void Referrer::DeleteLeastUseful() {
73 // Find the item with the lowest value. Most important is preconnection_rate, 75 // Find the item with the lowest value. Most important is preconnection_rate,
74 // next is latency savings, and last is lifetime (age). 76 // and least is lifetime (age).
75 GURL least_useful_url; 77 GURL least_useful_url;
76 double lowest_rate_seen = 0.0; 78 double lowest_rate_seen = 0.0;
77 // We use longs for durations because we will use multiplication on them. 79 // We use longs for durations because we will use multiplication on them.
78 int64 lowest_latency_seen = 0; // Duration in milliseconds.
79 int64 least_useful_lifetime = 0; // Duration in milliseconds. 80 int64 least_useful_lifetime = 0; // Duration in milliseconds.
80 81
81 const base::Time kNow(base::Time::Now()); // Avoid multiple calls. 82 const base::Time kNow(base::Time::Now()); // Avoid multiple calls.
82 for (SubresourceMap::iterator it = begin(); it != end(); ++it) { 83 for (SubresourceMap::iterator it = begin(); it != end(); ++it) {
83 int64 lifetime = (kNow - it->second.birth_time()).InMilliseconds(); 84 int64 lifetime = (kNow - it->second.birth_time()).InMilliseconds();
84 int64 latency = it->second.latency().InMilliseconds();
85 double rate = it->second.subresource_use_rate(); 85 double rate = it->second.subresource_use_rate();
86 if (least_useful_url.has_host()) { 86 if (least_useful_url.has_host()) {
87 if (rate > lowest_rate_seen) 87 if (rate > lowest_rate_seen)
88 continue; 88 continue;
89 if (!latency && !lowest_latency_seen) { 89 if (lifetime <= least_useful_lifetime)
90 // Older name is less useful. 90 continue;
91 if (lifetime <= least_useful_lifetime)
92 continue;
93 } else {
94 // Compare the ratios:
95 // latency/lifetime
96 // vs.
97 // lowest_latency_seen/least_useful_lifetime
98 // by cross multiplying (to avoid integer division hassles). Overflow's
99 // won't happen until both latency and lifetime pass about 49 days.
100 if (latency * least_useful_lifetime >
101 lowest_latency_seen * lifetime) {
102 continue;
103 }
104 }
105 } 91 }
106 least_useful_url = it->first; 92 least_useful_url = it->first;
107 lowest_rate_seen = rate; 93 lowest_rate_seen = rate;
108 lowest_latency_seen = latency;
109 least_useful_lifetime = lifetime; 94 least_useful_lifetime = lifetime;
110 } 95 }
111 erase(least_useful_url); 96 if (least_useful_url.has_host())
112 // Note: there is a small chance that we will discard a least_useful_url 97 erase(least_useful_url);
113 // that is currently being prefetched because it *was* in this referer list.
114 // In that case, when a benefit appears in AccrueValue() below, we are careful
115 // to check before accessing the member.
116 }
117
118 void Referrer::AccrueValue(const base::TimeDelta& delta,
119 const GURL& url) {
120 SubresourceMap::iterator it = find(url);
121 // Be careful that we weren't evicted from this referrer in DeleteLeastUseful.
122 if (it != end())
123 it->second.AccrueValue(delta);
124 } 98 }
125 99
126 bool Referrer::Trim() { 100 bool Referrer::Trim() {
127 bool has_some_latency_left = false; 101 std::vector<GURL> discarded_urls;
128 for (SubresourceMap::iterator it = begin(); it != end(); ++it) 102 for (SubresourceMap::iterator it = begin(); it != end(); ++it)
129 if (it->second.Trim()) 103 if (!it->second.Trim())
130 has_some_latency_left = true; 104 discarded_urls.push_back(it->first);
131 return has_some_latency_left; 105 for (size_t i = 0; i < discarded_urls.size(); ++i)
106 erase(discarded_urls[i]);
107 return size() > 0;
132 } 108 }
133 109
134 bool ReferrerValue::Trim() { 110 bool ReferrerValue::Trim() {
135 int64 latency_ms = latency_.InMilliseconds() / 2; 111 subresource_use_rate_ /= 2.0;
136 latency_ = base::TimeDelta::FromMilliseconds(latency_ms); 112 return subresource_use_rate_ > Predictor::kPersistWorthyExpectedValue;
137 return latency_ms > 0 ||
138 subresource_use_rate_ > kPreconnectWorthyExpectedValue / 2;
139 } 113 }
140 114
141 115
142 void Referrer::Deserialize(const Value& value) { 116 void Referrer::Deserialize(const Value& value) {
143 if (value.GetType() != Value::TYPE_LIST) 117 if (value.GetType() != Value::TYPE_LIST)
144 return; 118 return;
145 const ListValue* subresource_list(static_cast<const ListValue*>(&value)); 119 const ListValue* subresource_list(static_cast<const ListValue*>(&value));
146 size_t index = 0; // Bounds checking is done by subresource_list->Get*(). 120 size_t index = 0; // Bounds checking is done by subresource_list->Get*().
147 while (true) { 121 while (true) {
148 std::string url_spec; 122 std::string url_spec;
149 if (!subresource_list->GetString(index++, &url_spec)) 123 if (!subresource_list->GetString(index++, &url_spec))
150 return; 124 return;
151 int latency_ms;
152 if (!subresource_list->GetInteger(index++, &latency_ms))
153 return;
154 double rate; 125 double rate;
155 if (!subresource_list->GetReal(index++, &rate)) 126 if (!subresource_list->GetReal(index++, &rate))
156 return; 127 return;
157 128
158 GURL url(url_spec); 129 GURL url(url_spec);
159 base::TimeDelta latency = base::TimeDelta::FromMilliseconds(latency_ms);
160 // TODO(jar): We could be more direct, and change birth date or similar to 130 // TODO(jar): We could be more direct, and change birth date or similar to
161 // show that this is a resurrected value we're adding in. I'm not yet sure 131 // show that this is a resurrected value we're adding in. I'm not yet sure
162 // of how best to optimize the learning and pruning (Trim) algorithm at this 132 // of how best to optimize the learning and pruning (Trim) algorithm at this
163 // level, so for now, we just suggest subresources, which leaves them all 133 // level, so for now, we just suggest subresources, which leaves them all
164 // with the same birth date (typically start of process). 134 // with the same birth date (typically start of process).
165 SuggestHost(url); 135 SuggestHost(url);
166 AccrueValue(latency, url);
167 (*this)[url].SetSubresourceUseRate(rate); 136 (*this)[url].SetSubresourceUseRate(rate);
168 } 137 }
169 } 138 }
170 139
171 Value* Referrer::Serialize() const { 140 Value* Referrer::Serialize() const {
172 ListValue* subresource_list(new ListValue); 141 ListValue* subresource_list(new ListValue);
173 for (const_iterator it = begin(); it != end(); ++it) { 142 for (const_iterator it = begin(); it != end(); ++it) {
174 StringValue* url_spec(new StringValue(it->first.spec())); 143 StringValue* url_spec(new StringValue(it->first.spec()));
175 int latency_integer = static_cast<int>(it->second.latency().
176 InMilliseconds());
177 // Watch out for overflow in the above static_cast! Check to see if we went
178 // negative, and just use a "big" value. The value seems unimportant once
179 // we get to such high latencies. Probable cause of high latency is a bug
180 // in other code, so also do a DCHECK.
181 DCHECK_GE(latency_integer, 0);
182 if (latency_integer < 0)
183 latency_integer = INT_MAX;
184 FundamentalValue* latency(new FundamentalValue(latency_integer));
185 FundamentalValue* rate(new FundamentalValue( 144 FundamentalValue* rate(new FundamentalValue(
186 it->second.subresource_use_rate())); 145 it->second.subresource_use_rate()));
187 146
188 subresource_list->Append(url_spec); 147 subresource_list->Append(url_spec);
189 subresource_list->Append(latency);
190 subresource_list->Append(rate); 148 subresource_list->Append(rate);
191 } 149 }
192 return subresource_list; 150 return subresource_list;
193 } 151 }
194 152
195 //------------------------------------------------------------------------------ 153 //------------------------------------------------------------------------------
196 154
197 ReferrerValue::ReferrerValue() 155 ReferrerValue::ReferrerValue()
198 : birth_time_(base::Time::Now()), 156 : birth_time_(base::Time::Now()),
199 navigation_count_(0), 157 navigation_count_(0),
200 preconnection_count_(0), 158 preconnection_count_(0),
159 preresolution_count_(0),
201 subresource_use_rate_(kInitialExpectedValue) { 160 subresource_use_rate_(kInitialExpectedValue) {
202 } 161 }
203 162
204 void ReferrerValue::SubresourceIsNeeded() { 163 void ReferrerValue::SubresourceIsNeeded() {
205 DCHECK_GE(kWeightingForOldExpectedValue, 0); 164 DCHECK_GE(kWeightingForOldExpectedValue, 0);
206 DCHECK_LE(kWeightingForOldExpectedValue, 1.0); 165 DCHECK_LE(kWeightingForOldExpectedValue, 1.0);
207 ++navigation_count_; 166 ++navigation_count_;
208 subresource_use_rate_ += 1 - kWeightingForOldExpectedValue; 167 subresource_use_rate_ += 1 - kWeightingForOldExpectedValue;
209 } 168 }
210 169
211 bool ReferrerValue::IsPreconnectWorthDoing() { 170 void ReferrerValue::ReferrerWasObserved() {
212 bool preconnecting = kPreconnectWorthyExpectedValue < subresource_use_rate_;
213 if (preconnecting)
214 ++preconnection_count_;
215 subresource_use_rate_ *= kWeightingForOldExpectedValue; 171 subresource_use_rate_ *= kWeightingForOldExpectedValue;
216 // Note: the use rate is temporarilly possibly incorect, as we need to find 172 // Note: the use rate is temporarilly possibly incorect, as we need to find
217 // out if we really end up connecting. This will happen in a few hundred 173 // out if we really end up connecting. This will happen in a few hundred
218 // milliseconds (when content arrives, etc.). 174 // milliseconds (when content arrives, etc.).
219 return preconnecting; 175 // Value of subresource_use_rate_ should be sampled before this call.
220 } 176 }
221 177
222 } // namespace chrome_browser_net 178 } // namespace chrome_browser_net
OLDNEW
« no previous file with comments | « chrome/browser/net/referrer.h ('k') | chrome/browser/net/url_info.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698