| 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 610 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 621 CHECK_EQ(request.resource_type, content::RESOURCE_TYPE_MAIN_FRAME); | 621 CHECK_EQ(request.resource_type, content::RESOURCE_TYPE_MAIN_FRAME); |
| 622 OnMainFrameRequest(request); | 622 OnMainFrameRequest(request); |
| 623 } | 623 } |
| 624 | 624 |
| 625 void ResourcePrefetchPredictor::RecordURLResponse( | 625 void ResourcePrefetchPredictor::RecordURLResponse( |
| 626 const URLRequestSummary& response) { | 626 const URLRequestSummary& response) { |
| 627 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 627 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 628 if (initialization_state_ != INITIALIZED) | 628 if (initialization_state_ != INITIALIZED) |
| 629 return; | 629 return; |
| 630 | 630 |
| 631 if (response.resource_type == content::RESOURCE_TYPE_MAIN_FRAME) | 631 if (response.resource_type != content::RESOURCE_TYPE_MAIN_FRAME) |
| 632 OnMainFrameResponse(response); | |
| 633 else | |
| 634 OnSubresourceResponse(response); | 632 OnSubresourceResponse(response); |
| 635 } | 633 } |
| 636 | 634 |
| 637 void ResourcePrefetchPredictor::RecordURLRedirect( | 635 void ResourcePrefetchPredictor::RecordURLRedirect( |
| 638 const URLRequestSummary& response) { | 636 const URLRequestSummary& response) { |
| 639 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 637 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 640 if (initialization_state_ != INITIALIZED) | 638 if (initialization_state_ != INITIALIZED) |
| 641 return; | 639 return; |
| 642 | 640 |
| 643 if (response.resource_type == content::RESOURCE_TYPE_MAIN_FRAME) | 641 if (response.resource_type == content::RESOURCE_TYPE_MAIN_FRAME) |
| (...skipping 27 matching lines...) Expand all Loading... |
| 671 const base::TimeTicks& first_contentful_paint) { | 669 const base::TimeTicks& first_contentful_paint) { |
| 672 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 670 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 673 if (initialization_state_ != INITIALIZED) | 671 if (initialization_state_ != INITIALIZED) |
| 674 return; | 672 return; |
| 675 | 673 |
| 676 NavigationMap::iterator nav_it = inflight_navigations_.find(navigation_id); | 674 NavigationMap::iterator nav_it = inflight_navigations_.find(navigation_id); |
| 677 if (nav_it != inflight_navigations_.end()) | 675 if (nav_it != inflight_navigations_.end()) |
| 678 nav_it->second->first_contentful_paint = first_contentful_paint; | 676 nav_it->second->first_contentful_paint = first_contentful_paint; |
| 679 } | 677 } |
| 680 | 678 |
| 681 void ResourcePrefetchPredictor::StartPrefetching(const GURL& url, | |
| 682 HintOrigin origin) { | |
| 683 TRACE_EVENT1("browser", "ResourcePrefetchPredictor::StartPrefetching", "url", | |
| 684 url.spec()); | |
| 685 // Save prefetch start time to report prefetching duration. | |
| 686 if (inflight_prefetches_.find(url) == inflight_prefetches_.end() && | |
| 687 IsUrlPrefetchable(url)) { | |
| 688 inflight_prefetches_.insert(std::make_pair(url, base::TimeTicks::Now())); | |
| 689 } | |
| 690 | |
| 691 if (!prefetch_manager_.get()) // Prefetching not enabled. | |
| 692 return; | |
| 693 if (!config_.IsPrefetchingEnabledForOrigin(profile_, origin)) | |
| 694 return; | |
| 695 | |
| 696 ResourcePrefetchPredictor::Prediction prediction; | |
| 697 if (!GetPrefetchData(url, &prediction)) | |
| 698 return; | |
| 699 | |
| 700 BrowserThread::PostTask( | |
| 701 BrowserThread::IO, FROM_HERE, | |
| 702 base::BindOnce(&ResourcePrefetcherManager::MaybeAddPrefetch, | |
| 703 prefetch_manager_, url, prediction.subresource_urls)); | |
| 704 | |
| 705 if (observer_) | |
| 706 observer_->OnPrefetchingStarted(url); | |
| 707 } | |
| 708 | |
| 709 void ResourcePrefetchPredictor::StopPrefetching(const GURL& url) { | |
| 710 TRACE_EVENT1("browser", "ResourcePrefetchPredictor::StopPrefetching", "url", | |
| 711 url.spec()); | |
| 712 auto it = inflight_prefetches_.find(url); | |
| 713 if (it != inflight_prefetches_.end()) { | |
| 714 UMA_HISTOGRAM_TIMES( | |
| 715 internal::kResourcePrefetchPredictorPrefetchingDurationHistogram, | |
| 716 base::TimeTicks::Now() - it->second); | |
| 717 inflight_prefetches_.erase(it); | |
| 718 } | |
| 719 if (!prefetch_manager_.get()) // Not enabled. | |
| 720 return; | |
| 721 | |
| 722 BrowserThread::PostTask( | |
| 723 BrowserThread::IO, FROM_HERE, | |
| 724 base::BindOnce(&ResourcePrefetcherManager::MaybeRemovePrefetch, | |
| 725 prefetch_manager_, url)); | |
| 726 | |
| 727 if (observer_) | |
| 728 observer_->OnPrefetchingStopped(url); | |
| 729 } | |
| 730 | |
| 731 void ResourcePrefetchPredictor::OnPrefetchingFinished( | 679 void ResourcePrefetchPredictor::OnPrefetchingFinished( |
| 732 const GURL& main_frame_url, | 680 const GURL& main_frame_url, |
| 733 std::unique_ptr<ResourcePrefetcher::PrefetcherStats> stats) { | 681 std::unique_ptr<ResourcePrefetcher::PrefetcherStats> stats) { |
| 734 if (observer_) | 682 if (observer_) |
| 735 observer_->OnPrefetchingFinished(main_frame_url); | 683 observer_->OnPrefetchingFinished(main_frame_url); |
| 736 | 684 |
| 737 prefetcher_stats_.insert(std::make_pair(main_frame_url, std::move(stats))); | 685 prefetcher_stats_.insert(std::make_pair(main_frame_url, std::move(stats))); |
| 738 } | 686 } |
| 739 | 687 |
| 740 bool ResourcePrefetchPredictor::IsUrlPrefetchable(const GURL& main_frame_url) { | 688 bool ResourcePrefetchPredictor::IsUrlPrefetchable( |
| 689 const GURL& main_frame_url) const { |
| 741 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 690 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 742 if (initialization_state_ != INITIALIZED) | 691 if (initialization_state_ != INITIALIZED) |
| 743 return false; | 692 return false; |
| 744 | 693 |
| 745 return GetPrefetchData(main_frame_url, nullptr); | 694 return GetPrefetchData(main_frame_url, nullptr); |
| 746 } | 695 } |
| 747 | 696 |
| 748 bool ResourcePrefetchPredictor::IsResourcePrefetchable( | 697 bool ResourcePrefetchPredictor::IsResourcePrefetchable( |
| 749 const ResourceData& resource) const { | 698 const ResourceData& resource) const { |
| 750 float confidence = static_cast<float>(resource.number_of_hits()) / | 699 float confidence = static_cast<float>(resource.number_of_hits()) / |
| (...skipping 13 matching lines...) Expand all Loading... |
| 764 prefetch_manager_ = NULL; | 713 prefetch_manager_ = NULL; |
| 765 } | 714 } |
| 766 history_service_observer_.RemoveAll(); | 715 history_service_observer_.RemoveAll(); |
| 767 } | 716 } |
| 768 | 717 |
| 769 void ResourcePrefetchPredictor::OnMainFrameRequest( | 718 void ResourcePrefetchPredictor::OnMainFrameRequest( |
| 770 const URLRequestSummary& request) { | 719 const URLRequestSummary& request) { |
| 771 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 720 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 772 DCHECK_EQ(INITIALIZED, initialization_state_); | 721 DCHECK_EQ(INITIALIZED, initialization_state_); |
| 773 | 722 |
| 774 const GURL& main_frame_url = request.navigation_id.main_frame_url; | |
| 775 StartPrefetching(main_frame_url, HintOrigin::NAVIGATION); | |
| 776 | |
| 777 CleanupAbandonedNavigations(request.navigation_id); | 723 CleanupAbandonedNavigations(request.navigation_id); |
| 778 | 724 |
| 779 // New empty navigation entry. | 725 // New empty navigation entry. |
| 780 inflight_navigations_.insert( | 726 const GURL& main_frame_url = request.navigation_id.main_frame_url; |
| 781 std::make_pair(request.navigation_id, | 727 inflight_navigations_.emplace( |
| 782 base::MakeUnique<PageRequestSummary>(main_frame_url))); | 728 request.navigation_id, |
| 783 } | 729 base::MakeUnique<PageRequestSummary>(main_frame_url)); |
| 784 | |
| 785 void ResourcePrefetchPredictor::OnMainFrameResponse( | |
| 786 const URLRequestSummary& response) { | |
| 787 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 788 DCHECK_EQ(INITIALIZED, initialization_state_); | |
| 789 | |
| 790 NavigationMap::iterator nav_it = | |
| 791 inflight_navigations_.find(response.navigation_id); | |
| 792 if (nav_it != inflight_navigations_.end()) { | |
| 793 // To match an URL in StartPrefetching(). | |
| 794 StopPrefetching(nav_it->second->initial_url); | |
| 795 } else { | |
| 796 StopPrefetching(response.navigation_id.main_frame_url); | |
| 797 } | |
| 798 } | 730 } |
| 799 | 731 |
| 800 void ResourcePrefetchPredictor::OnMainFrameRedirect( | 732 void ResourcePrefetchPredictor::OnMainFrameRedirect( |
| 801 const URLRequestSummary& response) { | 733 const URLRequestSummary& response) { |
| 802 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 734 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 803 DCHECK_EQ(INITIALIZED, initialization_state_); | 735 DCHECK_EQ(INITIALIZED, initialization_state_); |
| 804 | 736 |
| 805 const GURL& main_frame_url = response.navigation_id.main_frame_url; | 737 const GURL& main_frame_url = response.navigation_id.main_frame_url; |
| 806 std::unique_ptr<PageRequestSummary> summary; | 738 std::unique_ptr<PageRequestSummary> summary; |
| 807 NavigationMap::iterator nav_it = | 739 NavigationMap::iterator nav_it = |
| (...skipping 10 matching lines...) Expand all Loading... |
| 818 // If we lost the information about the first hop for some reason. | 750 // If we lost the information about the first hop for some reason. |
| 819 if (!summary) { | 751 if (!summary) { |
| 820 summary = base::MakeUnique<PageRequestSummary>(main_frame_url); | 752 summary = base::MakeUnique<PageRequestSummary>(main_frame_url); |
| 821 } | 753 } |
| 822 | 754 |
| 823 // A redirect will not lead to another OnMainFrameRequest call, so record the | 755 // A redirect will not lead to another OnMainFrameRequest call, so record the |
| 824 // redirect url as a new navigation id and save the initial url. | 756 // redirect url as a new navigation id and save the initial url. |
| 825 NavigationID navigation_id(response.navigation_id); | 757 NavigationID navigation_id(response.navigation_id); |
| 826 navigation_id.main_frame_url = response.redirect_url; | 758 navigation_id.main_frame_url = response.redirect_url; |
| 827 summary->main_frame_url = response.redirect_url; | 759 summary->main_frame_url = response.redirect_url; |
| 828 inflight_navigations_.insert( | 760 inflight_navigations_.emplace(navigation_id, std::move(summary)); |
| 829 std::make_pair(navigation_id, std::move(summary))); | |
| 830 } | 761 } |
| 831 | 762 |
| 832 void ResourcePrefetchPredictor::OnSubresourceResponse( | 763 void ResourcePrefetchPredictor::OnSubresourceResponse( |
| 833 const URLRequestSummary& response) { | 764 const URLRequestSummary& response) { |
| 834 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 765 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 835 DCHECK_EQ(INITIALIZED, initialization_state_); | 766 DCHECK_EQ(INITIALIZED, initialization_state_); |
| 836 | 767 |
| 837 NavigationMap::const_iterator nav_it = | 768 NavigationMap::const_iterator nav_it = |
| 838 inflight_navigations_.find(response.navigation_id); | 769 inflight_navigations_.find(response.navigation_id); |
| 839 if (nav_it == inflight_navigations_.end()) | 770 if (nav_it == inflight_navigations_.end()) |
| (...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1072 for (NavigationMap::iterator it = inflight_navigations_.begin(); | 1003 for (NavigationMap::iterator it = inflight_navigations_.begin(); |
| 1073 it != inflight_navigations_.end();) { | 1004 it != inflight_navigations_.end();) { |
| 1074 if ((it->first.tab_id == navigation_id.tab_id) || | 1005 if ((it->first.tab_id == navigation_id.tab_id) || |
| 1075 (time_now - it->first.creation_time > max_navigation_age)) { | 1006 (time_now - it->first.creation_time > max_navigation_age)) { |
| 1076 inflight_navigations_.erase(it++); | 1007 inflight_navigations_.erase(it++); |
| 1077 } else { | 1008 } else { |
| 1078 ++it; | 1009 ++it; |
| 1079 } | 1010 } |
| 1080 } | 1011 } |
| 1081 | 1012 |
| 1082 for (auto it = inflight_prefetches_.begin(); | |
| 1083 it != inflight_prefetches_.end();) { | |
| 1084 base::TimeDelta prefetch_age = time_now - it->second; | |
| 1085 if (prefetch_age > max_navigation_age) { | |
| 1086 // It goes to the last bucket meaning that the duration was unlimited. | |
| 1087 UMA_HISTOGRAM_TIMES( | |
| 1088 internal::kResourcePrefetchPredictorPrefetchingDurationHistogram, | |
| 1089 prefetch_age); | |
| 1090 it = inflight_prefetches_.erase(it); | |
| 1091 } else { | |
| 1092 ++it; | |
| 1093 } | |
| 1094 } | |
| 1095 | |
| 1096 // Remove old prefetches that haven't been claimed. | 1013 // Remove old prefetches that haven't been claimed. |
| 1097 for (auto stats_it = prefetcher_stats_.begin(); | 1014 for (auto stats_it = prefetcher_stats_.begin(); |
| 1098 stats_it != prefetcher_stats_.end();) { | 1015 stats_it != prefetcher_stats_.end();) { |
| 1099 if (time_now - stats_it->second->start_time > max_navigation_age) { | 1016 if (time_now - stats_it->second->start_time > max_navigation_age) { |
| 1100 // No requests -> everything is a miss. | 1017 // No requests -> everything is a miss. |
| 1101 ReportPrefetchAccuracy(*stats_it->second, | 1018 ReportPrefetchAccuracy(*stats_it->second, |
| 1102 std::vector<URLRequestSummary>()); | 1019 std::vector<URLRequestSummary>()); |
| 1103 stats_it = prefetcher_stats_.erase(stats_it); | 1020 stats_it = prefetcher_stats_.erase(stats_it); |
| 1104 } else { | 1021 } else { |
| 1105 ++stats_it; | 1022 ++stats_it; |
| (...skipping 486 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1592 if (!history_service) | 1509 if (!history_service) |
| 1593 return; | 1510 return; |
| 1594 DCHECK(!history_service_observer_.IsObserving(history_service)); | 1511 DCHECK(!history_service_observer_.IsObserving(history_service)); |
| 1595 history_service_observer_.Add(history_service); | 1512 history_service_observer_.Add(history_service); |
| 1596 if (history_service->BackendLoaded()) { | 1513 if (history_service->BackendLoaded()) { |
| 1597 // HistoryService is already loaded. Continue with Initialization. | 1514 // HistoryService is already loaded. Continue with Initialization. |
| 1598 OnHistoryAndCacheLoaded(); | 1515 OnHistoryAndCacheLoaded(); |
| 1599 } | 1516 } |
| 1600 } | 1517 } |
| 1601 | 1518 |
| 1519 void ResourcePrefetchPredictor::StartPrefetching(const GURL& url) { |
| 1520 TRACE_EVENT1("browser", "ResourcePrefetchPredictor::StartPrefetching", "url", |
| 1521 url.spec()); |
| 1522 if (!prefetch_manager_.get()) // Not enabled. |
| 1523 return; |
| 1524 |
| 1525 ResourcePrefetchPredictor::Prediction prediction; |
| 1526 bool has_data = GetPrefetchData(url, &prediction); |
| 1527 DCHECK(has_data); |
| 1528 |
| 1529 BrowserThread::PostTask( |
| 1530 BrowserThread::IO, FROM_HERE, |
| 1531 base::BindOnce(&ResourcePrefetcherManager::MaybeAddPrefetch, |
| 1532 prefetch_manager_, url, prediction.subresource_urls)); |
| 1533 |
| 1534 if (observer_) |
| 1535 observer_->OnPrefetchingStarted(url); |
| 1536 } |
| 1537 |
| 1538 void ResourcePrefetchPredictor::StopPrefetching(const GURL& url) { |
| 1539 TRACE_EVENT1("browser", "ResourcePrefetchPredictor::StopPrefetching", "url", |
| 1540 url.spec()); |
| 1541 if (!prefetch_manager_.get()) // Not enabled. |
| 1542 return; |
| 1543 |
| 1544 BrowserThread::PostTask( |
| 1545 BrowserThread::IO, FROM_HERE, |
| 1546 base::BindOnce(&ResourcePrefetcherManager::MaybeRemovePrefetch, |
| 1547 prefetch_manager_, url)); |
| 1548 |
| 1549 if (observer_) |
| 1550 observer_->OnPrefetchingStopped(url); |
| 1551 } |
| 1552 |
| 1602 //////////////////////////////////////////////////////////////////////////////// | 1553 //////////////////////////////////////////////////////////////////////////////// |
| 1603 // TestObserver. | 1554 // TestObserver. |
| 1604 | 1555 |
| 1605 TestObserver::~TestObserver() { | 1556 TestObserver::~TestObserver() { |
| 1606 predictor_->SetObserverForTesting(nullptr); | 1557 predictor_->SetObserverForTesting(nullptr); |
| 1607 } | 1558 } |
| 1608 | 1559 |
| 1609 TestObserver::TestObserver(ResourcePrefetchPredictor* predictor) | 1560 TestObserver::TestObserver(ResourcePrefetchPredictor* predictor) |
| 1610 : predictor_(predictor) { | 1561 : predictor_(predictor) { |
| 1611 predictor_->SetObserverForTesting(this); | 1562 predictor_->SetObserverForTesting(this); |
| 1612 } | 1563 } |
| 1613 | 1564 |
| 1614 } // namespace predictors | 1565 } // namespace predictors |
| OLD | NEW |