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 |