summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/io_thread.cc21
-rw-r--r--chrome/browser/net/connect_interceptor.cc25
-rw-r--r--chrome/browser/net/preconnect.cc16
-rw-r--r--chrome/browser/net/preconnect.h12
-rw-r--r--chrome/browser/net/predictor.cc184
-rw-r--r--chrome/browser/net/predictor.h34
-rw-r--r--chrome/browser/net/predictor_api.cc178
-rw-r--r--chrome/browser/net/predictor_api.h4
-rw-r--r--chrome/browser/net/predictor_unittest.cc170
-rw-r--r--chrome/browser/net/referrer.cc114
-rw-r--r--chrome/browser/net/referrer.h44
-rw-r--r--chrome/browser/net/url_info.cc124
-rw-r--r--chrome/browser/net/url_info.h28
-rw-r--r--chrome/browser/renderer_host/resource_dispatcher_host.cc7
-rw-r--r--net/base/load_flags_list.h9
15 files changed, 285 insertions, 685 deletions
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc
index b0e27b2..998722e 100644
--- a/chrome/browser/io_thread.cc
+++ b/chrome/browser/io_thread.cc
@@ -336,17 +336,16 @@ void IOThread::InitNetworkPredictorOnIOThread(
preconnect_enabled);
predictor_->AddRef();
- // TODO(jar): Until connection notification and DNS observation handling are
- // properly combined into a learning model, we'll only use one observation
- // mechanism or the other.
- if (preconnect_enabled) {
- DCHECK(!speculative_interceptor_);
- speculative_interceptor_ = new chrome_browser_net::ConnectInterceptor;
- } else {
- DCHECK(!prefetch_observer_);
- prefetch_observer_ = chrome_browser_net::CreateResolverObserver();
- globals_->host_resolver->AddObserver(prefetch_observer_);
- }
+ // Speculative_interceptor_ is used to predict subresource usage.
+ DCHECK(!speculative_interceptor_);
+ speculative_interceptor_ = new chrome_browser_net::ConnectInterceptor;
+
+ // TODO(jar): We can completely replace prefetch_observer with
+ // speculative_interceptor.
+ // Prefetch_observer is used to monitor initial resolutions.
+ DCHECK(!prefetch_observer_);
+ prefetch_observer_ = chrome_browser_net::CreateResolverObserver();
+ globals_->host_resolver->AddObserver(prefetch_observer_);
FinalizePredictorInitialization(
predictor_, prefetch_observer_, startup_urls, referral_list);
diff --git a/chrome/browser/net/connect_interceptor.cc b/chrome/browser/net/connect_interceptor.cc
index 7415ac1..99abf24 100644
--- a/chrome/browser/net/connect_interceptor.cc
+++ b/chrome/browser/net/connect_interceptor.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/net/connect_interceptor.h"
#include "chrome/browser/net/predictor_api.h"
+#include "net/base/load_flags.h"
namespace chrome_browser_net {
@@ -17,24 +18,18 @@ ConnectInterceptor::~ConnectInterceptor() {
}
URLRequestJob* ConnectInterceptor::MaybeIntercept(URLRequest* request) {
- if (!request->referrer().empty()) {
+ bool is_subresource = !(request->load_flags() & net::LOAD_MAIN_FRAME);
+ if (is_subresource && !request->referrer().empty()) {
// Learn about our referring URL, for use in the future.
- GURL referring_url(GURL(request->referrer()).GetWithEmptyPath());
- // TODO(jar): Only call if we think this was part of a frame load, and not a
- // link navigation. For now, we'll "learn" that to preconnect when a user
- // actually does a click... which will probably waste space in our referrers
- // table (since it probably won't be that deterministic).
- LearnFromNavigation(referring_url, request->url().GetWithEmptyPath());
+ GURL referring_url(request->referrer());
+ LearnFromNavigation(referring_url.GetWithEmptyPath(),
+ request->url().GetWithEmptyPath());
}
+ bool is_frame = 0 != (request->load_flags() & (net::LOAD_SUB_FRAME |
+ net::LOAD_MAIN_FRAME));
// Now we use previous learning and setup for our subresources.
- if (request->was_fetched_via_proxy())
- return NULL;
- // TODO(jar): Only call if we believe this is a frame, and might have
- // subresources. We could "guess" by looking at path extensions (such as
- // foo.jpg or goo.gif etc.), but better would be to get this info from webkit
- // and have it add the info to the request (we currently only set the
- // priority, but we could record whether it was a frame).
- PredictFrameSubresources(request->url().GetWithEmptyPath());
+ if (is_frame && !request->was_fetched_via_proxy())
+ PredictFrameSubresources(request->url().GetWithEmptyPath());
return NULL;
}
diff --git a/chrome/browser/net/preconnect.cc b/chrome/browser/net/preconnect.cc
index af0c308..2d4db36 100644
--- a/chrome/browser/net/preconnect.cc
+++ b/chrome/browser/net/preconnect.cc
@@ -26,17 +26,18 @@ bool Preconnect::preconnect_despite_proxy_ = false;
Preconnect* Preconnect::callback_instance_;
// static
-bool Preconnect::PreconnectOnUIThread(const GURL& url) {
+void Preconnect::PreconnectOnUIThread(const GURL& url,
+ UrlInfo::ResolutionMotivation motivation) {
// Try to do connection warming for this search provider.
URLRequestContextGetter* getter = Profile::GetDefaultRequestContext();
if (!getter)
- return false;
+ return;
// Prewarm connection to Search URL.
ChromeThread::PostTask(
ChromeThread::IO,
FROM_HERE,
- NewRunnableFunction(Preconnect::PreconnectOnIOThread, url));
- return true;
+ NewRunnableFunction(Preconnect::PreconnectOnIOThread, url, motivation));
+ return;
}
enum ProxyStatus {
@@ -53,8 +54,8 @@ static void HistogramPreconnectStatus(ProxyStatus status) {
}
// static
-void Preconnect::PreconnectOnIOThread(const GURL& url) {
- // TODO(jar): This does not handle proxies currently.
+void Preconnect::PreconnectOnIOThread(const GURL& url,
+ UrlInfo::ResolutionMotivation motivation) {
URLRequestContextGetter* getter = Profile::GetDefaultRequestContext();
if (!getter)
return;
@@ -84,6 +85,9 @@ void Preconnect::PreconnectOnIOThread(const GURL& url) {
}
}
+ UMA_HISTOGRAM_ENUMERATION("Net.PreconnectMotivation", motivation,
+ UrlInfo::MAX_MOTIVATED);
+
net::HttpTransactionFactory* factory = context->http_transaction_factory();
net::HttpNetworkSession* session = factory->GetSession();
diff --git a/chrome/browser/net/preconnect.h b/chrome/browser/net/preconnect.h
index 83966b1..d773636 100644
--- a/chrome/browser/net/preconnect.h
+++ b/chrome/browser/net/preconnect.h
@@ -10,6 +10,7 @@
#pragma once
#include "base/ref_counted.h"
+#include "chrome/browser/net/url_info.h"
#include "net/base/completion_callback.h"
#include "net/base/host_port_pair.h"
#include "net/socket/client_socket_handle.h"
@@ -20,9 +21,14 @@ namespace chrome_browser_net {
class Preconnect : public net::CompletionCallback {
public:
- static bool PreconnectOnUIThread(const GURL& url);
-
- static void PreconnectOnIOThread(const GURL& url);
+ // Try to preconnect. Typically motivated by OMNIBOX to reach search service.
+ static void PreconnectOnUIThread(const GURL& url,
+ UrlInfo::ResolutionMotivation motivation);
+
+ // Try to preconnect. Typically used by predictor when a subresource probably
+ // needs a connection.
+ static void PreconnectOnIOThread(const GURL& url,
+ UrlInfo::ResolutionMotivation motivation);
static void SetPreconnectDespiteProxy(bool status) {
preconnect_despite_proxy_ = status;
diff --git a/chrome/browser/net/predictor.cc b/chrome/browser/net/predictor.cc
index 2675f88..eb4992c 100644
--- a/chrome/browser/net/predictor.cc
+++ b/chrome/browser/net/predictor.cc
@@ -26,6 +26,14 @@ using base::TimeDelta;
namespace chrome_browser_net {
+// static
+const double Predictor::kPreconnectWorthyExpectedValue = 0.7;
+// static
+const double Predictor::kDNSPreresolutionWorthyExpectedValue = 0.2;
+// static
+const double Predictor::kPersistWorthyExpectedValue = 0.1;
+
+
class Predictor::LookupRequest {
public:
LookupRequest(Predictor* predictor,
@@ -118,60 +126,6 @@ void Predictor::Resolve(const GURL& url,
AppendToResolutionQueue(url, motivation);
}
-bool Predictor::AccruePrefetchBenefits(const GURL& referrer,
- UrlInfo* navigation_info) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
- GURL url = navigation_info->url();
- Results::iterator it = results_.find(url);
- if (it == results_.end()) {
- // Use UMA histogram to quantify potential future gains here.
- UMA_HISTOGRAM_LONG_TIMES("DNS.UnexpectedResolutionL",
- navigation_info->resolve_duration());
- navigation_info->DLogResultsStats("DNS UnexpectedResolution");
-
- LearnFromNavigation(referrer, navigation_info->url());
- return false;
- }
- UrlInfo& prefetched_host_info(it->second);
-
- // Sometimes a host is used as a subresource by several referrers, so it is
- // in our list, but was never motivated by a page-link-scan. In that case, it
- // really is an "unexpected" navigation, and we should tally it, and augment
- // our referrers_.
- bool referrer_based_prefetch = !prefetched_host_info.was_linked();
- if (referrer_based_prefetch) {
- // This wasn't the first time this host refered to *some* referrer.
- LearnFromNavigation(referrer, navigation_info->url());
- }
-
- DnsBenefit benefit = prefetched_host_info.AccruePrefetchBenefits(
- navigation_info);
- switch (benefit) {
- case PREFETCH_NAME_FOUND:
- case PREFETCH_NAME_NONEXISTANT:
- dns_cache_hits_.push_back(*navigation_info);
- if (referrer_based_prefetch) {
- if (referrer.has_host()) {
- referrers_[referrer].AccrueValue(
- navigation_info->benefits_remaining(), url);
- }
- }
- return true;
-
- case PREFETCH_CACHE_EVICTION:
- cache_eviction_map_[url] = *navigation_info;
- return false;
-
- case PREFETCH_NO_BENEFIT:
- // Prefetch never hit the network. Name was pre-cached.
- return false;
-
- default:
- NOTREACHED();
- return false;
- }
-}
-
void Predictor::LearnFromNavigation(const GURL& referring_url,
const GURL& target_url) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
@@ -182,22 +136,12 @@ void Predictor::LearnFromNavigation(const GURL& referring_url,
}
}
-void Predictor::PredictSubresources(const GURL& url) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
- Referrers::iterator it = referrers_.find(url);
- if (referrers_.end() == it)
- return;
- Referrer* referrer = &(it->second);
- referrer->IncrementUseCount();
- for (Referrer::iterator future_url = referrer->begin();
- future_url != referrer->end(); ++future_url) {
- UrlInfo* queued_info = AppendToResolutionQueue(
- future_url->first,
- UrlInfo::LEARNED_REFERAL_MOTIVATED);
- if (queued_info)
- queued_info->SetReferringHostname(url);
- }
-}
+enum SubresourceValue {
+ PRECONNECTION,
+ PRERESOLUTION,
+ TOO_NEW,
+ SUBRESOURCE_VALUE_MAX
+};
void Predictor::PredictFrameSubresources(const GURL& url) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
@@ -207,19 +151,36 @@ void Predictor::PredictFrameSubresources(const GURL& url) {
return;
Referrer* referrer = &(it->second);
referrer->IncrementUseCount();
+ const UrlInfo::ResolutionMotivation motivation =
+ UrlInfo::LEARNED_REFERAL_MOTIVATED;
for (Referrer::iterator future_url = referrer->begin();
future_url != referrer->end(); ++future_url) {
- if (future_url->second.IsPreconnectWorthDoing())
- Preconnect::PreconnectOnIOThread(future_url->first);
+ SubresourceValue evalution(TOO_NEW);
+ double connection_expectation = future_url->second.subresource_use_rate();
+ UMA_HISTOGRAM_CUSTOM_COUNTS("Net.PreconnectSubresourceExpectation",
+ static_cast<int>(connection_expectation * 100),
+ 10, 5000, 50);
+ future_url->second.ReferrerWasObserved();
+ if (preconnect_enabled_ &&
+ kPreconnectWorthyExpectedValue < connection_expectation) {
+ evalution = PRECONNECTION;
+ future_url->second.IncrementPreconnectionCount();
+ Preconnect::PreconnectOnIOThread(future_url->first, motivation);
+ } else if (kDNSPreresolutionWorthyExpectedValue < connection_expectation) {
+ evalution = PRERESOLUTION;
+ future_url->second.preresolution_increment();
+ UrlInfo* queued_info = AppendToResolutionQueue(future_url->first,
+ motivation);
+ if (queued_info)
+ queued_info->SetReferringHostname(url);
+ }
+ UMA_HISTOGRAM_ENUMERATION("Net.PreconnectSubresourceEval", evalution,
+ SUBRESOURCE_VALUE_MAX);
}
}
// Provide sort order so all .com's are together, etc.
struct RightToLeftStringSorter {
- bool operator()(const net::HostPortPair& left,
- const net::HostPortPair& right) const {
- return string_compare(left.host(), right.host());
- }
bool operator()(const GURL& left,
const GURL& right) const {
return string_compare(left.host(), right.host());
@@ -301,8 +262,8 @@ void Predictor::GetHtmlReferrerLists(std::string* output) {
"<th>Page Load<br>Count</th>"
"<th>Subresource<br>Navigations</th>"
"<th>Subresource<br>PreConnects</th>"
+ "<th>Subresource<br>PreResolves</th>"
"<th>Expected<br>Connects</th>"
- "<th>DNS<br>Savings</th>"
"<th>Subresource Spec</th></tr>");
for (SortedNames::iterator it = sorted_names.begin();
@@ -320,11 +281,11 @@ void Predictor::GetHtmlReferrerLists(std::string* output) {
static_cast<int>(referrer->use_count()));
first_set_of_futures = false;
StringAppendF(output,
- "<td>%d</td><td>%d</td><td>%2.3f</td><td>%dms</td><td>%s</td></tr>",
+ "<td>%d</td><td>%d</td><td>%d</td><td>%2.3f</td><td>%s</td></tr>",
static_cast<int>(future_url->second.navigation_count()),
static_cast<int>(future_url->second.preconnection_count()),
+ static_cast<int>(future_url->second.preresolution_count()),
static_cast<double>(future_url->second.subresource_use_rate()),
- static_cast<int>(future_url->second.latency().InMilliseconds()),
future_url->first.spec().c_str());
}
}
@@ -334,53 +295,26 @@ void Predictor::GetHtmlReferrerLists(std::string* output) {
void Predictor::GetHtmlInfo(std::string* output) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
// Local lists for calling UrlInfo
- UrlInfo::DnsInfoTable cache_hits;
- UrlInfo::DnsInfoTable cache_evictions;
- UrlInfo::DnsInfoTable name_not_found;
- UrlInfo::DnsInfoTable network_hits;
- UrlInfo::DnsInfoTable already_cached;
+ UrlInfo::UrlInfoTable name_not_found;
+ UrlInfo::UrlInfoTable name_preresolved;
// Get copies of all useful data.
- typedef std::map<GURL, UrlInfo, RightToLeftStringSorter>
- Snapshot;
- Snapshot snapshot;
- {
- // UrlInfo supports value semantics, so we can do a shallow copy.
- for (Results::iterator it(results_.begin()); it != results_.end(); it++) {
- snapshot[it->first] = it->second;
- }
- for (Results::iterator it(cache_eviction_map_.begin());
- it != cache_eviction_map_.end();
- it++) {
- cache_evictions.push_back(it->second);
- }
- // Reverse list as we copy cache hits, so that new hits are at the top.
- size_t index = dns_cache_hits_.size();
- while (index > 0) {
- index--;
- cache_hits.push_back(dns_cache_hits_[index]);
- }
- }
+ typedef std::map<GURL, UrlInfo, RightToLeftStringSorter> SortedUrlInfo;
+ SortedUrlInfo snapshot;
+ // UrlInfo supports value semantics, so we can do a shallow copy.
+ for (Results::iterator it(results_.begin()); it != results_.end(); it++)
+ snapshot[it->first] = it->second;
// Partition the UrlInfo's into categories.
- for (Snapshot::iterator it(snapshot.begin()); it != snapshot.end(); it++) {
+ for (SortedUrlInfo::iterator it(snapshot.begin());
+ it != snapshot.end(); it++) {
if (it->second.was_nonexistant()) {
name_not_found.push_back(it->second);
continue;
}
if (!it->second.was_found())
continue; // Still being processed.
- if (TimeDelta() != it->second.benefits_remaining()) {
- network_hits.push_back(it->second); // With no benefit yet.
- continue;
- }
- if (UrlInfo::kMaxNonNetworkDnsLookupDuration >
- it->second.resolve_duration()) {
- already_cached.push_back(it->second);
- continue;
- }
- // Remaining case is where prefetch benefit was significant, and was used.
- // Since we shot those cases as historical hits, we won't bother here.
+ name_preresolved.push_back(it->second);
}
bool brief = false;
@@ -389,16 +323,10 @@ void Predictor::GetHtmlInfo(std::string* output) {
#endif // NDEBUG
// Call for display of each table, along with title.
- UrlInfo::GetHtmlTable(cache_hits,
- "Prefetching DNS records produced benefits for ", false, output);
- UrlInfo::GetHtmlTable(cache_evictions,
- "Cache evictions negated DNS prefetching benefits for ", brief, output);
- UrlInfo::GetHtmlTable(network_hits,
- "Prefetching DNS records was not yet beneficial for ", brief, output);
- UrlInfo::GetHtmlTable(already_cached,
- "Previously cached resolutions were found for ", brief, output);
+ UrlInfo::GetHtmlTable(name_preresolved,
+ "Preresolution DNS records performed for ", brief, output);
UrlInfo::GetHtmlTable(name_not_found,
- "Prefetching DNS records revealed non-existance for ", brief, output);
+ "Preresolving DNS records revealed non-existance for ", brief, output);
}
UrlInfo* Predictor::AppendToResolutionQueue(
@@ -507,8 +435,6 @@ void Predictor::LookupFinished(LookupRequest* request, const GURL& url,
void Predictor::DiscardAllResults() {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
// Delete anything listed so far in this session that shows in about:dns.
- cache_eviction_map_.clear();
- dns_cache_hits_.clear();
referrers_.clear();
@@ -559,7 +485,7 @@ void Predictor::TrimReferrers() {
void Predictor::SerializeReferrers(ListValue* referral_list) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
referral_list->Clear();
- referral_list->Append(new FundamentalValue(DNS_REFERRER_VERSION));
+ referral_list->Append(new FundamentalValue(PREDICTOR_REFERRER_VERSION));
for (Referrers::const_iterator it = referrers_.begin();
it != referrers_.end(); ++it) {
// Serialize the list of subresource names.
@@ -579,7 +505,7 @@ void Predictor::DeserializeReferrers(const ListValue& referral_list) {
int format_version = -1;
if (referral_list.GetSize() > 0 &&
referral_list.GetInteger(0, &format_version) &&
- format_version == DNS_REFERRER_VERSION) {
+ format_version == PREDICTOR_REFERRER_VERSION) {
for (size_t i = 1; i < referral_list.GetSize(); ++i) {
ListValue* motivator;
if (!referral_list.GetList(i, &motivator)) {
diff --git a/chrome/browser/net/predictor.h b/chrome/browser/net/predictor.h
index f6c14f3..a5b71e7 100644
--- a/chrome/browser/net/predictor.h
+++ b/chrome/browser/net/predictor.h
@@ -13,8 +13,8 @@
// Subresource relationships are usually acquired from the referrer field in a
// navigation. A subresource URL may be associated with a referrer URL. Later
// navigations may, if the likelihood of needing the subresource is high enough,
-// cause this module to speculatively create a TCP/IP connection that will
-// probably be needed to fetch the subresource.
+// cause this module to speculatively create a TCP/IP connection. If there is
+// only a low likelihood, then a DNS pre-resolution operation may be performed.
#ifndef CHROME_BROWSER_NET_PREDICTOR_H_
#define CHROME_BROWSER_NET_PREDICTOR_H_
@@ -49,9 +49,19 @@ class Predictor : public base::RefCountedThreadSafe<Predictor> {
public:
// A version number for prefs that are saved. This should be incremented when
// we change the format so that we discard old data.
- enum { DNS_REFERRER_VERSION = 1 };
-
-// |max_concurrent| specifies how many concurrent (parallel) prefetches will
+ enum { PREDICTOR_REFERRER_VERSION = 2 };
+
+ // Depending on the expected_subresource_use_, we may either make a TCP/IP
+ // preconnection, or merely pre-resolve the hostname via DNS (or even do
+ // nothing). The following are the threasholds for taking those actions.
+ static const double kPreconnectWorthyExpectedValue;
+ static const double kDNSPreresolutionWorthyExpectedValue;
+ // Values of expected_subresource_use_ that are less than the following
+ // threshold will be discarded when we Trim() the values, such as is done when
+ // the process ends, and some values are persisted.
+ static const double kPersistWorthyExpectedValue;
+
+ // |max_concurrent| specifies how many concurrent (parallel) prefetches will
// be performed. Host lookups will be issued through |host_resolver|.
Predictor(net::HostResolver* host_resolver,
base::TimeDelta max_queue_delay_ms, size_t max_concurrent,
@@ -73,14 +83,6 @@ class Predictor : public base::RefCountedThreadSafe<Predictor> {
void Resolve(const GURL& url,
UrlInfo::ResolutionMotivation motivation);
- // Get latency benefit of the prefetch that we are navigating to.
- bool AccruePrefetchBenefits(const GURL& referrer,
- UrlInfo* navigation_info);
-
- // Instigate preresolution of any domains we predict will be needed after this
- // navigation.
- void PredictSubresources(const GURL& url);
-
// Instigate pre-connection to any URLs we predict will be needed after this
// navigation (typically more-embedded resources on a page).
void PredictFrameSubresources(const GURL& url);
@@ -240,12 +242,6 @@ class Predictor : public base::RefCountedThreadSafe<Predictor> {
// When true, we don't make new lookup requests.
bool shutdown_;
- // A list of successful events resulting from pre-fetching.
- UrlInfo::DnsInfoTable dns_cache_hits_;
- // A map of hosts that were evicted from our cache (after we prefetched them)
- // and before the HTTP stack tried to look them up.
- Results cache_eviction_map_;
-
// The number of concurrent lookups currently allowed.
const size_t max_concurrent_dns_lookups_;
diff --git a/chrome/browser/net/predictor_api.cc b/chrome/browser/net/predictor_api.cc
index d5f661dc..4e4569e 100644
--- a/chrome/browser/net/predictor_api.cc
+++ b/chrome/browser/net/predictor_api.cc
@@ -35,14 +35,14 @@ using base::TimeDelta;
namespace chrome_browser_net {
-static void DnsMotivatedPrefetch(const GURL& url,
- UrlInfo::ResolutionMotivation motivation);
+static void ResolveOnUIThread(const GURL& url,
+ UrlInfo::ResolutionMotivation motivation);
static void DnsPrefetchMotivatedList(const UrlList& urls,
- UrlInfo::ResolutionMotivation motivation);
+ UrlInfo::ResolutionMotivation motivation);
-static UrlList GetPredictedUrlListAtStartup(
- PrefService* user_prefs, PrefService* local_state);
+static UrlList GetPredictedUrlListAtStartup(PrefService* user_prefs,
+ PrefService* local_state);
// static
const size_t PredictorInit::kMaxPrefetchConcurrentLookups = 8;
@@ -186,6 +186,7 @@ void AnticipateUrl(const GURL& url, bool preconnectable) {
last_prefetch_for_host = now;
GURL canonical_url(CanonicalizeUrl(url));
+ UrlInfo::ResolutionMotivation motivation(UrlInfo::OMNIBOX_MOTIVATED);
if (predictor->preconnect_enabled() && preconnectable) {
static base::TimeTicks last_keepalive;
@@ -197,16 +198,16 @@ void AnticipateUrl(const GURL& url, bool preconnectable) {
return;
last_keepalive = now;
- if (Preconnect::PreconnectOnUIThread(canonical_url))
- return; // Skip pre-resolution, since we'll open a connection.
+ Preconnect::PreconnectOnUIThread(canonical_url, motivation);
+ return; // Skip pre-resolution, since we'll open a connection.
}
// Perform at least DNS pre-resolution.
- DnsMotivatedPrefetch(canonical_url, UrlInfo::OMNIBOX_MOTIVATED);
+ ResolveOnUIThread(canonical_url, motivation);
}
-static void DnsMotivatedPrefetch(const GURL& url,
- UrlInfo::ResolutionMotivation motivation) {
+static void ResolveOnUIThread(const GURL& url,
+ UrlInfo::ResolutionMotivation motivation) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
if (!dns_prefetch_enabled || NULL == predictor || !url.has_host())
return;
@@ -225,24 +226,6 @@ static void DnsMotivatedPrefetch(const GURL& url,
// helpful during the next chrome-startup.
//------------------------------------------------------------------------------
-// This function determines if there was a saving by prefetching the hostname
-// for which the navigation_info is supplied.
-static bool AccruePrefetchBenefits(const GURL& referrer_url,
- UrlInfo* navigation_info) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
- if (!dns_prefetch_enabled || NULL == predictor)
- return false;
- DCHECK(referrer_url == referrer_url.GetWithEmptyPath());
- return predictor->AccruePrefetchBenefits(referrer_url, navigation_info);
-}
-
-void PredictSubresources(const GURL& url) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
- if (!dns_prefetch_enabled || NULL == predictor)
- return;
- predictor->PredictSubresources(url);
-}
-
void PredictFrameSubresources(const GURL& url) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
if (!dns_prefetch_enabled || NULL == predictor)
@@ -263,34 +246,32 @@ typedef std::map<int, UrlInfo> ObservedResolutionMap;
// There will only be one instance ever created of the following Observer
// class. The PrefetchObserver lives on the IO thread, and intercepts DNS
-// resolutions made by the network stack.
+// resolutions made by the network stack. This is only used to identify startup
+// time resolutions (for re-resolution during our next process startup).
class PrefetchObserver : public net::HostResolver::Observer {
public:
- typedef std::map<GURL, UrlInfo> FirstResolutionMap;
+ typedef std::set<GURL> FirstResolutions;
// net::HostResolver::Observer implementation:
virtual void OnStartResolution(
int request_id,
- const net::HostResolver::RequestInfo& request_info);
- virtual void OnFinishResolutionWithStatus(
- int request_id,
- bool was_resolved,
- const net::HostResolver::RequestInfo& request_info);
- virtual void OnCancelResolution(
- int request_id,
- const net::HostResolver::RequestInfo& request_info);
+ const net::HostResolver::RequestInfo& request_info) {}
+
+ virtual void OnFinishResolutionWithStatus(int id, bool was_resolved,
+ const net::HostResolver::RequestInfo& info);
- void DnsGetFirstResolutionsHtml(std::string* output);
+ virtual void OnCancelResolution(int id,
+ const net::HostResolver::RequestInfo& info) {}
+
+ void DnsGetFirstResolutionsHtml(std::string* output);
void GetInitialDnsResolutionList(ListValue* startup_list);
private:
- void StartupListAppend(const UrlInfo& navigation_info);
+ void StartupListAppend(const std::string& host, int port);
- // Map of pending resolutions seen by observer.
- ObservedResolutionMap resolutions_;
- // List of the first N hostname resolutions observed in this run.
- FirstResolutionMap first_resolutions_;
- // The number of hostnames we'll save for prefetching at next startup.
+ // List of the first N URL resolutions observed in this run.
+ FirstResolutions first_resolutions_;
+ // The number of URLs we'll save for pre-resolving at next startup.
static const size_t kStartupResolutionCount = 10;
};
@@ -300,101 +281,39 @@ static PrefetchObserver* g_prefetch_observer = NULL;
//------------------------------------------------------------------------------
// Member definitions for above Observer class.
-void PrefetchObserver::OnStartResolution(
- int request_id,
- const net::HostResolver::RequestInfo& request_info) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
- if (request_info.is_speculative())
- return; // One of our own requests.
- if (!request_info.hostname().length())
- return; // PAC scripts may create queries without a hostname.
-
- UrlInfo navigation_info;
- // TODO(jar): Remove hack which guestimates ssl via port number, and perhaps
- // have actual URL passed down in request_info instead.
- bool is_ssl(443 == request_info.port());
- std::string url_spec = is_ssl ? "https://" : "http://";
- url_spec += request_info.hostname();
- url_spec += ":";
- url_spec += IntToString(request_info.port());
- navigation_info.SetUrl(GURL(url_spec));
- navigation_info.SetStartedState();
-
- // This entry will be deleted either by OnFinishResolutionWithStatus(), or
- // by OnCancelResolution().
- resolutions_[request_id] = navigation_info;
-}
-
void PrefetchObserver::OnFinishResolutionWithStatus(
int request_id,
bool was_resolved,
const net::HostResolver::RequestInfo& request_info) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
+ if (!was_resolved)
+ return; // Don't remember failures.
if (request_info.is_speculative())
return; // One of our own requests.
if (!request_info.hostname().length())
return; // PAC scripts may create queries without a hostname.
- UrlInfo navigation_info;
- size_t startup_count = 0;
- {
- ObservedResolutionMap::iterator it = resolutions_.find(request_id);
- if (resolutions_.end() == it) {
- NOTREACHED();
- return;
- }
- navigation_info = it->second;
- resolutions_.erase(it);
- startup_count = first_resolutions_.size();
- }
-
- navigation_info.SetFinishedState(was_resolved); // Get timing info
- AccruePrefetchBenefits(CanonicalizeUrl(request_info.referrer()),
- &navigation_info);
- // Handle sub-resource resolutions now that the critical navigational
- // resolution has completed. This prevents us from in any way delaying that
- // navigational resolution.
- std::string url_spec;
- StringAppendF(&url_spec, "http%s://%s:%d", "",
- request_info.hostname().c_str(), request_info.port());
- PredictSubresources(GURL(url_spec));
-
- if (kStartupResolutionCount <= startup_count || !was_resolved)
- return;
- // TODO(jar): Don't add host to our list if it is a non-linked lookup, and
- // instead rely on Referrers to pull this in automatically with the enclosing
- // page load (once we start to persist elements of our referrer tree).
- StartupListAppend(navigation_info);
+ StartupListAppend(request_info.hostname(), request_info.port());
}
-void PrefetchObserver::OnCancelResolution(
- int request_id,
- const net::HostResolver::RequestInfo& request_info) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
- if (request_info.is_speculative())
- return; // One of our own requests.
- if (!request_info.hostname().length())
- return; // PAC scripts may create queries without a hostname.
-
- // Remove the entry from |resolutions| that was added by OnStartResolution().
- ObservedResolutionMap::iterator it = resolutions_.find(request_id);
- if (resolutions_.end() == it) {
- NOTREACHED();
- return;
- }
- resolutions_.erase(it);
-}
-
-void PrefetchObserver::StartupListAppend(const UrlInfo& navigation_info) {
+void PrefetchObserver::StartupListAppend(const std::string& host, int port) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
if (!on_the_record_switch || NULL == predictor)
return;
if (kStartupResolutionCount <= first_resolutions_.size())
return; // Someone just added the last item.
- if (ContainsKey(first_resolutions_, navigation_info.url()))
- return; // We already have this hostname listed.
- first_resolutions_[navigation_info.url()] = navigation_info;
+
+ // TODO(jar): Switch to using speculative_interceptor_ instead of
+ // PrefetchObserver.
+ bool is_ssl(443 == port);
+ std::string url_spec = is_ssl ? "https://" : "http://";
+ url_spec += host;
+ url_spec += ":";
+ url_spec += IntToString(port);
+
+ GURL url(url_spec);
+ first_resolutions_.insert(url);
}
void PrefetchObserver::GetInitialDnsResolutionList(ListValue* startup_list) {
@@ -403,23 +322,26 @@ void PrefetchObserver::GetInitialDnsResolutionList(ListValue* startup_list) {
startup_list->Clear();
DCHECK_EQ(0u, startup_list->GetSize());
startup_list->Append(new FundamentalValue(kPredictorStartupFormatVersion));
- for (FirstResolutionMap::iterator it = first_resolutions_.begin();
+ for (FirstResolutions::iterator it = first_resolutions_.begin();
it != first_resolutions_.end();
++it) {
- DCHECK(it->first == CanonicalizeUrl(it->first));
- startup_list->Append(new StringValue(it->first.spec()));
+ DCHECK(*it == CanonicalizeUrl(*it));
+ startup_list->Append(new StringValue(it->spec()));
}
}
void PrefetchObserver::DnsGetFirstResolutionsHtml(std::string* output) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
- UrlInfo::DnsInfoTable resolution_list;
+ UrlInfo::UrlInfoTable resolution_list;
{
- for (FirstResolutionMap::iterator it(first_resolutions_.begin());
+ for (FirstResolutions::iterator it(first_resolutions_.begin());
it != first_resolutions_.end();
it++) {
- resolution_list.push_back(it->second);
+ UrlInfo info;
+ info.SetUrl(*it);
+ // TODO(jar): Need to set time of info.GetDuration();
+ resolution_list.push_back(info);
}
}
UrlInfo::GetHtmlTable(resolution_list,
diff --git a/chrome/browser/net/predictor_api.h b/chrome/browser/net/predictor_api.h
index 9f91634..90603a3 100644
--- a/chrome/browser/net/predictor_api.h
+++ b/chrome/browser/net/predictor_api.h
@@ -59,10 +59,6 @@ void AnticipateUrl(const GURL& url, bool preconnectable);
void PredictorGetHtmlInfo(std::string* output);
//------------------------------------------------------------------------------
-// When we navigate, we may know in advance some other URLs that will need to
-// be resolved. This function initiates those side effects.
-void PredictSubresources(const GURL& url);
-
// When we navigate to a frame that may contain embedded resources, we may know
// in advance some other URLs that will need to be connected to (via TCP and
// sometimes SSL). This function initiates those connections
diff --git a/chrome/browser/net/predictor_unittest.cc b/chrome/browser/net/predictor_unittest.cc
index d60961e..9a3eea3 100644
--- a/chrome/browser/net/predictor_unittest.cc
+++ b/chrome/browser/net/predictor_unittest.cc
@@ -115,70 +115,6 @@ TEST_F(PredictorTest, StartupShutdownTest) {
testing_master->Shutdown();
}
-TEST_F(PredictorTest, BenefitLookupTest) {
- scoped_refptr<Predictor> testing_master = new Predictor(
- host_resolver_,
- default_max_queueing_delay_,
- PredictorInit::kMaxPrefetchConcurrentLookups,
- false);
-
- GURL goog("http://www.google.com:80"),
- goog2("http://gmail.google.com.com:80"),
- goog3("http://mail.google.com:80"),
- goog4("http://gmail.com:80");
- UrlInfo goog_info, goog2_info, goog3_info, goog4_info;
-
- // Simulate getting similar names from a network observer
- goog_info.SetUrl(goog);
- goog2_info.SetUrl(goog2);
- goog3_info.SetUrl(goog3);
- goog4_info.SetUrl(goog4);
-
- goog_info.SetStartedState();
- goog2_info.SetStartedState();
- goog3_info.SetStartedState();
- goog4_info.SetStartedState();
-
- goog_info.SetFinishedState(true);
- goog2_info.SetFinishedState(true);
- goog3_info.SetFinishedState(true);
- goog4_info.SetFinishedState(true);
-
- UrlList names;
- names.push_back(goog);
- names.push_back(goog2);
- names.push_back(goog3);
- names.push_back(goog4);
-
- testing_master->ResolveList(names, UrlInfo::PAGE_SCAN_MOTIVATED);
-
- WaitForResolution(testing_master, names);
-
- EXPECT_TRUE(testing_master->WasFound(goog));
- EXPECT_TRUE(testing_master->WasFound(goog2));
- EXPECT_TRUE(testing_master->WasFound(goog3));
- EXPECT_TRUE(testing_master->WasFound(goog4));
-
- // With the mock DNS, each of these should have taken some time, and hence
- // shown a benefit (i.e., prefetch cost more than network access time).
-
- GURL referer; // Null host.
-
- // Simulate actual navigation, and acrue the benefit for "helping" the DNS
- // part of the navigation.
- EXPECT_TRUE(testing_master->AccruePrefetchBenefits(referer, &goog_info));
- EXPECT_TRUE(testing_master->AccruePrefetchBenefits(referer, &goog2_info));
- EXPECT_TRUE(testing_master->AccruePrefetchBenefits(referer, &goog3_info));
- EXPECT_TRUE(testing_master->AccruePrefetchBenefits(referer, &goog4_info));
-
- // Benefits can ONLY be reported once (for the first navigation).
- EXPECT_FALSE(testing_master->AccruePrefetchBenefits(referer, &goog_info));
- EXPECT_FALSE(testing_master->AccruePrefetchBenefits(referer, &goog2_info));
- EXPECT_FALSE(testing_master->AccruePrefetchBenefits(referer, &goog3_info));
- EXPECT_FALSE(testing_master->AccruePrefetchBenefits(referer, &goog4_info));
-
- testing_master->Shutdown();
-}
TEST_F(PredictorTest, ShutdownWhenResolutionIsPendingTest) {
scoped_refptr<net::WaitingHostResolverProc> resolver_proc =
@@ -327,7 +263,7 @@ static ListValue* FindSerializationMotivation(
CHECK_LT(0u, referral_list.GetSize()); // Room for version.
int format_version = -1;
CHECK(referral_list.GetInteger(0, &format_version));
- CHECK_EQ(Predictor::DNS_REFERRER_VERSION, format_version);
+ CHECK_EQ(Predictor::PREDICTOR_REFERRER_VERSION, format_version);
ListValue* motivation_list(NULL);
for (size_t i = 1; i < referral_list.GetSize(); ++i) {
referral_list.GetList(i, &motivation_list);
@@ -342,17 +278,16 @@ static ListValue* FindSerializationMotivation(
// Create a new empty serialization list.
static ListValue* NewEmptySerializationList() {
ListValue* list = new ListValue;
- list->Append(new FundamentalValue(Predictor::DNS_REFERRER_VERSION));
+ list->Append(new FundamentalValue(Predictor::PREDICTOR_REFERRER_VERSION));
return list;
}
-// Add a motivating_host and a subresource_host to a serialized list, using
+// Add a motivating_url and a subresource_url to a serialized list, using
// this given latency. This is a helper function for quickly building these
// lists.
static void AddToSerializedList(const GURL& motivation,
const GURL& subresource,
- int latency,
- double rate,
+ double use_rate,
ListValue* referral_list ) {
// Find the motivation if it is already used.
ListValue* motivation_list = FindSerializationMotivation(motivation,
@@ -377,8 +312,7 @@ static void AddToSerializedList(const GURL& motivation,
// existing value(s) will be added to the referrer.
subresource_list->Append(new StringValue(subresource.spec()));
- subresource_list->Append(new FundamentalValue(latency));
- subresource_list->Append(new FundamentalValue(rate));
+ subresource_list->Append(new FundamentalValue(use_rate));
}
static const int kLatencyNotFound = -1;
@@ -386,12 +320,11 @@ static const int kLatencyNotFound = -1;
// For a given motivation, and subresource, find what latency is currently
// listed. This assume a well formed serialization, which has at most one such
// entry for any pair of names. If no such pair is found, then return false.
-// Data is written into rate and latency arguments.
+// Data is written into use_rate arguments.
static bool GetDataFromSerialization(const GURL& motivation,
const GURL& subresource,
const ListValue& referral_list,
- double* rate,
- int* latency) {
+ double* use_rate) {
ListValue* motivation_list = FindSerializationMotivation(motivation,
referral_list);
if (!motivation_list)
@@ -401,8 +334,7 @@ static bool GetDataFromSerialization(const GURL& motivation,
for (size_t i = 0; i < subresource_list->GetSize();) {
std::string url_spec;
EXPECT_TRUE(subresource_list->GetString(i++, &url_spec));
- EXPECT_TRUE(subresource_list->GetInteger(i++, latency));
- EXPECT_TRUE(subresource_list->GetReal(i++, rate));
+ EXPECT_TRUE(subresource_list->GetReal(i++, use_rate));
if (subresource == GURL(url_spec)) {
return true;
}
@@ -423,7 +355,7 @@ TEST_F(PredictorTest, ReferrerSerializationNilTest) {
EXPECT_EQ(1U, referral_list->GetSize());
EXPECT_FALSE(GetDataFromSerialization(
GURL("http://a.com:79"), GURL("http://b.com:78"),
- *referral_list.get(), NULL, NULL));
+ *referral_list.get(), NULL));
predictor->Shutdown();
}
@@ -438,25 +370,21 @@ TEST_F(PredictorTest, ReferrerSerializationSingleReferrerTest) {
false);
const GURL motivation_url("http://www.google.com:91");
const GURL subresource_url("http://icons.google.com:90");
- const int kLatency = 3;
- const double kRate = 23.4;
+ const double kUseRate = 23.4;
scoped_ptr<ListValue> referral_list(NewEmptySerializationList());
AddToSerializedList(motivation_url, subresource_url,
- kLatency, kRate, referral_list.get());
+ kUseRate, referral_list.get());
predictor->DeserializeReferrers(*referral_list.get());
ListValue recovered_referral_list;
predictor->SerializeReferrers(&recovered_referral_list);
EXPECT_EQ(2U, recovered_referral_list.GetSize());
- int latency;
double rate;
EXPECT_TRUE(GetDataFromSerialization(
- motivation_url, subresource_url, recovered_referral_list, &rate,
- &latency));
- EXPECT_EQ(rate, kRate);
- EXPECT_EQ(latency, kLatency);
+ motivation_url, subresource_url, recovered_referral_list, &rate));
+ EXPECT_EQ(rate, kUseRate);
predictor->Shutdown();
}
@@ -470,99 +398,73 @@ TEST_F(PredictorTest, ReferrerSerializationTrimTest) {
GURL motivation_url("http://www.google.com:110");
GURL icon_subresource_url("http://icons.google.com:111");
- const int kLatencyIcon = 10;
- const double kRateIcon = 0.; // User low rate, so latency will dominate.
+ const double kRateIcon = 16.0 * Predictor::kPersistWorthyExpectedValue;
GURL img_subresource_url("http://img.google.com:118");
- const int kLatencyImg = 3;
- const double kRateImg = 0.;
+ const double kRateImg = 8.0 * Predictor::kPersistWorthyExpectedValue;
scoped_ptr<ListValue> referral_list(NewEmptySerializationList());
AddToSerializedList(
- motivation_url, icon_subresource_url,
- kLatencyIcon, kRateIcon, referral_list.get());
+ motivation_url, icon_subresource_url, kRateIcon, referral_list.get());
AddToSerializedList(
- motivation_url, img_subresource_url,
- kLatencyImg, kRateImg, referral_list.get());
+ motivation_url, img_subresource_url, kRateImg, referral_list.get());
predictor->DeserializeReferrers(*referral_list.get());
ListValue recovered_referral_list;
predictor->SerializeReferrers(&recovered_referral_list);
EXPECT_EQ(2U, recovered_referral_list.GetSize());
- int latency;
double rate;
EXPECT_TRUE(GetDataFromSerialization(
motivation_url, icon_subresource_url, recovered_referral_list,
- &rate, &latency));
- EXPECT_EQ(latency, kLatencyIcon);
+ &rate));
EXPECT_EQ(rate, kRateIcon);
EXPECT_TRUE(GetDataFromSerialization(
- motivation_url, img_subresource_url, recovered_referral_list,
- &rate, &latency));
- EXPECT_EQ(latency, kLatencyImg);
+ motivation_url, img_subresource_url, recovered_referral_list, &rate));
EXPECT_EQ(rate, kRateImg);
- // Each time we Trim, the latency figures should reduce by a factor of two,
- // until they both are 0, an then a trim will delete the whole entry.
+ // Each time we Trim, the user_rate figures should reduce by a factor of two,
+ // until they both are small, an then a trim will delete the whole entry.
predictor->TrimReferrers();
predictor->SerializeReferrers(&recovered_referral_list);
EXPECT_EQ(2U, recovered_referral_list.GetSize());
EXPECT_TRUE(GetDataFromSerialization(
- motivation_url, icon_subresource_url, recovered_referral_list,
- &rate, &latency));
- EXPECT_EQ(latency, kLatencyIcon / 2);
- EXPECT_EQ(rate, kRateIcon);
+ motivation_url, icon_subresource_url, recovered_referral_list, &rate));
+ EXPECT_EQ(rate, kRateIcon / 2);
EXPECT_TRUE(GetDataFromSerialization(
- motivation_url, img_subresource_url, recovered_referral_list,
- &rate, &latency));
- EXPECT_EQ(latency, kLatencyImg / 2);
- EXPECT_EQ(rate, kRateImg);
+ motivation_url, img_subresource_url, recovered_referral_list, &rate));
+ EXPECT_EQ(rate, kRateImg / 2);
predictor->TrimReferrers();
predictor->SerializeReferrers(&recovered_referral_list);
EXPECT_EQ(2U, recovered_referral_list.GetSize());
EXPECT_TRUE(GetDataFromSerialization(
- motivation_url, icon_subresource_url, recovered_referral_list,
- &rate, &latency));
- EXPECT_EQ(latency, kLatencyIcon / 4);
- EXPECT_EQ(rate, kRateIcon);
- // Img is down to zero, but we don't delete it yet.
+ motivation_url, icon_subresource_url, recovered_referral_list, &rate));
+ EXPECT_EQ(rate, kRateIcon / 4);
EXPECT_TRUE(GetDataFromSerialization(
- motivation_url, img_subresource_url, recovered_referral_list,
- &rate, &latency));
- EXPECT_EQ(kLatencyImg / 4, 0);
- EXPECT_EQ(latency, kLatencyImg / 4);
- EXPECT_EQ(rate, kRateImg);
+ motivation_url, img_subresource_url, recovered_referral_list, &rate));
+ EXPECT_EQ(rate, kRateImg / 4);
predictor->TrimReferrers();
predictor->SerializeReferrers(&recovered_referral_list);
EXPECT_EQ(2U, recovered_referral_list.GetSize());
EXPECT_TRUE(GetDataFromSerialization(
- motivation_url, icon_subresource_url, recovered_referral_list,
- &rate, &latency));
- EXPECT_EQ(latency, kLatencyIcon / 8);
- EXPECT_EQ(rate, kRateIcon);
+ motivation_url, icon_subresource_url, recovered_referral_list, &rate));
+ EXPECT_EQ(rate, kRateIcon / 8);
- // Img is down to zero, but we don't delete it yet.
- EXPECT_TRUE(GetDataFromSerialization(
- motivation_url, img_subresource_url, recovered_referral_list,
- &rate, &latency));
- EXPECT_EQ(kLatencyImg / 8, 0);
- EXPECT_EQ(latency, kLatencyImg / 8);
- EXPECT_EQ(rate, kRateImg);
+ // Img is below threshold, and so it gets deleted.
+ EXPECT_FALSE(GetDataFromSerialization(
+ motivation_url, img_subresource_url, recovered_referral_list, &rate));
predictor->TrimReferrers();
predictor->SerializeReferrers(&recovered_referral_list);
// Icon is also trimmed away, so entire set gets discarded.
EXPECT_EQ(1U, recovered_referral_list.GetSize());
EXPECT_FALSE(GetDataFromSerialization(
- motivation_url, icon_subresource_url, recovered_referral_list,
- &rate, &latency));
+ motivation_url, icon_subresource_url, recovered_referral_list, &rate));
EXPECT_FALSE(GetDataFromSerialization(
- motivation_url, img_subresource_url, recovered_referral_list,
- &rate, &latency));
+ motivation_url, img_subresource_url, recovered_referral_list, &rate));
predictor->Shutdown();
}
diff --git a/chrome/browser/net/referrer.cc b/chrome/browser/net/referrer.cc
index 936d25b..b5d8c82 100644
--- a/chrome/browser/net/referrer.cc
+++ b/chrome/browser/net/referrer.cc
@@ -7,23 +7,24 @@
#include <limits.h>
#include "base/logging.h"
+#include "chrome/browser/net/predictor.h"
namespace chrome_browser_net {
//------------------------------------------------------------------------------
// Smoothing parameter for updating subresource_use_rate_.
-// We always combine our old expected value, weighted by some factor, with the
-// new expected value Enew. The new "expected value" is the number of actual
-// connections made due to the curernt navigations.
-// This means the formula (in a concise form) is:
-// Eupdated = Eold * W + Enew * (1 - W)
+// We always combine our old expected value, weighted by some factor W (we use
+// kWeightingForOldExpectedValue), with the new expected value Enew. The new
+// "expected value" is the number of actual connections made due to the current
+// navigations.
// That means that IF we end up needing to connect, we should apply the formula:
-// Pupdated = Pold * W + Enew * (1 - W)
-// If we visit the containing url, but don't end up needing a connection:
-// Pupdated = Pold * W
-// To achive the above upating algorithm, we end up doing the multiplication
-// by W every time we contemplate doing a preconneciton (i.e., when we navigate
+// Eupdated = Eold * W + Enew * (1 - W)
+// If we visit the containing url, but don't end up needing a connection, then
+// Enew == 0, so we use the formula:
+// Eupdated = Eold * W
+// To achieve the above updating algorithm, we end up doing the multiplication
+// by W every time we contemplate doing a preconnection (i.e., when we navigate
// to the containing URL, and consider doing a preconnection), and then IFF we
// learn that we really needed a connection to the subresource, we complete the
// above algorithm by adding the (1 - W) for each connection we make.
@@ -32,13 +33,14 @@ namespace chrome_browser_net {
// 1.0.
static const double kWeightingForOldExpectedValue = 0.66;
-// The expected value needed before we actually do a preconnection.
-static const double kPreconnectWorthyExpectedValue = 0.7;
-
-// The expected value that we'll need a preconnection when we first see the
-// subresource getting fetched. Very conservative is 0.0, which will mean that
-// we have to wait for a while before using preconnection... but we do persist
-// results, so we'll have the learned answer in the long run.
+// To estimate the expected value of the number of connections that we'll need
+// when a referrer is navigated to, we start with the following rather low
+// initial value. Each time we do indeed (again) need the subresource, this
+// value will get increased. Each time we navigate to the refererrer but never
+// end up needing this subresource, the value will decrease.
+// Very conservative is 0.0, which will mean that we have to wait for a while
+// before doing much speculative acvtivity... but we do persist results, so
+// we'll save the asymptotic (correct?) learned answer in the long run.
static const double kInitialExpectedValue = 0.0;
// static
@@ -71,71 +73,43 @@ void Referrer::SuggestHost(const GURL& url) {
void Referrer::DeleteLeastUseful() {
// Find the item with the lowest value. Most important is preconnection_rate,
- // next is latency savings, and last is lifetime (age).
+ // and least is lifetime (age).
GURL least_useful_url;
double lowest_rate_seen = 0.0;
// We use longs for durations because we will use multiplication on them.
- int64 lowest_latency_seen = 0; // Duration in milliseconds.
int64 least_useful_lifetime = 0; // Duration in milliseconds.
const base::Time kNow(base::Time::Now()); // Avoid multiple calls.
for (SubresourceMap::iterator it = begin(); it != end(); ++it) {
int64 lifetime = (kNow - it->second.birth_time()).InMilliseconds();
- int64 latency = it->second.latency().InMilliseconds();
double rate = it->second.subresource_use_rate();
if (least_useful_url.has_host()) {
if (rate > lowest_rate_seen)
continue;
- if (!latency && !lowest_latency_seen) {
- // Older name is less useful.
- if (lifetime <= least_useful_lifetime)
- continue;
- } else {
- // Compare the ratios:
- // latency/lifetime
- // vs.
- // lowest_latency_seen/least_useful_lifetime
- // by cross multiplying (to avoid integer division hassles). Overflow's
- // won't happen until both latency and lifetime pass about 49 days.
- if (latency * least_useful_lifetime >
- lowest_latency_seen * lifetime) {
- continue;
- }
- }
+ if (lifetime <= least_useful_lifetime)
+ continue;
}
least_useful_url = it->first;
lowest_rate_seen = rate;
- lowest_latency_seen = latency;
least_useful_lifetime = lifetime;
}
- erase(least_useful_url);
- // Note: there is a small chance that we will discard a least_useful_url
- // that is currently being prefetched because it *was* in this referer list.
- // In that case, when a benefit appears in AccrueValue() below, we are careful
- // to check before accessing the member.
-}
-
-void Referrer::AccrueValue(const base::TimeDelta& delta,
- const GURL& url) {
- SubresourceMap::iterator it = find(url);
- // Be careful that we weren't evicted from this referrer in DeleteLeastUseful.
- if (it != end())
- it->second.AccrueValue(delta);
+ if (least_useful_url.has_host())
+ erase(least_useful_url);
}
bool Referrer::Trim() {
- bool has_some_latency_left = false;
+ std::vector<GURL> discarded_urls;
for (SubresourceMap::iterator it = begin(); it != end(); ++it)
- if (it->second.Trim())
- has_some_latency_left = true;
- return has_some_latency_left;
+ if (!it->second.Trim())
+ discarded_urls.push_back(it->first);
+ for (size_t i = 0; i < discarded_urls.size(); ++i)
+ erase(discarded_urls[i]);
+ return size() > 0;
}
bool ReferrerValue::Trim() {
- int64 latency_ms = latency_.InMilliseconds() / 2;
- latency_ = base::TimeDelta::FromMilliseconds(latency_ms);
- return latency_ms > 0 ||
- subresource_use_rate_ > kPreconnectWorthyExpectedValue / 2;
+ subresource_use_rate_ /= 2.0;
+ return subresource_use_rate_ > Predictor::kPersistWorthyExpectedValue;
}
@@ -148,22 +122,17 @@ void Referrer::Deserialize(const Value& value) {
std::string url_spec;
if (!subresource_list->GetString(index++, &url_spec))
return;
- int latency_ms;
- if (!subresource_list->GetInteger(index++, &latency_ms))
- return;
double rate;
if (!subresource_list->GetReal(index++, &rate))
return;
GURL url(url_spec);
- base::TimeDelta latency = base::TimeDelta::FromMilliseconds(latency_ms);
// TODO(jar): We could be more direct, and change birth date or similar to
// show that this is a resurrected value we're adding in. I'm not yet sure
// of how best to optimize the learning and pruning (Trim) algorithm at this
// level, so for now, we just suggest subresources, which leaves them all
// with the same birth date (typically start of process).
SuggestHost(url);
- AccrueValue(latency, url);
(*this)[url].SetSubresourceUseRate(rate);
}
}
@@ -172,21 +141,10 @@ Value* Referrer::Serialize() const {
ListValue* subresource_list(new ListValue);
for (const_iterator it = begin(); it != end(); ++it) {
StringValue* url_spec(new StringValue(it->first.spec()));
- int latency_integer = static_cast<int>(it->second.latency().
- InMilliseconds());
- // Watch out for overflow in the above static_cast! Check to see if we went
- // negative, and just use a "big" value. The value seems unimportant once
- // we get to such high latencies. Probable cause of high latency is a bug
- // in other code, so also do a DCHECK.
- DCHECK_GE(latency_integer, 0);
- if (latency_integer < 0)
- latency_integer = INT_MAX;
- FundamentalValue* latency(new FundamentalValue(latency_integer));
FundamentalValue* rate(new FundamentalValue(
it->second.subresource_use_rate()));
subresource_list->Append(url_spec);
- subresource_list->Append(latency);
subresource_list->Append(rate);
}
return subresource_list;
@@ -198,6 +156,7 @@ ReferrerValue::ReferrerValue()
: birth_time_(base::Time::Now()),
navigation_count_(0),
preconnection_count_(0),
+ preresolution_count_(0),
subresource_use_rate_(kInitialExpectedValue) {
}
@@ -208,15 +167,12 @@ void ReferrerValue::SubresourceIsNeeded() {
subresource_use_rate_ += 1 - kWeightingForOldExpectedValue;
}
-bool ReferrerValue::IsPreconnectWorthDoing() {
- bool preconnecting = kPreconnectWorthyExpectedValue < subresource_use_rate_;
- if (preconnecting)
- ++preconnection_count_;
+void ReferrerValue::ReferrerWasObserved() {
subresource_use_rate_ *= kWeightingForOldExpectedValue;
// Note: the use rate is temporarilly possibly incorect, as we need to find
// out if we really end up connecting. This will happen in a few hundred
// milliseconds (when content arrives, etc.).
- return preconnecting;
+ // Value of subresource_use_rate_ should be sampled before this call.
}
} // namespace chrome_browser_net
diff --git a/chrome/browser/net/referrer.h b/chrome/browser/net/referrer.h
index 267648a..2e43f89 100644
--- a/chrome/browser/net/referrer.h
+++ b/chrome/browser/net/referrer.h
@@ -38,28 +38,32 @@ class ReferrerValue {
// Used during deserialization.
void SetSubresourceUseRate(double rate) { subresource_use_rate_ = rate; }
- base::TimeDelta latency() const { return latency_; }
base::Time birth_time() const { return birth_time_; }
- void AccrueValue(const base::TimeDelta& delta) { latency_ += delta; }
- // Record the fact that we navigated to the associated subresource URL.
+ // Record the fact that we navigated to the associated subresource URL. This
+ // will increase the value of the expected subresource_use_rate_
void SubresourceIsNeeded();
- // Evaluate if it is worth making this preconnection, and return true if it
- // seems worthwhile. As a side effect, we also tally the proconnection for
- // statistical purposes only.
- bool IsPreconnectWorthDoing();
+ // Record the fact that the referrer of this subresource was observed. This
+ // will diminish the expected subresource_use_rate_ (and will only be
+ // counteracted later if we really needed this subresource as a consequence
+ // of our associated referrer.)
+ void ReferrerWasObserved();
int64 navigation_count() const { return navigation_count_; }
- int64 preconnection_count() const { return preconnection_count_; }
double subresource_use_rate() const { return subresource_use_rate_; }
- // Reduce the latency figure by a factor of 2, and return true if any latency
- // remains.
+ int64 preconnection_count() const { return preconnection_count_; }
+ void IncrementPreconnectionCount() { ++preconnection_count_; }
+
+ int64 preresolution_count() const { return preresolution_count_; }
+ void preresolution_increment() { ++preresolution_count_; }
+
+ // Reduce the latency figure by a factor of 2, and return true if it still has
+ // subresources that could potentially be used.
bool Trim();
private:
- base::TimeDelta latency_; // Accumulated DNS resolution latency savings.
const base::Time birth_time_;
// The number of times this item was navigated to with the fixed referrer.
@@ -69,7 +73,12 @@ class ReferrerValue {
// referrer.
int64 preconnection_count_;
- // A smoothed estimate of the probability that a connection will be needed.
+ // The number of times this item was pre-resolved (via DNS) as a consequence
+ // of its referrer.
+ int64 preresolution_count_;
+
+ // A smoothed estimate of the expected number of connections that will be made
+ // to this subresource.
double subresource_use_rate_;
};
@@ -99,14 +108,9 @@ class Referrer : public SubresourceMap {
// discarded to make room for this insertion.
void SuggestHost(const GURL& url);
- // Record additional usefulness of having this url in the list.
- // Value is expressed as positive latency of amount delta.
- void AccrueValue(const base::TimeDelta& delta,
- const GURL& url);
-
- // Trim the Referrer, by first diminishing (scaling down) the latency for each
- // ReferredValue.
- // Returns true if there are any referring names with some latency left.
+ // Trim the Referrer, by first diminishing (scaling down) the subresource
+ // use expectation for each ReferredValue.
+ // Returns true if there are any referring names left.
bool Trim();
// Provide methods for persisting, and restoring contents into a Value class.
diff --git a/chrome/browser/net/url_info.cc b/chrome/browser/net/url_info.cc
index fab27ad..a92f5a2 100644
--- a/chrome/browser/net/url_info.cc
+++ b/chrome/browser/net/url_info.cc
@@ -131,11 +131,6 @@ void UrlInfo::SetFoundState() {
resolve_duration_, kMaxNonNetworkDnsLookupDuration,
TimeDelta::FromMinutes(15), 100);
}
-
- // Record potential beneficial time, and maybe we'll get a cache hit.
- // We keep the maximum, as the warming we did earlier may still be
- // helping with a cache upstream in DNS resolution.
- benefits_remaining_ = std::max(resolve_duration_, benefits_remaining_);
}
sequence_number_ = sequence_counter++;
DLogResultsStats("DNS PrefetchFound");
@@ -147,29 +142,11 @@ void UrlInfo::SetNoSuchNameState() {
resolve_duration_ = GetDuration();
if (kMaxNonNetworkDnsLookupDuration <= resolve_duration_) {
DHISTOGRAM_TIMES("DNS.PrefetchNotFoundName", resolve_duration_);
- // Record potential beneficial time, and maybe we'll get a cache hit.
- benefits_remaining_ = std::max(resolve_duration_, benefits_remaining_);
}
sequence_number_ = sequence_counter++;
DLogResultsStats("DNS PrefetchNotFound");
}
-void UrlInfo::SetStartedState() {
- DCHECK(PENDING == state_);
- state_ = STARTED;
- queue_duration_ = resolve_duration_ = TimeDelta(); // 0ms.
- SetMotivation(NO_PREFETCH_MOTIVATION);
- GetDuration(); // Set time.
-}
-
-void UrlInfo::SetFinishedState(bool was_resolved) {
- DCHECK(STARTED == state_);
- state_ = was_resolved ? FINISHED : FINISHED_UNRESOLVED;
- resolve_duration_ = GetDuration();
- // TODO(jar): Sequence number should be incremented in prefetched HostInfo.
- DLogResultsStats("DNS HTTP Finished");
-}
-
void UrlInfo::SetUrl(const GURL& url) {
if (url_.is_empty()) // Not yet initialized.
url_ = url;
@@ -195,65 +172,12 @@ bool UrlInfo::IsStillCached() const {
return time_since_resolution < kCacheExpirationDuration;
}
-// Compare the actual navigation DNS latency found in navigation_info, to the
-// previously prefetched info.
-DnsBenefit UrlInfo::AccruePrefetchBenefits(UrlInfo* navigation_info) {
- DCHECK(FINISHED == navigation_info->state_ ||
- FINISHED_UNRESOLVED == navigation_info->state_);
- DCHECK(navigation_info->url() == url_);
-
- if ((0 == benefits_remaining_.InMilliseconds()) ||
- (FOUND != state_ && NO_SUCH_NAME != state_)) {
- if (FINISHED == navigation_info->state_)
- UMA_HISTOGRAM_LONG_TIMES("DNS.IndependentNavigation",
- navigation_info->resolve_duration_);
- else
- UMA_HISTOGRAM_LONG_TIMES("DNS.IndependentFailedNavigation",
- navigation_info->resolve_duration_);
- return PREFETCH_NO_BENEFIT;
- }
-
- TimeDelta benefit = benefits_remaining_ - navigation_info->resolve_duration_;
- navigation_info->benefits_remaining_ = benefits_remaining_;
- benefits_remaining_ = TimeDelta(); // We used up all our benefits here.
-
- navigation_info->motivation_ = motivation_;
- if (LEARNED_REFERAL_MOTIVATED == motivation_ ||
- STATIC_REFERAL_MOTIVATED == motivation_)
- navigation_info->referring_url_ = referring_url_;
-
- if (navigation_info->resolve_duration_ > kMaxNonNetworkDnsLookupDuration) {
- // Our precache effort didn't help since HTTP stack hit the network.
- UMA_HISTOGRAM_LONG_TIMES("DNS.PrefetchCacheEvictionL", resolve_duration_);
- DLogResultsStats("DNS PrefetchCacheEviction");
- return PREFETCH_CACHE_EVICTION;
- }
-
- if (NO_SUCH_NAME == state_) {
- UMA_HISTOGRAM_LONG_TIMES("DNS.PrefetchNegativeHitL", benefit);
- DLogResultsStats("DNS PrefetchNegativeHit");
- return PREFETCH_NAME_NONEXISTANT;
- }
-
- DCHECK_EQ(FOUND, state_);
- if (LEARNED_REFERAL_MOTIVATED == motivation_ ||
- STATIC_REFERAL_MOTIVATED == motivation_) {
- UMA_HISTOGRAM_TIMES("DNS.PrefetchReferredPositiveHit", benefit);
- DLogResultsStats("DNS PrefetchReferredPositiveHit");
- } else {
- UMA_HISTOGRAM_LONG_TIMES("DNS.PrefetchPositiveHitL", benefit);
- DLogResultsStats("DNS PrefetchPositiveHit");
- }
- return PREFETCH_NAME_FOUND;
-}
-
void UrlInfo::DLogResultsStats(const char* message) const {
if (!detailed_logging_enabled)
return;
DLOG(INFO) << "\t" << message << "\tq="
<< queue_duration().InMilliseconds() << "ms,\tr="
<< resolve_duration().InMilliseconds() << "ms\tp="
- << benefits_remaining_.InMilliseconds() << "ms\tseq="
<< sequence_number_
<< "\t" << url_.spec();
}
@@ -329,7 +253,7 @@ static std::string HoursMinutesSeconds(int seconds) {
}
// static
-void UrlInfo::GetHtmlTable(const DnsInfoTable host_infos,
+void UrlInfo::GetHtmlTable(const UrlInfoTable host_infos,
const char* description,
const bool brief,
std::string* output) {
@@ -344,53 +268,29 @@ void UrlInfo::GetHtmlTable(const DnsInfoTable host_infos,
return;
}
- const char* row_format = "<tr align=right><td>%s</td>"
- "<td>%d</td><td>%d</td><td>%s</td><td>%s</td></tr>";
+ output->append("<br><table border=1>"
+ "<tr><th>Host name</th>"
+ "<th>How long ago<br>(HH:MM:SS)</th>"
+ "<th>Motivation</th>"
+ "</tr>");
- output->append("<br><table border=1>");
- StringAppendF(output,
- "<tr><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th></tr>",
- "Host name", "Applicable Prefetch<br>Time (ms)",
- "Recent Resolution<br>Time(ms)", "How long ago<br>(HH:MM:SS)",
- "Motivation");
+ const char* row_format = "<tr align=right><td>%s</td>" // Host name.
+ "<td>%s</td>" // How long ago.
+ "<td>%s</td>" // Motivation.
+ "</tr>";
// Print bulk of table, and gather stats at same time.
- MinMaxAverage queue, resolve, preresolve, when;
+ MinMaxAverage queue, when;
TimeTicks current_time = TimeTicks::Now();
- for (DnsInfoTable::const_iterator it(host_infos.begin());
+ for (UrlInfoTable::const_iterator it(host_infos.begin());
it != host_infos.end(); it++) {
queue.sample((it->queue_duration_.InMilliseconds()));
StringAppendF(output, row_format,
RemoveJs(it->url_.spec()).c_str(),
- preresolve.sample((it->benefits_remaining_.InMilliseconds())),
- resolve.sample((it->resolve_duration_.InMilliseconds())),
HoursMinutesSeconds(when.sample(
(current_time - it->time_).InSeconds())).c_str(),
it->GetAsciiMotivation().c_str());
}
- // Write min, max, and average summary lines.
- if (host_infos.size() > 2) {
- output->append("<B>");
- StringAppendF(output, row_format,
- "<b>---minimum---</b>",
- preresolve.minimum(), resolve.minimum(),
- HoursMinutesSeconds(when.minimum()).c_str(), "");
- StringAppendF(output, row_format,
- "<b>---average---</b>",
- preresolve.average(), resolve.average(),
- HoursMinutesSeconds(when.average()).c_str(), "");
- StringAppendF(output, row_format,
- "<b>standard deviation</b>",
- preresolve.standard_deviation(),
- resolve.standard_deviation(), "n/a", "");
- StringAppendF(output, row_format,
- "<b>---maximum---</b>",
- preresolve.maximum(), resolve.maximum(),
- HoursMinutesSeconds(when.maximum()).c_str(), "");
- StringAppendF(output, row_format,
- "<b>-----SUM-----</b>",
- preresolve.sum(), resolve.sum(), "n/a", "");
- }
output->append("</table>");
#ifdef DEBUG
diff --git a/chrome/browser/net/url_info.h b/chrome/browser/net/url_info.h
index e9ee771..c2af6e9 100644
--- a/chrome/browser/net/url_info.h
+++ b/chrome/browser/net/url_info.h
@@ -29,14 +29,6 @@ namespace chrome_browser_net {
// Use command line switch to enable detailed logging.
void EnablePredictorDetailedLog(bool enable);
-enum DnsBenefit {
- PREFETCH_NO_BENEFIT, // Prefetch never hit the network. Name was pre-cached.
- PREFETCH_CACHE_EVICTION, // Prefetch used network, but so did HTTP stack.
- PREFETCH_NAME_NONEXISTANT, // Valuable prefetch of "name not found" was used.
- PREFETCH_NAME_FOUND, // Valuable prefetch was used.
- PREFETCH_OBLIVIOUS // No prefetch attempt was even made.
-};
-
class UrlInfo {
public:
// Reasons for a domain to be resolved.
@@ -55,6 +47,8 @@ class UrlInfo {
// TODO(jar): Support STATIC_REFERAL_MOTIVATED API and integration.
STATIC_REFERAL_MOTIVATED, // External database suggested this resolution.
LEARNED_REFERAL_MOTIVATED, // Prior navigation taught us this resolution.
+
+ MAX_MOTIVATED // Beyond all enums, for use in histogram bounding.
};
enum DnsProcessingState {
@@ -65,16 +59,13 @@ class UrlInfo {
ASSIGNED_BUT_MARKED, // Needs to be deleted as soon as it's resolved.
FOUND, // DNS resolution completed.
NO_SUCH_NAME, // DNS resolution completed.
- // When processed by the network stack during navigation, the states are:
- STARTED, // Resolution has begun for a navigation.
- FINISHED, // Resolution has completed for a navigation.
- FINISHED_UNRESOLVED}; // No resolution found, so navigation will fail.
+ };
static const base::TimeDelta kMaxNonNetworkDnsLookupDuration;
// The number of OS cache entries we can guarantee(?) before cache eviction
// might likely take place.
static const int kMaxGuaranteedDnsCacheSize = 50;
- typedef std::vector<UrlInfo> DnsInfoTable;
+ typedef std::vector<UrlInfo> UrlInfoTable;
static const base::TimeDelta kNullDuration;
@@ -85,7 +76,6 @@ class UrlInfo {
old_prequeue_state_(state_),
resolve_duration_(kNullDuration),
queue_duration_(kNullDuration),
- benefits_remaining_(),
sequence_number_(0),
motivation_(NO_PREFETCH_MOTIVATION),
was_linked_(false) {
@@ -108,9 +98,6 @@ class UrlInfo {
void SetPendingDeleteState();
void SetFoundState();
void SetNoSuchNameState();
- // The actual browsing resolution lifecycle.
- void SetStartedState();
- void SetFinishedState(bool was_resolved);
// Finish initialization. Must only be called once.
void SetUrl(const GURL& url);
@@ -136,13 +123,10 @@ class UrlInfo {
base::TimeDelta resolve_duration() const { return resolve_duration_;}
base::TimeDelta queue_duration() const { return queue_duration_;}
- base::TimeDelta benefits_remaining() const { return benefits_remaining_; }
-
- DnsBenefit AccruePrefetchBenefits(UrlInfo* navigation_info);
void DLogResultsStats(const char* message) const;
- static void GetHtmlTable(const DnsInfoTable host_infos,
+ static void GetHtmlTable(const UrlInfoTable host_infos,
const char* description,
const bool brief,
std::string* output);
@@ -182,8 +166,6 @@ class UrlInfo {
base::TimeDelta resolve_duration_;
// Time spent in queue.
base::TimeDelta queue_duration_;
- // Unused potential benefits of a prefetch.
- base::TimeDelta benefits_remaining_;
int sequence_number_; // Used to calculate potential of cache eviction.
static int sequence_counter; // Used to allocate sequence_number_'s.
diff --git a/chrome/browser/renderer_host/resource_dispatcher_host.cc b/chrome/browser/renderer_host/resource_dispatcher_host.cc
index b9a11c7..7e53a5e 100644
--- a/chrome/browser/renderer_host/resource_dispatcher_host.cc
+++ b/chrome/browser/renderer_host/resource_dispatcher_host.cc
@@ -425,8 +425,11 @@ void ResourceDispatcherHost::BeginRequest(
// EV certificate verification could be expensive. We don't want to spend
// time performing EV certificate verification on all resources because
// EV status is irrelevant to sub-frames and sub-resources.
- if (request_data.resource_type == ResourceType::MAIN_FRAME)
- load_flags |= net::LOAD_VERIFY_EV_CERT;
+ if (request_data.resource_type == ResourceType::MAIN_FRAME) {
+ load_flags |= net::LOAD_VERIFY_EV_CERT | net::LOAD_MAIN_FRAME;
+ } else if (request_data.resource_type == ResourceType::SUB_FRAME) {
+ load_flags |= net::LOAD_SUB_FRAME;
+ }
request->set_load_flags(load_flags);
request->set_context(context);
request->set_priority(DetermineRequestPriority(request_data.resource_type));
diff --git a/net/base/load_flags_list.h b/net/base/load_flags_list.h
index ff5e609..1125a3e 100644
--- a/net/base/load_flags_list.h
+++ b/net/base/load_flags_list.h
@@ -82,3 +82,12 @@ LOAD_FLAG(DO_NOT_SEND_AUTH_DATA, 1 << 18)
// This should only be used for testing (set by HttpNetworkTransaction).
LOAD_FLAG(IGNORE_ALL_CERT_ERRORS, 1 << 19)
+
+// Indicate that this is a top level frame, so that we don't assume it is a
+// subresource and speculatively pre-connect or pre-resolve when a referring
+// page is loaded.
+LOAD_FLAG(MAIN_FRAME, 1 << 20)
+
+// Indicate that this is a sub frame, and hence it might have subresources that
+// should be speculatively resolved, or even speculatively preconnected.
+LOAD_FLAG(SUB_FRAME, 1 << 21)