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(); |