| 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 380 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 391 std::any_of(std::begin(kFontMimeTypes), std::end(kFontMimeTypes), | 391 std::any_of(std::begin(kFontMimeTypes), std::end(kFontMimeTypes), |
| 392 [&mime_type](const std::string& mime) { | 392 [&mime_type](const std::string& mime) { |
| 393 return net::MatchesMimeType(mime, mime_type); | 393 return net::MatchesMimeType(mime, mime_type); |
| 394 }); | 394 }); |
| 395 if (found) | 395 if (found) |
| 396 return content::RESOURCE_TYPE_FONT_RESOURCE; | 396 return content::RESOURCE_TYPE_FONT_RESOURCE; |
| 397 } | 397 } |
| 398 return fallback; | 398 return fallback; |
| 399 } | 399 } |
| 400 | 400 |
| 401 // static | |
| 402 bool ResourcePrefetchPredictor::GetRedirectEndpoint( | 401 bool ResourcePrefetchPredictor::GetRedirectEndpoint( |
| 403 const std::string& first_redirect, | 402 const std::string& entry_point, |
| 404 const RedirectDataMap& redirect_data_map, | 403 const RedirectDataMap& redirect_data_map, |
| 405 std::string* final_redirect) { | 404 std::string* redirect_endpoint) const { |
| 406 DCHECK(final_redirect); | 405 DCHECK(redirect_endpoint); |
| 407 | 406 |
| 408 RedirectDataMap::const_iterator it = redirect_data_map.find(first_redirect); | 407 RedirectDataMap::const_iterator it = redirect_data_map.find(entry_point); |
| 409 if (it == redirect_data_map.end()) | 408 if (it == redirect_data_map.end()) { |
| 410 return false; | 409 // Fallback to fetching URLs based on the incoming URL/host. By default |
| 410 // the predictor is confident that there is no redirect. |
| 411 *redirect_endpoint = entry_point; |
| 412 return true; |
| 413 } |
| 411 | 414 |
| 412 const RedirectData& redirect_data = it->second; | 415 const RedirectData& redirect_data = it->second; |
| 413 auto best_redirect = std::max_element( | 416 DCHECK_GT(redirect_data.redirect_endpoints_size(), 0); |
| 414 redirect_data.redirect_endpoints().begin(), | 417 if (redirect_data.redirect_endpoints_size() > 1) { |
| 415 redirect_data.redirect_endpoints().end(), | 418 // The predictor observed multiple redirect destinations recently. Redirect |
| 416 [](const RedirectStat& x, const RedirectStat& y) { | 419 // endpoint is ambiguous. The predictor predicts a redirect only if it |
| 417 return ComputeRedirectConfidence(x) < ComputeRedirectConfidence(y); | 420 // believes that the redirect is "permanent", i.e. subsequent navigations |
| 418 }); | 421 // will lead to the same destination. |
| 422 return false; |
| 423 } |
| 419 | 424 |
| 420 const float kMinRedirectConfidenceToTriggerPrefetch = 0.7f; | 425 // The threshold is higher than the threshold for resources because the |
| 426 // redirect misprediction causes the waste of whole prefetch. |
| 427 const float kMinRedirectConfidenceToTriggerPrefetch = 0.9f; |
| 421 const int kMinRedirectHitsToTriggerPrefetch = 2; | 428 const int kMinRedirectHitsToTriggerPrefetch = 2; |
| 422 | 429 |
| 423 if (best_redirect == redirect_data.redirect_endpoints().end() || | 430 // The predictor doesn't apply a minimum-number-of-hits threshold to |
| 424 ComputeRedirectConfidence(*best_redirect) < | 431 // the no-redirect case because the no-redirect is a default assumption. |
| 432 const RedirectStat& redirect = redirect_data.redirect_endpoints(0); |
| 433 if (ComputeRedirectConfidence(redirect) < |
| 425 kMinRedirectConfidenceToTriggerPrefetch || | 434 kMinRedirectConfidenceToTriggerPrefetch || |
| 426 best_redirect->number_of_hits() < kMinRedirectHitsToTriggerPrefetch) | 435 (redirect.number_of_hits() < kMinRedirectHitsToTriggerPrefetch && |
| 436 redirect.url() != entry_point)) { |
| 427 return false; | 437 return false; |
| 438 } |
| 428 | 439 |
| 429 *final_redirect = best_redirect->url(); | 440 *redirect_endpoint = redirect.url(); |
| 430 return true; | 441 return true; |
| 431 } | 442 } |
| 432 | 443 |
| 433 // static | 444 // static |
| 434 void ResourcePrefetchPredictor::SetAllowPortInUrlsForTesting(bool state) { | 445 void ResourcePrefetchPredictor::SetAllowPortInUrlsForTesting(bool state) { |
| 435 g_allow_port_in_urls = state; | 446 g_allow_port_in_urls = state; |
| 436 } | 447 } |
| 437 | 448 |
| 438 //////////////////////////////////////////////////////////////////////////////// | 449 //////////////////////////////////////////////////////////////////////////////// |
| 439 // ResourcePrefetchPredictor nested types. | 450 // ResourcePrefetchPredictor nested types. |
| (...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 862 } | 873 } |
| 863 } | 874 } |
| 864 | 875 |
| 865 bool ResourcePrefetchPredictor::GetPrefetchData( | 876 bool ResourcePrefetchPredictor::GetPrefetchData( |
| 866 const GURL& main_frame_url, | 877 const GURL& main_frame_url, |
| 867 ResourcePrefetchPredictor::Prediction* prediction) const { | 878 ResourcePrefetchPredictor::Prediction* prediction) const { |
| 868 std::vector<GURL>* urls = | 879 std::vector<GURL>* urls = |
| 869 prediction ? &prediction->subresource_urls : nullptr; | 880 prediction ? &prediction->subresource_urls : nullptr; |
| 870 DCHECK(!urls || urls->empty()); | 881 DCHECK(!urls || urls->empty()); |
| 871 | 882 |
| 872 // Fetch URLs based on a redirect endpoint for URL/host first. | 883 // Fetch resources using URL-keyed data first. |
| 873 std::string redirect_endpoint; | 884 std::string redirect_endpoint; |
| 885 const std::string& main_frame_url_spec = main_frame_url.spec(); |
| 874 if (config_.is_url_learning_enabled && | 886 if (config_.is_url_learning_enabled && |
| 875 GetRedirectEndpoint(main_frame_url.spec(), *url_redirect_table_cache_, | 887 GetRedirectEndpoint(main_frame_url_spec, *url_redirect_table_cache_, |
| 876 &redirect_endpoint) && | 888 &redirect_endpoint) && |
| 877 PopulatePrefetcherRequest(redirect_endpoint, *url_table_cache_, urls)) { | 889 PopulatePrefetcherRequest(redirect_endpoint, *url_table_cache_, urls)) { |
| 878 if (prediction) { | 890 if (prediction) { |
| 879 prediction->is_host = false; | 891 prediction->is_host = false; |
| 880 prediction->is_redirected = true; | |
| 881 prediction->main_frame_key = redirect_endpoint; | 892 prediction->main_frame_key = redirect_endpoint; |
| 893 prediction->is_redirected = (redirect_endpoint != main_frame_url_spec); |
| 882 } | 894 } |
| 883 return true; | 895 return true; |
| 884 } | 896 } |
| 885 | 897 |
| 886 if (GetRedirectEndpoint(main_frame_url.host(), *host_redirect_table_cache_, | 898 // Use host data if the URL-based prediction isn't available. |
| 899 std::string main_frame_url_host = main_frame_url.host(); |
| 900 if (GetRedirectEndpoint(main_frame_url_host, *host_redirect_table_cache_, |
| 887 &redirect_endpoint) && | 901 &redirect_endpoint) && |
| 888 PopulatePrefetcherRequest(redirect_endpoint, *host_table_cache_, urls)) { | 902 PopulatePrefetcherRequest(redirect_endpoint, *host_table_cache_, urls)) { |
| 889 if (prediction) { | 903 if (prediction) { |
| 890 prediction->is_host = true; | 904 prediction->is_host = true; |
| 891 prediction->is_redirected = true; | |
| 892 prediction->main_frame_key = redirect_endpoint; | 905 prediction->main_frame_key = redirect_endpoint; |
| 906 prediction->is_redirected = (redirect_endpoint != main_frame_url_host); |
| 893 } | 907 } |
| 894 return true; | 908 return true; |
| 895 } | 909 } |
| 896 | |
| 897 // Fallback to fetching URLs based on the incoming URL/host. | |
| 898 if (config_.is_url_learning_enabled && | |
| 899 PopulatePrefetcherRequest(main_frame_url.spec(), *url_table_cache_, | |
| 900 urls)) { | |
| 901 if (prediction) { | |
| 902 prediction->is_host = false; | |
| 903 prediction->is_redirected = false; | |
| 904 prediction->main_frame_key = main_frame_url.spec(); | |
| 905 } | |
| 906 return true; | |
| 907 } | |
| 908 | |
| 909 if (PopulatePrefetcherRequest(main_frame_url.host(), *host_table_cache_, | |
| 910 urls)) { | |
| 911 if (prediction) { | |
| 912 prediction->is_host = true; | |
| 913 prediction->is_redirected = false; | |
| 914 prediction->main_frame_key = main_frame_url.host(); | |
| 915 } | |
| 916 return true; | |
| 917 } | |
| 918 | 910 |
| 919 return false; | 911 return false; |
| 920 } | 912 } |
| 921 | 913 |
| 922 bool ResourcePrefetchPredictor::PopulatePrefetcherRequest( | 914 bool ResourcePrefetchPredictor::PopulatePrefetcherRequest( |
| 923 const std::string& main_frame_key, | 915 const std::string& main_frame_key, |
| 924 const PrefetchDataMap& data_map, | 916 const PrefetchDataMap& data_map, |
| 925 std::vector<GURL>* urls) const { | 917 std::vector<GURL>* urls) const { |
| 926 PrefetchDataMap::const_iterator it = data_map.find(main_frame_key); | 918 PrefetchDataMap::const_iterator it = data_map.find(main_frame_key); |
| 927 if (it == data_map.end()) | 919 if (it == data_map.end()) |
| (...skipping 472 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1400 bool is_host = key_type == PREFETCH_KEY_TYPE_HOST; | 1392 bool is_host = key_type == PREFETCH_KEY_TYPE_HOST; |
| 1401 const PrefetchData& host_data = is_host ? data : empty_data; | 1393 const PrefetchData& host_data = is_host ? data : empty_data; |
| 1402 const PrefetchData& url_data = is_host ? empty_data : data; | 1394 const PrefetchData& url_data = is_host ? empty_data : data; |
| 1403 BrowserThread::PostTask( | 1395 BrowserThread::PostTask( |
| 1404 BrowserThread::DB, FROM_HERE, | 1396 BrowserThread::DB, FROM_HERE, |
| 1405 base::Bind(&ResourcePrefetchPredictorTables::UpdateData, tables_, | 1397 base::Bind(&ResourcePrefetchPredictorTables::UpdateData, tables_, |
| 1406 url_data, host_data, empty_redirect_data, | 1398 url_data, host_data, empty_redirect_data, |
| 1407 empty_redirect_data)); | 1399 empty_redirect_data)); |
| 1408 } | 1400 } |
| 1409 | 1401 |
| 1410 if (key != key_before_redirects) { | 1402 // Predictor learns about both redirected and non-redirected destinations to |
| 1411 LearnRedirect(key_before_redirects, key_type, key, max_data_map_size, | 1403 // estimate whether the endpoint is permanent. |
| 1412 redirect_map); | 1404 LearnRedirect(key_before_redirects, key_type, key, max_data_map_size, |
| 1413 } | 1405 redirect_map); |
| 1414 } | 1406 } |
| 1415 | 1407 |
| 1416 void ResourcePrefetchPredictor::LearnRedirect(const std::string& key, | 1408 void ResourcePrefetchPredictor::LearnRedirect(const std::string& key, |
| 1417 PrefetchKeyType key_type, | 1409 PrefetchKeyType key_type, |
| 1418 const std::string& final_redirect, | 1410 const std::string& final_redirect, |
| 1419 size_t max_redirect_map_size, | 1411 size_t max_redirect_map_size, |
| 1420 RedirectDataMap* redirect_map) { | 1412 RedirectDataMap* redirect_map) { |
| 1421 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 1413 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 1422 // If the primary key is too long reject it. | 1414 // If the primary key is too long reject it. |
| 1423 if (key.length() > ResourcePrefetchPredictorTables::kMaxStringLength) | 1415 if (key.length() > ResourcePrefetchPredictorTables::kMaxStringLength) |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1455 if (need_to_add) { | 1447 if (need_to_add) { |
| 1456 RedirectStat* redirect_to_add = data.add_redirect_endpoints(); | 1448 RedirectStat* redirect_to_add = data.add_redirect_endpoints(); |
| 1457 redirect_to_add->set_url(final_redirect); | 1449 redirect_to_add->set_url(final_redirect); |
| 1458 redirect_to_add->set_number_of_hits(1); | 1450 redirect_to_add->set_number_of_hits(1); |
| 1459 } | 1451 } |
| 1460 } | 1452 } |
| 1461 | 1453 |
| 1462 RedirectData& data = cache_entry->second; | 1454 RedirectData& data = cache_entry->second; |
| 1463 // Trim the redirects after the update. | 1455 // Trim the redirects after the update. |
| 1464 ResourcePrefetchPredictorTables::TrimRedirects( | 1456 ResourcePrefetchPredictorTables::TrimRedirects( |
| 1465 &data, config_.max_consecutive_misses); | 1457 &data, config_.max_redirect_consecutive_misses); |
| 1466 | 1458 |
| 1467 if (data.redirect_endpoints_size() == 0) { | 1459 if (data.redirect_endpoints_size() == 0) { |
| 1468 redirect_map->erase(cache_entry); | 1460 redirect_map->erase(cache_entry); |
| 1469 BrowserThread::PostTask( | 1461 BrowserThread::PostTask( |
| 1470 BrowserThread::DB, FROM_HERE, | 1462 BrowserThread::DB, FROM_HERE, |
| 1471 base::Bind( | 1463 base::Bind( |
| 1472 &ResourcePrefetchPredictorTables::DeleteSingleRedirectDataPoint, | 1464 &ResourcePrefetchPredictorTables::DeleteSingleRedirectDataPoint, |
| 1473 tables_, key, key_type)); | 1465 tables_, key, key_type)); |
| 1474 } else { | 1466 } else { |
| 1475 RedirectData empty_redirect_data; | 1467 RedirectData empty_redirect_data; |
| (...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1706 TestObserver::~TestObserver() { | 1698 TestObserver::~TestObserver() { |
| 1707 predictor_->SetObserverForTesting(nullptr); | 1699 predictor_->SetObserverForTesting(nullptr); |
| 1708 } | 1700 } |
| 1709 | 1701 |
| 1710 TestObserver::TestObserver(ResourcePrefetchPredictor* predictor) | 1702 TestObserver::TestObserver(ResourcePrefetchPredictor* predictor) |
| 1711 : predictor_(predictor) { | 1703 : predictor_(predictor) { |
| 1712 predictor_->SetObserverForTesting(this); | 1704 predictor_->SetObserverForTesting(this); |
| 1713 } | 1705 } |
| 1714 | 1706 |
| 1715 } // namespace predictors | 1707 } // namespace predictors |
| OLD | NEW |