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

Unified Diff: chrome/browser/predictors/resource_prefetch_predictor.cc

Issue 10817004: Adds speculative prefetching of resources. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Addressing Dominich's comment. Created 8 years, 3 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/predictors/resource_prefetch_predictor.cc
diff --git a/chrome/browser/predictors/resource_prefetch_predictor.cc b/chrome/browser/predictors/resource_prefetch_predictor.cc
index 12fe48486fad10be3f3198f9c7959f23e8afe9e3..8d52a7369e22e23e8943ff4c39ca50d464ecfe6a 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor.cc
+++ b/chrome/browser/predictors/resource_prefetch_predictor.cc
@@ -21,6 +21,7 @@
#include "chrome/browser/history/url_database.h"
#include "chrome/browser/predictors/predictor_database.h"
#include "chrome/browser/predictors/predictor_database_factory.h"
+#include "chrome/browser/predictors/resource_prefetcher_manager.h"
#include "chrome/browser/prerender/prerender_field_trial.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_notification_types.h"
@@ -89,14 +90,6 @@ void RecordNavigationEvent(NavigationEvent event) {
namespace predictors {
-ResourcePrefetchPredictor::Config::Config()
- : max_navigation_lifetime_seconds(60),
- max_urls_to_track(500),
- min_url_visit_count(3),
- max_resources_per_entry(50),
- max_consecutive_misses(3) {
-}
-
ResourcePrefetchPredictor::URLRequestSummary::URLRequestSummary()
: resource_type(ResourceType::LAST_TYPE),
was_cached(false) {
@@ -122,13 +115,14 @@ ResourcePrefetchPredictor::UrlTableCacheValue::~UrlTableCacheValue() {
}
ResourcePrefetchPredictor::ResourcePrefetchPredictor(
- const Config& config,
+ const ResourcePrefetchPredictorConfig& config,
Profile* profile)
: profile_(profile),
config_(config),
initialization_state_(NOT_INITIALIZED),
tables_(PredictorDatabaseFactory::GetForProfile(
- profile)->resource_prefetch_tables()) {
+ profile)->resource_prefetch_tables()),
+ results_map_deleter_(&results_map_) {
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
notification_registrar_.Add(this,
@@ -139,9 +133,11 @@ ResourcePrefetchPredictor::ResourcePrefetchPredictor(
ResourcePrefetchPredictor::~ResourcePrefetchPredictor() {
}
-// static
-bool ResourcePrefetchPredictor::IsEnabled(Profile* profile) {
- return prerender::IsSpeculativeResourcePrefetchingLearningEnabled(profile);
+void ResourcePrefetchPredictor::Shutdown() {
+ if (prefetch_manager_) {
+ prefetch_manager_->ShutdownOnUIThread();
+ prefetch_manager_ = NULL;
+ }
}
void ResourcePrefetchPredictor::LazilyInitialize() {
@@ -358,15 +354,60 @@ void ResourcePrefetchPredictor::OnMainFrameRequest(
// New empty navigation entry.
inflight_navigations_.insert(std::make_pair(
request.navigation_id, std::vector<URLRequestSummary>()));
+
+ // If prefetching is enabled, and we can prefetch something, start
+ // prefetching.
+ if (!prefetch_manager_.get())
+ return;
+
+ const GURL& main_frame_url = request.navigation_id.main_frame_url;
+ const UrlTableCacheMap::const_iterator value_iter = url_table_cache_.find(
+ main_frame_url);
+ if (value_iter == url_table_cache_.end())
+ return;
+
+ const UrlTableCacheValue& value = value_iter->second;
+
+ scoped_ptr<ResourcePrefetcher::RequestVector> requests(
+ new ResourcePrefetcher::RequestVector);
+ for (UrlTableRowVector::const_iterator it = value.rows.begin();
+ it != value.rows.end(); ++it) {
+ float confidence = static_cast<float>(it->number_of_hits) /
+ (it->number_of_hits + it->number_of_misses);
+ if (confidence < config_.min_resource_confidence_to_trigger_prefetch ||
+ it->number_of_hits < config_.min_resource_hits_to_trigger_prefetch) {
+ continue;
+ }
+
+ ResourcePrefetcher::Request* req = new ResourcePrefetcher::Request(
+ it->resource_url);
+ requests->push_back(req);
+ }
+
+ if (requests->empty())
+ return;
+
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(&ResourcePrefetcherManager::MaybeAddPrefetch,
+ prefetch_manager_,
+ request.navigation_id,
+ base::Passed(&requests)));
}
void ResourcePrefetchPredictor::OnMainFrameResponse(
const URLRequestSummary& response) {
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (initialization_state_ != INITIALIZED)
+ return;
RecordNavigationEvent(NAVIGATION_EVENT_RESPONSE_STARTED);
- // TODO(shishir): The prefreshing will be stopped here.
+ if (prefetch_manager_.get())
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&ResourcePrefetcherManager::MaybeRemovePrefetch,
+ prefetch_manager_,
+ response.navigation_id));
}
void ResourcePrefetchPredictor::OnMainFrameRedirect(
@@ -438,6 +479,16 @@ void ResourcePrefetchPredictor::CleanupAbandonedNavigations(
++it;
}
}
+ for (ResultsMap::iterator it = results_map_.begin();
+ it != results_map_.end();) {
+ if (it->first.IsSameRenderer(navigation_id) ||
+ (time_now - it->first.creation_time > max_navigation_age)) {
+ delete it->second;
+ results_map_.erase(it++);
+ } else {
+ ++it;
+ }
+ }
}
void ResourcePrefetchPredictor::Observe(
@@ -516,6 +567,18 @@ void ResourcePrefetchPredictor::Observe(
}
}
+void ResourcePrefetchPredictor::FinishedPrefetchForNavigation(
+ const NavigationID& navigation_id,
+ ResourcePrefetcher::RequestVector* requests) {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ // Add the results to the results map.
+ if (!results_map_.insert(std::make_pair(navigation_id, requests)).second) {
+ DLOG(FATAL) << "Returning results for existing navigation.";
+ delete requests;
+ }
+}
+
void ResourcePrefetchPredictor::OnHistoryAndCacheLoaded() {
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK_EQ(initialization_state_, INITIALIZING);
@@ -565,6 +628,12 @@ void ResourcePrefetchPredictor::OnHistoryAndCacheLoaded() {
// TODO(shishir): Maybe listen for notifications for navigation being
// abandoned and cleanup the inflight_navigations_.
+ // Initialize the prefetch manager only if prefetching is enabled.
+ if (prerender::IsSpeculativeResourcePrefetchingEnabled(profile_)) {
+ prefetch_manager_ = new ResourcePrefetcherManager(
+ this, config_, profile_->GetRequestContext());
+ }
+
initialization_state_ = INITIALIZED;
}
@@ -602,7 +671,11 @@ void ResourcePrefetchPredictor::OnNavigationComplete(
RecordNavigationEvent(NAVIGATION_EVENT_ONLOAD_TRACKED_URL);
// Report any stats.
- MaybeReportAccuracyStats(navigation_id);
+ if (prefetch_manager_.get()) {
+ MaybeReportAccuracyStats(navigation_id);
+ } else {
+ MaybeReportSimulatedAccuracyStats(navigation_id);
+ }
// Update the URL table.
const GURL& main_frame_url = navigation_id.main_frame_url;
@@ -615,6 +688,8 @@ void ResourcePrefetchPredictor::OnNavigationComplete(
// Remove the navigation.
inflight_navigations_.erase(navigation_id);
+ delete results_map_[navigation_id];
+ results_map_.erase(navigation_id);
}
void ResourcePrefetchPredictor::LearnUrlNavigation(
@@ -623,7 +698,7 @@ void ResourcePrefetchPredictor::LearnUrlNavigation(
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (url_table_cache_.find(main_frame_url) == url_table_cache_.end()) {
- if (url_table_cache_.size() >= config_.max_urls_to_track)
+ if (static_cast<int>(url_table_cache_.size()) >= config_.max_urls_to_track)
RemoveAnEntryFromUrlDB();
url_table_cache_[main_frame_url].last_visit = base::Time::Now();
@@ -753,7 +828,7 @@ void ResourcePrefetchPredictor::RemoveAnEntryFromUrlDB() {
urls_to_delete));
}
-void ResourcePrefetchPredictor::MaybeReportAccuracyStats(
+void ResourcePrefetchPredictor::MaybeReportSimulatedAccuracyStats(
const NavigationID& navigation_id) const {
const GURL& main_frame_url = navigation_id.main_frame_url;
DCHECK(inflight_navigations_.find(navigation_id) !=
@@ -855,6 +930,130 @@ void ResourcePrefetchPredictor::ReportAccuracyHistograms(
#undef RPP_PREDICTED_HISTOGRAM_COUNTS
}
+void ResourcePrefetchPredictor::MaybeReportAccuracyStats(
+ const NavigationID& navigation_id) {
+ NavigationMap::iterator nav_it = inflight_navigations_.find(navigation_id);
+ DCHECK(nav_it != inflight_navigations_.end());
+
+ ResultsMap::iterator results_it = results_map_.find(navigation_id);
+ bool have_prefetch_results = results_it != results_map_.end();
+ UMA_HISTOGRAM_BOOLEAN("ResourcePrefetchPredictor.HavePrefetchResults",
+ have_prefetch_results);
+ if (!have_prefetch_results)
+ return;
+
+ // Annotate the results.
+ const std::vector<URLRequestSummary>& actual = nav_it->second;
+ ResourcePrefetcher::RequestVector* prefetched = results_it->second;
+
+ std::map<GURL, bool> actual_resources;
+ for (std::vector<URLRequestSummary>::const_iterator it = actual.begin();
+ it != actual.end(); ++it) {
+ actual_resources[it->resource_url] = it->was_cached;
+ }
+
+ int prefetch_cancelled = 0, prefetch_failed = 0, prefetch_not_started = 0;
+ // 'a_' -> actual, 'p_' -> predicted.
+ int p_cache_a_cache = 0, p_cache_a_network = 0, p_cache_a_notused = 0,
+ p_network_a_cache = 0, p_network_a_network = 0, p_network_a_notused = 0;
+
+ for (ResourcePrefetcher::RequestVector::iterator it = prefetched->begin();
+ it != prefetched->end(); ++it) {
+ ResourcePrefetcher::Request* req = *it;
+
+ // Set the usage states if the resource was actually used.
+ std::map<GURL, bool>::iterator actual_it = actual_resources.find(
+ req->resource_url);
+ if (actual_it != actual_resources.end()) {
+ if (actual_it->second) {
+ req->usage_status =
+ ResourcePrefetcher::Request::USAGE_STATUS_FROM_CACHE;
+ } else {
+ req->usage_status =
+ ResourcePrefetcher::Request::USAGE_STATUS_FROM_NETWORK;
+ }
+ }
+
+ switch (req->prefetch_status) {
+
+ // TODO(shishir): Add histogram for each cancellation reason.
+ case ResourcePrefetcher::Request::PREFETCH_STATUS_REDIRECTED:
+ case ResourcePrefetcher::Request::PREFETCH_STATUS_AUTH_REQUIRED:
+ case ResourcePrefetcher::Request::PREFETCH_STATUS_CERT_REQUIRED:
+ case ResourcePrefetcher::Request::PREFETCH_STATUS_CERT_ERROR:
+ case ResourcePrefetcher::Request::PREFETCH_STATUS_CANCELLED:
+ ++prefetch_cancelled;
+ break;
+
+ case ResourcePrefetcher::Request::PREFETCH_STATUS_FAILED:
+ ++prefetch_failed;
+ break;
+
+ case ResourcePrefetcher::Request::PREFETCH_STATUS_FROM_CACHE:
+ if (req->usage_status ==
+ ResourcePrefetcher::Request::USAGE_STATUS_FROM_CACHE)
+ ++p_cache_a_cache;
+ else if (req->usage_status ==
+ ResourcePrefetcher::Request::USAGE_STATUS_FROM_NETWORK)
+ ++p_cache_a_network;
+ else
+ ++p_cache_a_notused;
+ break;
+
+ case ResourcePrefetcher::Request::PREFETCH_STATUS_FROM_NETWORK:
+ if (req->usage_status ==
+ ResourcePrefetcher::Request::USAGE_STATUS_FROM_CACHE)
+ ++p_network_a_cache;
+ else if (req->usage_status ==
+ ResourcePrefetcher::Request::USAGE_STATUS_FROM_NETWORK)
+ ++p_network_a_network;
+ else
+ ++p_network_a_notused;
+ break;
+
+ case ResourcePrefetcher::Request::PREFETCH_STATUS_NOT_STARTED:
+ ++prefetch_not_started;
+ break;
+
+ case ResourcePrefetcher::Request::PREFETCH_STATUS_STARTED:
+ DLOG(FATAL) << "Invalid prefetch status";
+ break;
+ }
+ }
+
+ int total_prefetched = p_cache_a_cache + p_cache_a_network + p_cache_a_notused
+ + p_network_a_cache + p_network_a_network + p_network_a_notused;
+
+ UMA_HISTOGRAM_PERCENTAGE(
+ "ResourcePrefetchPredictor.PrefetchCancelled",
+ prefetch_cancelled * 100.0 / total_prefetched);
+ UMA_HISTOGRAM_PERCENTAGE(
+ "ResourcePrefetchPredictor.PrefetchFailed",
+ prefetch_failed * 100.0 / total_prefetched);
+ UMA_HISTOGRAM_PERCENTAGE(
+ "ResourcePrefetchPredictor.PrefetchFromCacheUsedFromCache",
+ p_cache_a_cache * 100.0 / total_prefetched);
+ UMA_HISTOGRAM_PERCENTAGE(
+ "ResourcePrefetchPredictor.PrefetchFromCacheUsedFromNetwork",
+ p_cache_a_network * 100.0 / total_prefetched);
+ UMA_HISTOGRAM_PERCENTAGE(
+ "ResourcePrefetchPredictor.PrefetchFromCacheNotUsed",
+ p_cache_a_notused * 100.0 / total_prefetched);
+ UMA_HISTOGRAM_PERCENTAGE(
+ "ResourcePrefetchPredictor.PrefetchFromNetworkUsedFromCache",
+ p_network_a_cache * 100.0 / total_prefetched);
+ UMA_HISTOGRAM_PERCENTAGE(
+ "ResourcePrefetchPredictor.PrefetchFromNetworkUsedFromNetwork",
+ p_network_a_network * 100.0 / total_prefetched);
+ UMA_HISTOGRAM_PERCENTAGE(
+ "ResourcePrefetchPredictor.PrefetchFromNetworkNotUsed",
+ p_network_a_notused * 100.0 / total_prefetched);
+
+ UMA_HISTOGRAM_PERCENTAGE(
+ "ResourcePrefetchPredictor.PrefetchNotStarted",
+ prefetch_not_started * 100.0 / (prefetch_not_started + total_prefetched));
+}
+
void ResourcePrefetchPredictor::DeleteAllUrls() {
inflight_navigations_.clear();
url_table_cache_.clear();

Powered by Google App Engine
This is Rietveld 408576698