| 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 600 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 611 CHECK_EQ(request.resource_type, content::RESOURCE_TYPE_MAIN_FRAME); | 611 CHECK_EQ(request.resource_type, content::RESOURCE_TYPE_MAIN_FRAME); |
| 612 OnMainFrameRequest(request); | 612 OnMainFrameRequest(request); |
| 613 } | 613 } |
| 614 | 614 |
| 615 void ResourcePrefetchPredictor::RecordURLResponse( | 615 void ResourcePrefetchPredictor::RecordURLResponse( |
| 616 const URLRequestSummary& response) { | 616 const URLRequestSummary& response) { |
| 617 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 617 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 618 if (initialization_state_ != INITIALIZED) | 618 if (initialization_state_ != INITIALIZED) |
| 619 return; | 619 return; |
| 620 | 620 |
| 621 if (response.resource_type == content::RESOURCE_TYPE_MAIN_FRAME) | 621 if (response.resource_type != content::RESOURCE_TYPE_MAIN_FRAME) |
| 622 OnMainFrameResponse(response); | |
| 623 else | |
| 624 OnSubresourceResponse(response); | 622 OnSubresourceResponse(response); |
| 625 } | 623 } |
| 626 | 624 |
| 627 void ResourcePrefetchPredictor::RecordURLRedirect( | 625 void ResourcePrefetchPredictor::RecordURLRedirect( |
| 628 const URLRequestSummary& response) { | 626 const URLRequestSummary& response) { |
| 629 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 627 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 630 if (initialization_state_ != INITIALIZED) | 628 if (initialization_state_ != INITIALIZED) |
| 631 return; | 629 return; |
| 632 | 630 |
| 633 if (response.resource_type == content::RESOURCE_TYPE_MAIN_FRAME) | 631 if (response.resource_type == content::RESOURCE_TYPE_MAIN_FRAME) |
| (...skipping 27 matching lines...) Expand all Loading... |
| 661 const base::TimeTicks& first_contentful_paint) { | 659 const base::TimeTicks& first_contentful_paint) { |
| 662 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 660 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 663 if (initialization_state_ != INITIALIZED) | 661 if (initialization_state_ != INITIALIZED) |
| 664 return; | 662 return; |
| 665 | 663 |
| 666 NavigationMap::iterator nav_it = inflight_navigations_.find(navigation_id); | 664 NavigationMap::iterator nav_it = inflight_navigations_.find(navigation_id); |
| 667 if (nav_it != inflight_navigations_.end()) | 665 if (nav_it != inflight_navigations_.end()) |
| 668 nav_it->second->first_contentful_paint = first_contentful_paint; | 666 nav_it->second->first_contentful_paint = first_contentful_paint; |
| 669 } | 667 } |
| 670 | 668 |
| 671 void ResourcePrefetchPredictor::StartPrefetching(const GURL& url, | |
| 672 HintOrigin origin) { | |
| 673 TRACE_EVENT1("browser", "ResourcePrefetchPredictor::StartPrefetching", "url", | |
| 674 url.spec()); | |
| 675 // Save prefetch start time to report prefetching duration. | |
| 676 if (inflight_prefetches_.find(url) == inflight_prefetches_.end() && | |
| 677 IsUrlPrefetchable(url)) { | |
| 678 inflight_prefetches_.insert(std::make_pair(url, base::TimeTicks::Now())); | |
| 679 } | |
| 680 | |
| 681 if (!prefetch_manager_.get()) // Prefetching not enabled. | |
| 682 return; | |
| 683 if (!config_.IsPrefetchingEnabledForOrigin(profile_, origin)) | |
| 684 return; | |
| 685 | |
| 686 ResourcePrefetchPredictor::Prediction prediction; | |
| 687 if (!GetPrefetchData(url, &prediction)) | |
| 688 return; | |
| 689 | |
| 690 BrowserThread::PostTask( | |
| 691 BrowserThread::IO, FROM_HERE, | |
| 692 base::BindOnce(&ResourcePrefetcherManager::MaybeAddPrefetch, | |
| 693 prefetch_manager_, url, prediction.subresource_urls)); | |
| 694 | |
| 695 if (observer_) | |
| 696 observer_->OnPrefetchingStarted(url); | |
| 697 } | |
| 698 | |
| 699 void ResourcePrefetchPredictor::StopPrefetching(const GURL& url) { | |
| 700 TRACE_EVENT1("browser", "ResourcePrefetchPredictor::StopPrefetching", "url", | |
| 701 url.spec()); | |
| 702 auto it = inflight_prefetches_.find(url); | |
| 703 if (it != inflight_prefetches_.end()) { | |
| 704 UMA_HISTOGRAM_TIMES( | |
| 705 internal::kResourcePrefetchPredictorPrefetchingDurationHistogram, | |
| 706 base::TimeTicks::Now() - it->second); | |
| 707 inflight_prefetches_.erase(it); | |
| 708 } | |
| 709 if (!prefetch_manager_.get()) // Not enabled. | |
| 710 return; | |
| 711 | |
| 712 BrowserThread::PostTask( | |
| 713 BrowserThread::IO, FROM_HERE, | |
| 714 base::BindOnce(&ResourcePrefetcherManager::MaybeRemovePrefetch, | |
| 715 prefetch_manager_, url)); | |
| 716 | |
| 717 if (observer_) | |
| 718 observer_->OnPrefetchingStopped(url); | |
| 719 } | |
| 720 | |
| 721 void ResourcePrefetchPredictor::OnPrefetchingFinished( | 669 void ResourcePrefetchPredictor::OnPrefetchingFinished( |
| 722 const GURL& main_frame_url, | 670 const GURL& main_frame_url, |
| 723 std::unique_ptr<ResourcePrefetcher::PrefetcherStats> stats) { | 671 std::unique_ptr<ResourcePrefetcher::PrefetcherStats> stats) { |
| 724 if (observer_) | 672 if (observer_) |
| 725 observer_->OnPrefetchingFinished(main_frame_url); | 673 observer_->OnPrefetchingFinished(main_frame_url); |
| 726 | 674 |
| 727 prefetcher_stats_.insert(std::make_pair(main_frame_url, std::move(stats))); | 675 prefetcher_stats_.insert(std::make_pair(main_frame_url, std::move(stats))); |
| 728 } | 676 } |
| 729 | 677 |
| 730 bool ResourcePrefetchPredictor::IsUrlPrefetchable(const GURL& main_frame_url) { | 678 bool ResourcePrefetchPredictor::IsUrlPrefetchable( |
| 679 const GURL& main_frame_url) const { |
| 731 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 680 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 732 if (initialization_state_ != INITIALIZED) | 681 if (initialization_state_ != INITIALIZED) |
| 733 return false; | 682 return false; |
| 734 | 683 |
| 735 return GetPrefetchData(main_frame_url, nullptr); | 684 return GetPrefetchData(main_frame_url, nullptr); |
| 736 } | 685 } |
| 737 | 686 |
| 738 bool ResourcePrefetchPredictor::IsResourcePrefetchable( | 687 bool ResourcePrefetchPredictor::IsResourcePrefetchable( |
| 739 const ResourceData& resource) const { | 688 const ResourceData& resource) const { |
| 740 float confidence = static_cast<float>(resource.number_of_hits()) / | 689 float confidence = static_cast<float>(resource.number_of_hits()) / |
| (...skipping 13 matching lines...) Expand all Loading... |
| 754 prefetch_manager_ = NULL; | 703 prefetch_manager_ = NULL; |
| 755 } | 704 } |
| 756 history_service_observer_.RemoveAll(); | 705 history_service_observer_.RemoveAll(); |
| 757 } | 706 } |
| 758 | 707 |
| 759 void ResourcePrefetchPredictor::OnMainFrameRequest( | 708 void ResourcePrefetchPredictor::OnMainFrameRequest( |
| 760 const URLRequestSummary& request) { | 709 const URLRequestSummary& request) { |
| 761 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 710 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 762 DCHECK_EQ(INITIALIZED, initialization_state_); | 711 DCHECK_EQ(INITIALIZED, initialization_state_); |
| 763 | 712 |
| 764 const GURL& main_frame_url = request.navigation_id.main_frame_url; | |
| 765 StartPrefetching(main_frame_url, HintOrigin::NAVIGATION); | |
| 766 | |
| 767 CleanupAbandonedNavigations(request.navigation_id); | 713 CleanupAbandonedNavigations(request.navigation_id); |
| 768 | 714 |
| 769 // New empty navigation entry. | 715 // New empty navigation entry. |
| 770 inflight_navigations_.insert( | 716 const GURL& main_frame_url = request.navigation_id.main_frame_url; |
| 771 std::make_pair(request.navigation_id, | 717 inflight_navigations_.emplace( |
| 772 base::MakeUnique<PageRequestSummary>(main_frame_url))); | 718 request.navigation_id, |
| 773 } | 719 base::MakeUnique<PageRequestSummary>(main_frame_url)); |
| 774 | |
| 775 void ResourcePrefetchPredictor::OnMainFrameResponse( | |
| 776 const URLRequestSummary& response) { | |
| 777 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 778 DCHECK_EQ(INITIALIZED, initialization_state_); | |
| 779 | |
| 780 NavigationMap::iterator nav_it = | |
| 781 inflight_navigations_.find(response.navigation_id); | |
| 782 if (nav_it != inflight_navigations_.end()) { | |
| 783 // To match an URL in StartPrefetching(). | |
| 784 StopPrefetching(nav_it->second->initial_url); | |
| 785 } else { | |
| 786 StopPrefetching(response.navigation_id.main_frame_url); | |
| 787 } | |
| 788 } | 720 } |
| 789 | 721 |
| 790 void ResourcePrefetchPredictor::OnMainFrameRedirect( | 722 void ResourcePrefetchPredictor::OnMainFrameRedirect( |
| 791 const URLRequestSummary& response) { | 723 const URLRequestSummary& response) { |
| 792 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 724 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 793 DCHECK_EQ(INITIALIZED, initialization_state_); | 725 DCHECK_EQ(INITIALIZED, initialization_state_); |
| 794 | 726 |
| 795 const GURL& main_frame_url = response.navigation_id.main_frame_url; | 727 const GURL& main_frame_url = response.navigation_id.main_frame_url; |
| 796 std::unique_ptr<PageRequestSummary> summary; | 728 std::unique_ptr<PageRequestSummary> summary; |
| 797 NavigationMap::iterator nav_it = | 729 NavigationMap::iterator nav_it = |
| (...skipping 10 matching lines...) Expand all Loading... |
| 808 // If we lost the information about the first hop for some reason. | 740 // If we lost the information about the first hop for some reason. |
| 809 if (!summary) { | 741 if (!summary) { |
| 810 summary = base::MakeUnique<PageRequestSummary>(main_frame_url); | 742 summary = base::MakeUnique<PageRequestSummary>(main_frame_url); |
| 811 } | 743 } |
| 812 | 744 |
| 813 // A redirect will not lead to another OnMainFrameRequest call, so record the | 745 // A redirect will not lead to another OnMainFrameRequest call, so record the |
| 814 // redirect url as a new navigation id and save the initial url. | 746 // redirect url as a new navigation id and save the initial url. |
| 815 NavigationID navigation_id(response.navigation_id); | 747 NavigationID navigation_id(response.navigation_id); |
| 816 navigation_id.main_frame_url = response.redirect_url; | 748 navigation_id.main_frame_url = response.redirect_url; |
| 817 summary->main_frame_url = response.redirect_url; | 749 summary->main_frame_url = response.redirect_url; |
| 818 inflight_navigations_.insert( | 750 inflight_navigations_.emplace(navigation_id, std::move(summary)); |
| 819 std::make_pair(navigation_id, std::move(summary))); | |
| 820 } | 751 } |
| 821 | 752 |
| 822 void ResourcePrefetchPredictor::OnSubresourceResponse( | 753 void ResourcePrefetchPredictor::OnSubresourceResponse( |
| 823 const URLRequestSummary& response) { | 754 const URLRequestSummary& response) { |
| 824 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 755 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 825 DCHECK_EQ(INITIALIZED, initialization_state_); | 756 DCHECK_EQ(INITIALIZED, initialization_state_); |
| 826 | 757 |
| 827 NavigationMap::const_iterator nav_it = | 758 NavigationMap::const_iterator nav_it = |
| 828 inflight_navigations_.find(response.navigation_id); | 759 inflight_navigations_.find(response.navigation_id); |
| 829 if (nav_it == inflight_navigations_.end()) | 760 if (nav_it == inflight_navigations_.end()) |
| (...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1092 for (NavigationMap::iterator it = inflight_navigations_.begin(); | 1023 for (NavigationMap::iterator it = inflight_navigations_.begin(); |
| 1093 it != inflight_navigations_.end();) { | 1024 it != inflight_navigations_.end();) { |
| 1094 if ((it->first.tab_id == navigation_id.tab_id) || | 1025 if ((it->first.tab_id == navigation_id.tab_id) || |
| 1095 (time_now - it->first.creation_time > max_navigation_age)) { | 1026 (time_now - it->first.creation_time > max_navigation_age)) { |
| 1096 inflight_navigations_.erase(it++); | 1027 inflight_navigations_.erase(it++); |
| 1097 } else { | 1028 } else { |
| 1098 ++it; | 1029 ++it; |
| 1099 } | 1030 } |
| 1100 } | 1031 } |
| 1101 | 1032 |
| 1102 for (auto it = inflight_prefetches_.begin(); | |
| 1103 it != inflight_prefetches_.end();) { | |
| 1104 base::TimeDelta prefetch_age = time_now - it->second; | |
| 1105 if (prefetch_age > max_navigation_age) { | |
| 1106 // It goes to the last bucket meaning that the duration was unlimited. | |
| 1107 UMA_HISTOGRAM_TIMES( | |
| 1108 internal::kResourcePrefetchPredictorPrefetchingDurationHistogram, | |
| 1109 prefetch_age); | |
| 1110 it = inflight_prefetches_.erase(it); | |
| 1111 } else { | |
| 1112 ++it; | |
| 1113 } | |
| 1114 } | |
| 1115 | |
| 1116 // Remove old prefetches that haven't been claimed. | 1033 // Remove old prefetches that haven't been claimed. |
| 1117 for (auto stats_it = prefetcher_stats_.begin(); | 1034 for (auto stats_it = prefetcher_stats_.begin(); |
| 1118 stats_it != prefetcher_stats_.end();) { | 1035 stats_it != prefetcher_stats_.end();) { |
| 1119 if (time_now - stats_it->second->start_time > max_navigation_age) { | 1036 if (time_now - stats_it->second->start_time > max_navigation_age) { |
| 1120 // No requests -> everything is a miss. | 1037 // No requests -> everything is a miss. |
| 1121 ReportPrefetchAccuracy(*stats_it->second, | 1038 ReportPrefetchAccuracy(*stats_it->second, |
| 1122 std::vector<URLRequestSummary>()); | 1039 std::vector<URLRequestSummary>()); |
| 1123 stats_it = prefetcher_stats_.erase(stats_it); | 1040 stats_it = prefetcher_stats_.erase(stats_it); |
| 1124 } else { | 1041 } else { |
| 1125 ++stats_it; | 1042 ++stats_it; |
| (...skipping 712 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1838 if (!history_service) | 1755 if (!history_service) |
| 1839 return; | 1756 return; |
| 1840 DCHECK(!history_service_observer_.IsObserving(history_service)); | 1757 DCHECK(!history_service_observer_.IsObserving(history_service)); |
| 1841 history_service_observer_.Add(history_service); | 1758 history_service_observer_.Add(history_service); |
| 1842 if (history_service->BackendLoaded()) { | 1759 if (history_service->BackendLoaded()) { |
| 1843 // HistoryService is already loaded. Continue with Initialization. | 1760 // HistoryService is already loaded. Continue with Initialization. |
| 1844 OnHistoryAndCacheLoaded(); | 1761 OnHistoryAndCacheLoaded(); |
| 1845 } | 1762 } |
| 1846 } | 1763 } |
| 1847 | 1764 |
| 1765 void ResourcePrefetchPredictor::StartPrefetching(const GURL& url) { |
| 1766 TRACE_EVENT1("browser", "ResourcePrefetchPredictor::StartPrefetching", "url", |
| 1767 url.spec()); |
| 1768 if (!prefetch_manager_.get()) // Not enabled. |
| 1769 return; |
| 1770 |
| 1771 ResourcePrefetchPredictor::Prediction prediction; |
| 1772 bool has_data = GetPrefetchData(url, &prediction); |
| 1773 DCHECK(has_data); |
| 1774 |
| 1775 BrowserThread::PostTask( |
| 1776 BrowserThread::IO, FROM_HERE, |
| 1777 base::BindOnce(&ResourcePrefetcherManager::MaybeAddPrefetch, |
| 1778 prefetch_manager_, url, prediction.subresource_urls)); |
| 1779 |
| 1780 if (observer_) |
| 1781 observer_->OnPrefetchingStarted(url); |
| 1782 return; |
| 1783 } |
| 1784 |
| 1785 void ResourcePrefetchPredictor::StopPrefetching(const GURL& url) { |
| 1786 TRACE_EVENT1("browser", "ResourcePrefetchPredictor::StopPrefetching", "url", |
| 1787 url.spec()); |
| 1788 if (!prefetch_manager_.get()) // Not enabled. |
| 1789 return; |
| 1790 |
| 1791 BrowserThread::PostTask( |
| 1792 BrowserThread::IO, FROM_HERE, |
| 1793 base::BindOnce(&ResourcePrefetcherManager::MaybeRemovePrefetch, |
| 1794 prefetch_manager_, url)); |
| 1795 |
| 1796 if (observer_) |
| 1797 observer_->OnPrefetchingStopped(url); |
| 1798 } |
| 1799 |
| 1848 //////////////////////////////////////////////////////////////////////////////// | 1800 //////////////////////////////////////////////////////////////////////////////// |
| 1849 // TestObserver. | 1801 // TestObserver. |
| 1850 | 1802 |
| 1851 TestObserver::~TestObserver() { | 1803 TestObserver::~TestObserver() { |
| 1852 predictor_->SetObserverForTesting(nullptr); | 1804 predictor_->SetObserverForTesting(nullptr); |
| 1853 } | 1805 } |
| 1854 | 1806 |
| 1855 TestObserver::TestObserver(ResourcePrefetchPredictor* predictor) | 1807 TestObserver::TestObserver(ResourcePrefetchPredictor* predictor) |
| 1856 : predictor_(predictor) { | 1808 : predictor_(predictor) { |
| 1857 predictor_->SetObserverForTesting(this); | 1809 predictor_->SetObserverForTesting(this); |
| 1858 } | 1810 } |
| 1859 | 1811 |
| 1860 } // namespace predictors | 1812 } // namespace predictors |
| OLD | NEW |