| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/predictors/resource_prefetch_predictor.h" | 5 #include "chrome/browser/predictors/resource_prefetch_predictor.h" |
| 6 | 6 |
| 7 #include <map> | 7 #include <map> |
| 8 #include <set> | 8 #include <set> |
| 9 #include <utility> | 9 #include <utility> |
| 10 | 10 |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 164 internal::kResourcePrefetchPredictorPrefetchHitsCountNotCached, | 164 internal::kResourcePrefetchPredictorPrefetchHitsCountNotCached, |
| 165 not_cached_hits_count); | 165 not_cached_hits_count); |
| 166 UMA_HISTOGRAM_COUNTS_10000( | 166 UMA_HISTOGRAM_COUNTS_10000( |
| 167 internal::kResourcePrefetchPredictorPrefetchHitsSize, hits_bytes / 1024); | 167 internal::kResourcePrefetchPredictorPrefetchHitsSize, hits_bytes / 1024); |
| 168 UMA_HISTOGRAM_COUNTS_10000( | 168 UMA_HISTOGRAM_COUNTS_10000( |
| 169 internal::kResourcePrefetchPredictorPrefetchMissesSize, | 169 internal::kResourcePrefetchPredictorPrefetchMissesSize, |
| 170 misses_bytes / 1024); | 170 misses_bytes / 1024); |
| 171 } | 171 } |
| 172 | 172 |
| 173 void ReportPredictionAccuracy( | 173 void ReportPredictionAccuracy( |
| 174 const std::vector<GURL>& predicted_urls, | 174 const ResourcePrefetchPredictor::Prediction& prediction, |
| 175 const ResourcePrefetchPredictor::PageRequestSummary& summary) { | 175 const ResourcePrefetchPredictor::PageRequestSummary& summary) { |
| 176 DCHECK(!predicted_urls.empty()); | 176 const std::vector<GURL>& predicted_urls = prediction.subresource_urls; |
| 177 | |
| 178 if (predicted_urls.empty() || summary.subresource_requests.empty()) | 177 if (predicted_urls.empty() || summary.subresource_requests.empty()) |
| 179 return; | 178 return; |
| 180 | 179 |
| 181 std::set<GURL> predicted_urls_set(predicted_urls.begin(), | 180 std::set<GURL> predicted_urls_set(predicted_urls.begin(), |
| 182 predicted_urls.end()); | 181 predicted_urls.end()); |
| 183 std::set<GURL> actual_urls_set; | 182 std::set<GURL> actual_urls_set; |
| 184 for (const auto& request_summary : summary.subresource_requests) | 183 for (const auto& request_summary : summary.subresource_requests) |
| 185 actual_urls_set.insert(request_summary.resource_url); | 184 actual_urls_set.insert(request_summary.resource_url); |
| 186 | 185 |
| 187 size_t correctly_predicted_count = 0; | 186 size_t correctly_predicted_count = 0; |
| 188 for (const GURL& predicted_url : predicted_urls_set) { | 187 for (const GURL& predicted_url : predicted_urls_set) { |
| 189 if (actual_urls_set.find(predicted_url) != actual_urls_set.end()) | 188 if (actual_urls_set.find(predicted_url) != actual_urls_set.end()) |
| 190 correctly_predicted_count++; | 189 correctly_predicted_count++; |
| 191 } | 190 } |
| 192 | 191 |
| 193 size_t precision_percentage = | 192 size_t precision_percentage = |
| 194 (100 * correctly_predicted_count) / predicted_urls_set.size(); | 193 (100 * correctly_predicted_count) / predicted_urls_set.size(); |
| 195 size_t recall_percentage = | 194 size_t recall_percentage = |
| 196 (100 * correctly_predicted_count) / actual_urls_set.size(); | 195 (100 * correctly_predicted_count) / actual_urls_set.size(); |
| 197 | 196 |
| 197 using RedirectStatus = ResourcePrefetchPredictor::RedirectStatus; |
| 198 RedirectStatus redirect_status; |
| 199 if (summary.main_frame_url == summary.initial_url) { |
| 200 // The actual navigation wasn't redirected. |
| 201 redirect_status = prediction.is_redirected |
| 202 ? RedirectStatus::NO_REDIRECT_BUT_PREDICTED |
| 203 : RedirectStatus::NO_REDIRECT; |
| 204 } else { |
| 205 if (prediction.is_redirected) { |
| 206 std::string main_frame_key = prediction.is_host |
| 207 ? summary.main_frame_url.host() |
| 208 : summary.main_frame_url.spec(); |
| 209 redirect_status = main_frame_key == prediction.main_frame_key |
| 210 ? RedirectStatus::REDIRECT_CORRECTLY_PREDICTED |
| 211 : RedirectStatus::REDIRECT_WRONG_PREDICTED; |
| 212 } else { |
| 213 redirect_status = RedirectStatus::REDIRECT_NOT_PREDICTED; |
| 214 } |
| 215 } |
| 216 |
| 198 UMA_HISTOGRAM_PERCENTAGE( | 217 UMA_HISTOGRAM_PERCENTAGE( |
| 199 internal::kResourcePrefetchPredictorPrecisionHistogram, | 218 internal::kResourcePrefetchPredictorPrecisionHistogram, |
| 200 precision_percentage); | 219 precision_percentage); |
| 201 UMA_HISTOGRAM_PERCENTAGE(internal::kResourcePrefetchPredictorRecallHistogram, | 220 UMA_HISTOGRAM_PERCENTAGE(internal::kResourcePrefetchPredictorRecallHistogram, |
| 202 recall_percentage); | 221 recall_percentage); |
| 203 UMA_HISTOGRAM_COUNTS_100(internal::kResourcePrefetchPredictorCountHistogram, | 222 UMA_HISTOGRAM_COUNTS_100(internal::kResourcePrefetchPredictorCountHistogram, |
| 204 predicted_urls.size()); | 223 predicted_urls.size()); |
| 224 UMA_HISTOGRAM_ENUMERATION( |
| 225 internal::kResourcePrefetchPredictorRedirectStatusHistogram, |
| 226 static_cast<int>(redirect_status), static_cast<int>(RedirectStatus::MAX)); |
| 205 } | 227 } |
| 206 | 228 |
| 207 } // namespace | 229 } // namespace |
| 208 | 230 |
| 209 //////////////////////////////////////////////////////////////////////////////// | 231 //////////////////////////////////////////////////////////////////////////////// |
| 210 // ResourcePrefetchPredictor static functions. | 232 // ResourcePrefetchPredictor static functions. |
| 211 | 233 |
| 212 // static | 234 // static |
| 213 bool ResourcePrefetchPredictor::ShouldRecordRequest( | 235 bool ResourcePrefetchPredictor::ShouldRecordRequest( |
| 214 net::URLRequest* request, | 236 net::URLRequest* request, |
| (...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 442 | 464 |
| 443 ResourcePrefetchPredictor::PageRequestSummary::PageRequestSummary( | 465 ResourcePrefetchPredictor::PageRequestSummary::PageRequestSummary( |
| 444 const GURL& i_main_frame_url) | 466 const GURL& i_main_frame_url) |
| 445 : main_frame_url(i_main_frame_url), initial_url(i_main_frame_url) {} | 467 : main_frame_url(i_main_frame_url), initial_url(i_main_frame_url) {} |
| 446 | 468 |
| 447 ResourcePrefetchPredictor::PageRequestSummary::PageRequestSummary( | 469 ResourcePrefetchPredictor::PageRequestSummary::PageRequestSummary( |
| 448 const PageRequestSummary& other) = default; | 470 const PageRequestSummary& other) = default; |
| 449 | 471 |
| 450 ResourcePrefetchPredictor::PageRequestSummary::~PageRequestSummary() {} | 472 ResourcePrefetchPredictor::PageRequestSummary::~PageRequestSummary() {} |
| 451 | 473 |
| 474 ResourcePrefetchPredictor::Prediction::Prediction() = default; |
| 475 |
| 476 ResourcePrefetchPredictor::Prediction::Prediction( |
| 477 const ResourcePrefetchPredictor::Prediction& other) = default; |
| 478 |
| 479 ResourcePrefetchPredictor::Prediction::~Prediction() = default; |
| 480 |
| 452 //////////////////////////////////////////////////////////////////////////////// | 481 //////////////////////////////////////////////////////////////////////////////// |
| 453 // ResourcePrefetchPredictor. | 482 // ResourcePrefetchPredictor. |
| 454 | 483 |
| 455 ResourcePrefetchPredictor::ResourcePrefetchPredictor( | 484 ResourcePrefetchPredictor::ResourcePrefetchPredictor( |
| 456 const ResourcePrefetchPredictorConfig& config, | 485 const ResourcePrefetchPredictorConfig& config, |
| 457 Profile* profile) | 486 Profile* profile) |
| 458 : profile_(profile), | 487 : profile_(profile), |
| 459 observer_(nullptr), | 488 observer_(nullptr), |
| 460 config_(config), | 489 config_(config), |
| 461 initialization_state_(NOT_INITIALIZED), | 490 initialization_state_(NOT_INITIALIZED), |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 562 if (inflight_prefetches_.find(url) == inflight_prefetches_.end() && | 591 if (inflight_prefetches_.find(url) == inflight_prefetches_.end() && |
| 563 IsUrlPrefetchable(url)) { | 592 IsUrlPrefetchable(url)) { |
| 564 inflight_prefetches_.insert(std::make_pair(url, base::TimeTicks::Now())); | 593 inflight_prefetches_.insert(std::make_pair(url, base::TimeTicks::Now())); |
| 565 } | 594 } |
| 566 | 595 |
| 567 if (!prefetch_manager_.get()) // Prefetching not enabled. | 596 if (!prefetch_manager_.get()) // Prefetching not enabled. |
| 568 return; | 597 return; |
| 569 if (!config_.IsPrefetchingEnabledForOrigin(profile_, origin)) | 598 if (!config_.IsPrefetchingEnabledForOrigin(profile_, origin)) |
| 570 return; | 599 return; |
| 571 | 600 |
| 572 std::vector<GURL> subresource_urls; | 601 ResourcePrefetchPredictor::Prediction prediction; |
| 573 if (!GetPrefetchData(url, &subresource_urls)) | 602 if (!GetPrefetchData(url, &prediction)) |
| 574 return; | 603 return; |
| 575 | 604 |
| 576 BrowserThread::PostTask( | 605 BrowserThread::PostTask( |
| 577 BrowserThread::IO, FROM_HERE, | 606 BrowserThread::IO, FROM_HERE, |
| 578 base::Bind(&ResourcePrefetcherManager::MaybeAddPrefetch, | 607 base::Bind(&ResourcePrefetcherManager::MaybeAddPrefetch, |
| 579 prefetch_manager_, url, subresource_urls)); | 608 prefetch_manager_, url, prediction.subresource_urls)); |
| 580 } | 609 } |
| 581 | 610 |
| 582 void ResourcePrefetchPredictor::StopPrefetching(const GURL& url) { | 611 void ResourcePrefetchPredictor::StopPrefetching(const GURL& url) { |
| 583 TRACE_EVENT1("browser", "ResourcePrefetchPredictor::StopPrefetching", "url", | 612 TRACE_EVENT1("browser", "ResourcePrefetchPredictor::StopPrefetching", "url", |
| 584 url.spec()); | 613 url.spec()); |
| 585 auto it = inflight_prefetches_.find(url); | 614 auto it = inflight_prefetches_.find(url); |
| 586 if (it != inflight_prefetches_.end()) { | 615 if (it != inflight_prefetches_.end()) { |
| 587 UMA_HISTOGRAM_TIMES( | 616 UMA_HISTOGRAM_TIMES( |
| 588 internal::kResourcePrefetchPredictorPrefetchingDurationHistogram, | 617 internal::kResourcePrefetchPredictorPrefetchingDurationHistogram, |
| 589 base::TimeTicks::Now() - it->second); | 618 base::TimeTicks::Now() - it->second); |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 702 | 731 |
| 703 NavigationMap::iterator nav_it = | 732 NavigationMap::iterator nav_it = |
| 704 inflight_navigations_.find(nav_id_without_timing_info); | 733 inflight_navigations_.find(nav_id_without_timing_info); |
| 705 if (nav_it == inflight_navigations_.end()) | 734 if (nav_it == inflight_navigations_.end()) |
| 706 return; | 735 return; |
| 707 | 736 |
| 708 // Remove the navigation from the inflight navigations. | 737 // Remove the navigation from the inflight navigations. |
| 709 std::unique_ptr<PageRequestSummary> summary = std::move(nav_it->second); | 738 std::unique_ptr<PageRequestSummary> summary = std::move(nav_it->second); |
| 710 inflight_navigations_.erase(nav_it); | 739 inflight_navigations_.erase(nav_it); |
| 711 | 740 |
| 712 const GURL& main_frame_url = nav_id_without_timing_info.main_frame_url; | 741 const GURL& initial_url = summary->initial_url; |
| 713 std::vector<GURL> predicted_urls; | 742 ResourcePrefetchPredictor::Prediction prediction; |
| 714 bool has_data = GetPrefetchData(main_frame_url, &predicted_urls); | 743 bool has_data = GetPrefetchData(initial_url, &prediction); |
| 715 if (has_data) | 744 if (has_data) |
| 716 ReportPredictionAccuracy(predicted_urls, *summary); | 745 ReportPredictionAccuracy(prediction, *summary); |
| 717 | 746 |
| 718 auto it = prefetcher_stats_.find(main_frame_url); | 747 auto it = prefetcher_stats_.find(initial_url); |
| 719 if (it != prefetcher_stats_.end()) { | 748 if (it != prefetcher_stats_.end()) { |
| 720 const std::vector<URLRequestSummary>& summaries = | 749 const std::vector<URLRequestSummary>& summaries = |
| 721 summary->subresource_requests; | 750 summary->subresource_requests; |
| 722 ReportPrefetchAccuracy(*it->second, summaries); | 751 ReportPrefetchAccuracy(*it->second, summaries); |
| 723 prefetcher_stats_.erase(it); | 752 prefetcher_stats_.erase(it); |
| 724 } | 753 } |
| 725 | 754 |
| 726 // Kick off history lookup to determine if we should record the URL. | 755 // Kick off history lookup to determine if we should record the URL. |
| 727 history::HistoryService* history_service = | 756 history::HistoryService* history_service = |
| 728 HistoryServiceFactory::GetForProfile(profile_, | 757 HistoryServiceFactory::GetForProfile(profile_, |
| 729 ServiceAccessType::EXPLICIT_ACCESS); | 758 ServiceAccessType::EXPLICIT_ACCESS); |
| 730 DCHECK(history_service); | 759 DCHECK(history_service); |
| 731 history_service->ScheduleDBTask( | 760 history_service->ScheduleDBTask( |
| 732 std::unique_ptr<history::HistoryDBTask>(new GetUrlVisitCountTask( | 761 std::unique_ptr<history::HistoryDBTask>(new GetUrlVisitCountTask( |
| 733 std::move(summary), | 762 std::move(summary), |
| 734 base::Bind(&ResourcePrefetchPredictor::OnVisitCountLookup, | 763 base::Bind(&ResourcePrefetchPredictor::OnVisitCountLookup, |
| 735 AsWeakPtr()))), | 764 AsWeakPtr()))), |
| 736 &history_lookup_consumer_); | 765 &history_lookup_consumer_); |
| 737 | 766 |
| 738 // Report readiness metric with 20% probability. | 767 // Report readiness metric with 20% probability. |
| 739 if (base::RandInt(1, 5) == 5) { | 768 if (base::RandInt(1, 5) == 5) { |
| 740 history_service->TopHosts( | 769 history_service->TopHosts( |
| 741 kNumSampleHosts, | 770 kNumSampleHosts, |
| 742 base::Bind(&ResourcePrefetchPredictor::ReportDatabaseReadiness, | 771 base::Bind(&ResourcePrefetchPredictor::ReportDatabaseReadiness, |
| 743 AsWeakPtr())); | 772 AsWeakPtr())); |
| 744 } | 773 } |
| 745 } | 774 } |
| 746 | 775 |
| 747 bool ResourcePrefetchPredictor::GetPrefetchData(const GURL& main_frame_url, | 776 bool ResourcePrefetchPredictor::GetPrefetchData( |
| 748 std::vector<GURL>* urls) const { | 777 const GURL& main_frame_url, |
| 778 ResourcePrefetchPredictor::Prediction* prediction) const { |
| 779 std::vector<GURL>* urls = |
| 780 prediction ? &prediction->subresource_urls : nullptr; |
| 749 DCHECK(!urls || urls->empty()); | 781 DCHECK(!urls || urls->empty()); |
| 750 | 782 |
| 751 // Fetch URLs based on a redirect endpoint for URL/host first. | 783 // Fetch URLs based on a redirect endpoint for URL/host first. |
| 752 std::string redirect_endpoint; | 784 std::string redirect_endpoint; |
| 753 if (GetRedirectEndpoint(main_frame_url.spec(), *url_redirect_table_cache_, | 785 if (GetRedirectEndpoint(main_frame_url.spec(), *url_redirect_table_cache_, |
| 754 &redirect_endpoint) && | 786 &redirect_endpoint) && |
| 755 PopulatePrefetcherRequest(redirect_endpoint, *url_table_cache_, urls)) { | 787 PopulatePrefetcherRequest(redirect_endpoint, *url_table_cache_, urls)) { |
| 788 if (prediction) { |
| 789 prediction->is_host = false; |
| 790 prediction->is_redirected = true; |
| 791 prediction->main_frame_key = redirect_endpoint; |
| 792 } |
| 756 return true; | 793 return true; |
| 757 } | 794 } |
| 758 | 795 |
| 759 if (GetRedirectEndpoint(main_frame_url.host(), *host_redirect_table_cache_, | 796 if (GetRedirectEndpoint(main_frame_url.host(), *host_redirect_table_cache_, |
| 760 &redirect_endpoint) && | 797 &redirect_endpoint) && |
| 761 PopulatePrefetcherRequest(redirect_endpoint, *host_table_cache_, urls)) { | 798 PopulatePrefetcherRequest(redirect_endpoint, *host_table_cache_, urls)) { |
| 799 if (prediction) { |
| 800 prediction->is_host = true; |
| 801 prediction->is_redirected = true; |
| 802 prediction->main_frame_key = redirect_endpoint; |
| 803 } |
| 762 return true; | 804 return true; |
| 763 } | 805 } |
| 764 | 806 |
| 765 // Fallback to fetching URLs based on the incoming URL/host. | 807 // Fallback to fetching URLs based on the incoming URL/host. |
| 766 if (PopulatePrefetcherRequest(main_frame_url.spec(), *url_table_cache_, | 808 if (PopulatePrefetcherRequest(main_frame_url.spec(), *url_table_cache_, |
| 767 urls)) { | 809 urls)) { |
| 810 if (prediction) { |
| 811 prediction->is_host = false; |
| 812 prediction->is_redirected = false; |
| 813 prediction->main_frame_key = main_frame_url.spec(); |
| 814 } |
| 768 return true; | 815 return true; |
| 769 } | 816 } |
| 770 | 817 |
| 771 return PopulatePrefetcherRequest(main_frame_url.host(), *host_table_cache_, | 818 if (PopulatePrefetcherRequest(main_frame_url.host(), *host_table_cache_, |
| 772 urls); | 819 urls)) { |
| 820 if (prediction) { |
| 821 prediction->is_host = true; |
| 822 prediction->is_redirected = false; |
| 823 prediction->main_frame_key = main_frame_url.host(); |
| 824 } |
| 825 return true; |
| 826 } |
| 827 |
| 828 return false; |
| 773 } | 829 } |
| 774 | 830 |
| 775 bool ResourcePrefetchPredictor::PopulatePrefetcherRequest( | 831 bool ResourcePrefetchPredictor::PopulatePrefetcherRequest( |
| 776 const std::string& main_frame_key, | 832 const std::string& main_frame_key, |
| 777 const PrefetchDataMap& data_map, | 833 const PrefetchDataMap& data_map, |
| 778 std::vector<GURL>* urls) const { | 834 std::vector<GURL>* urls) const { |
| 779 PrefetchDataMap::const_iterator it = data_map.find(main_frame_key); | 835 PrefetchDataMap::const_iterator it = data_map.find(main_frame_key); |
| 780 if (it == data_map.end()) | 836 if (it == data_map.end()) |
| 781 return false; | 837 return false; |
| 782 | 838 |
| (...skipping 554 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1337 TestObserver::~TestObserver() { | 1393 TestObserver::~TestObserver() { |
| 1338 predictor_->SetObserverForTesting(nullptr); | 1394 predictor_->SetObserverForTesting(nullptr); |
| 1339 } | 1395 } |
| 1340 | 1396 |
| 1341 TestObserver::TestObserver(ResourcePrefetchPredictor* predictor) | 1397 TestObserver::TestObserver(ResourcePrefetchPredictor* predictor) |
| 1342 : predictor_(predictor) { | 1398 : predictor_(predictor) { |
| 1343 predictor_->SetObserverForTesting(this); | 1399 predictor_->SetObserverForTesting(this); |
| 1344 } | 1400 } |
| 1345 | 1401 |
| 1346 } // namespace predictors | 1402 } // namespace predictors |
| OLD | NEW |