| 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..b51017d22d1cbb5f501b5153118151f314a7fff8 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,19 @@ void ResourcePrefetchPredictor::Observe(
|
| }
|
| }
|
|
|
| +void ResourcePrefetchPredictor::FinishedPrefetchForNavigation(
|
| + const NavigationID& navigation_id,
|
| + scoped_ptr<ResourcePrefetcher::RequestVector> requests) {
|
| + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| +
|
| + // Add the results to the results map.
|
| + ResourcePrefetcher::RequestVector* req = requests.release();
|
| + if (!results_map_.insert(std::make_pair(navigation_id, req)).second) {
|
| + DLOG(FATAL) << "Returning results for existing navigation.";
|
| + delete req;
|
| + }
|
| +}
|
| +
|
| void ResourcePrefetchPredictor::OnHistoryAndCacheLoaded() {
|
| CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| DCHECK_EQ(initialization_state_, INITIALIZING);
|
| @@ -565,6 +629,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 +672,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 +689,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 +699,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 +829,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 +931,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();
|
|
|