| 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 451 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 462 first_occurrence(0) {} | 462 first_occurrence(0) {} |
| 463 | 463 |
| 464 ResourcePrefetchPredictor::OriginRequestSummary::OriginRequestSummary( | 464 ResourcePrefetchPredictor::OriginRequestSummary::OriginRequestSummary( |
| 465 const OriginRequestSummary& other) = default; | 465 const OriginRequestSummary& other) = default; |
| 466 | 466 |
| 467 ResourcePrefetchPredictor::OriginRequestSummary::~OriginRequestSummary() {} | 467 ResourcePrefetchPredictor::OriginRequestSummary::~OriginRequestSummary() {} |
| 468 | 468 |
| 469 ResourcePrefetchPredictor::URLRequestSummary::URLRequestSummary() | 469 ResourcePrefetchPredictor::URLRequestSummary::URLRequestSummary() |
| 470 : resource_type(content::RESOURCE_TYPE_LAST_TYPE), | 470 : resource_type(content::RESOURCE_TYPE_LAST_TYPE), |
| 471 priority(net::IDLE), | 471 priority(net::IDLE), |
| 472 before_first_contentful_paint(false), |
| 472 was_cached(false), | 473 was_cached(false), |
| 473 has_validators(false), | 474 has_validators(false), |
| 474 always_revalidate(false), | 475 always_revalidate(false), |
| 475 is_no_store(false), | 476 is_no_store(false), |
| 476 network_accessed(false) {} | 477 network_accessed(false) {} |
| 477 | 478 |
| 478 ResourcePrefetchPredictor::URLRequestSummary::URLRequestSummary( | 479 ResourcePrefetchPredictor::URLRequestSummary::URLRequestSummary( |
| 479 const URLRequestSummary& other) = default; | 480 const URLRequestSummary& other) = default; |
| 480 | 481 |
| 481 ResourcePrefetchPredictor::URLRequestSummary::~URLRequestSummary() { | 482 ResourcePrefetchPredictor::URLRequestSummary::~URLRequestSummary() { |
| 482 } | 483 } |
| 483 | 484 |
| 484 // static | 485 // static |
| 485 bool ResourcePrefetchPredictor::URLRequestSummary::SummarizeResponse( | 486 bool ResourcePrefetchPredictor::URLRequestSummary::SummarizeResponse( |
| 486 const net::URLRequest& request, | 487 const net::URLRequest& request, |
| 487 URLRequestSummary* summary) { | 488 URLRequestSummary* summary) { |
| 488 const content::ResourceRequestInfo* request_info = | 489 const content::ResourceRequestInfo* request_info = |
| 489 content::ResourceRequestInfo::ForRequest(&request); | 490 content::ResourceRequestInfo::ForRequest(&request); |
| 490 if (!request_info) | 491 if (!request_info) |
| 491 return false; | 492 return false; |
| 492 | 493 |
| 494 // This method is called when the response is started, so this field reflects |
| 495 // the time at which the response began, not when it finished, as would |
| 496 // arguably be ideal. This means if firstContentfulPaint happens after the |
| 497 // response has started, but before it's finished, we will erroneously mark |
| 498 // the resource as having been loaded before firstContentfulPaint. This is |
| 499 // a rare and insignificant enough occurrence that we opt to record the time |
| 500 // here for the sake of simplicity. |
| 501 summary->response_time = base::TimeTicks::Now(); |
| 493 summary->resource_url = request.original_url(); | 502 summary->resource_url = request.original_url(); |
| 494 summary->request_url = request.url(); | 503 summary->request_url = request.url(); |
| 495 content::ResourceType resource_type_from_request = | 504 content::ResourceType resource_type_from_request = |
| 496 request_info->GetResourceType(); | 505 request_info->GetResourceType(); |
| 497 summary->priority = request.priority(); | 506 summary->priority = request.priority(); |
| 498 request.GetMimeType(&summary->mime_type); | 507 request.GetMimeType(&summary->mime_type); |
| 499 summary->was_cached = request.was_cached(); | 508 summary->was_cached = request.was_cached(); |
| 500 summary->resource_type = | 509 summary->resource_type = |
| 501 GetResourceType(resource_type_from_request, summary->mime_type); | 510 GetResourceType(resource_type_from_request, summary->mime_type); |
| 502 | 511 |
| 503 scoped_refptr<net::HttpResponseHeaders> headers = | 512 scoped_refptr<net::HttpResponseHeaders> headers = |
| 504 request.response_info().headers; | 513 request.response_info().headers; |
| 505 if (headers.get()) { | 514 if (headers.get()) { |
| 506 summary->has_validators = headers->HasValidators(); | 515 summary->has_validators = headers->HasValidators(); |
| 507 // RFC 2616, section 14.9. | 516 // RFC 2616, section 14.9. |
| 508 summary->always_revalidate = | 517 summary->always_revalidate = |
| 509 headers->HasHeaderValue("cache-control", "no-cache") || | 518 headers->HasHeaderValue("cache-control", "no-cache") || |
| 510 headers->HasHeaderValue("pragma", "no-cache") || | 519 headers->HasHeaderValue("pragma", "no-cache") || |
| 511 headers->HasHeaderValue("vary", "*"); | 520 headers->HasHeaderValue("vary", "*"); |
| 512 summary->is_no_store = IsNoStore(request); | 521 summary->is_no_store = IsNoStore(request); |
| 513 } | 522 } |
| 514 summary->network_accessed = request.response_info().network_accessed; | 523 summary->network_accessed = request.response_info().network_accessed; |
| 515 return true; | 524 return true; |
| 516 } | 525 } |
| 517 | 526 |
| 518 ResourcePrefetchPredictor::PageRequestSummary::PageRequestSummary( | 527 ResourcePrefetchPredictor::PageRequestSummary::PageRequestSummary( |
| 519 const GURL& i_main_frame_url) | 528 const GURL& i_main_frame_url) |
| 520 : main_frame_url(i_main_frame_url), initial_url(i_main_frame_url) {} | 529 : main_frame_url(i_main_frame_url), |
| 530 initial_url(i_main_frame_url), |
| 531 first_contentful_paint(base::TimeTicks::Max()) {} |
| 521 | 532 |
| 522 ResourcePrefetchPredictor::PageRequestSummary::PageRequestSummary( | 533 ResourcePrefetchPredictor::PageRequestSummary::PageRequestSummary( |
| 523 const PageRequestSummary& other) = default; | 534 const PageRequestSummary& other) = default; |
| 524 | 535 |
| 525 ResourcePrefetchPredictor::PageRequestSummary::~PageRequestSummary() {} | 536 ResourcePrefetchPredictor::PageRequestSummary::~PageRequestSummary() {} |
| 526 | 537 |
| 527 ResourcePrefetchPredictor::Prediction::Prediction() = default; | 538 ResourcePrefetchPredictor::Prediction::Prediction() = default; |
| 528 | 539 |
| 529 ResourcePrefetchPredictor::Prediction::Prediction( | 540 ResourcePrefetchPredictor::Prediction::Prediction( |
| 530 const ResourcePrefetchPredictor::Prediction& other) = default; | 541 const ResourcePrefetchPredictor::Prediction& other) = default; |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 638 // corresponding to the navigation has not been created yet. | 649 // corresponding to the navigation has not been created yet. |
| 639 if (!navigation_id.main_frame_url.is_empty()) | 650 if (!navigation_id.main_frame_url.is_empty()) |
| 640 OnNavigationComplete(navigation_id); | 651 OnNavigationComplete(navigation_id); |
| 641 break; | 652 break; |
| 642 default: | 653 default: |
| 643 NOTREACHED() << "Unexpected initialization_state_: " | 654 NOTREACHED() << "Unexpected initialization_state_: " |
| 644 << initialization_state_; | 655 << initialization_state_; |
| 645 } | 656 } |
| 646 } | 657 } |
| 647 | 658 |
| 659 void ResourcePrefetchPredictor::RecordFirstContentfulPaint( |
| 660 const NavigationID& navigation_id, |
| 661 const base::TimeTicks& first_contentful_paint) { |
| 662 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 663 if (initialization_state_ != INITIALIZED) |
| 664 return; |
| 665 |
| 666 NavigationMap::iterator nav_it = inflight_navigations_.find(navigation_id); |
| 667 if (nav_it != inflight_navigations_.end()) |
| 668 nav_it->second->first_contentful_paint = first_contentful_paint; |
| 669 } |
| 670 |
| 648 void ResourcePrefetchPredictor::StartPrefetching(const GURL& url, | 671 void ResourcePrefetchPredictor::StartPrefetching(const GURL& url, |
| 649 PrefetchOrigin origin) { | 672 PrefetchOrigin origin) { |
| 650 TRACE_EVENT1("browser", "ResourcePrefetchPredictor::StartPrefetching", "url", | 673 TRACE_EVENT1("browser", "ResourcePrefetchPredictor::StartPrefetching", "url", |
| 651 url.spec()); | 674 url.spec()); |
| 652 // Save prefetch start time to report prefetching duration. | 675 // Save prefetch start time to report prefetching duration. |
| 653 if (inflight_prefetches_.find(url) == inflight_prefetches_.end() && | 676 if (inflight_prefetches_.find(url) == inflight_prefetches_.end() && |
| 654 IsUrlPrefetchable(url)) { | 677 IsUrlPrefetchable(url)) { |
| 655 inflight_prefetches_.insert(std::make_pair(url, base::TimeTicks::Now())); | 678 inflight_prefetches_.insert(std::make_pair(url, base::TimeTicks::Now())); |
| 656 } | 679 } |
| 657 | 680 |
| (...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 837 | 860 |
| 838 NavigationMap::iterator nav_it = | 861 NavigationMap::iterator nav_it = |
| 839 inflight_navigations_.find(nav_id_without_timing_info); | 862 inflight_navigations_.find(nav_id_without_timing_info); |
| 840 if (nav_it == inflight_navigations_.end()) | 863 if (nav_it == inflight_navigations_.end()) |
| 841 return; | 864 return; |
| 842 | 865 |
| 843 // Remove the navigation from the inflight navigations. | 866 // Remove the navigation from the inflight navigations. |
| 844 std::unique_ptr<PageRequestSummary> summary = std::move(nav_it->second); | 867 std::unique_ptr<PageRequestSummary> summary = std::move(nav_it->second); |
| 845 inflight_navigations_.erase(nav_it); | 868 inflight_navigations_.erase(nav_it); |
| 846 | 869 |
| 870 // Set before_first_contentful paint for each resource. |
| 871 for (auto& request_summary : summary->subresource_requests) { |
| 872 request_summary.before_first_contentful_paint = |
| 873 request_summary.response_time < summary->first_contentful_paint; |
| 874 } |
| 875 |
| 847 const GURL& initial_url = summary->initial_url; | 876 const GURL& initial_url = summary->initial_url; |
| 848 ResourcePrefetchPredictor::Prediction prediction; | 877 ResourcePrefetchPredictor::Prediction prediction; |
| 849 bool has_data = GetPrefetchData(initial_url, &prediction); | 878 bool has_data = GetPrefetchData(initial_url, &prediction); |
| 850 if (has_data) | 879 if (has_data) |
| 851 ReportPredictionAccuracy(prediction, *summary); | 880 ReportPredictionAccuracy(prediction, *summary); |
| 852 | 881 |
| 853 auto it = prefetcher_stats_.find(initial_url); | 882 auto it = prefetcher_stats_.find(initial_url); |
| 854 if (it != prefetcher_stats_.end()) { | 883 if (it != prefetcher_stats_.end()) { |
| 855 const std::vector<URLRequestSummary>& summaries = | 884 const std::vector<URLRequestSummary>& summaries = |
| 856 summary->subresource_requests; | 885 summary->subresource_requests; |
| (...skipping 495 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1352 continue; | 1381 continue; |
| 1353 | 1382 |
| 1354 ResourceData* resource_to_add = data.add_resources(); | 1383 ResourceData* resource_to_add = data.add_resources(); |
| 1355 resource_to_add->set_resource_url(summary.resource_url.spec()); | 1384 resource_to_add->set_resource_url(summary.resource_url.spec()); |
| 1356 resource_to_add->set_resource_type( | 1385 resource_to_add->set_resource_type( |
| 1357 static_cast<ResourceData::ResourceType>(summary.resource_type)); | 1386 static_cast<ResourceData::ResourceType>(summary.resource_type)); |
| 1358 resource_to_add->set_number_of_hits(1); | 1387 resource_to_add->set_number_of_hits(1); |
| 1359 resource_to_add->set_average_position(i + 1); | 1388 resource_to_add->set_average_position(i + 1); |
| 1360 resource_to_add->set_priority( | 1389 resource_to_add->set_priority( |
| 1361 static_cast<ResourceData::Priority>(summary.priority)); | 1390 static_cast<ResourceData::Priority>(summary.priority)); |
| 1391 resource_to_add->set_before_first_contentful_paint( |
| 1392 summary.before_first_contentful_paint); |
| 1362 resource_to_add->set_has_validators(summary.has_validators); | 1393 resource_to_add->set_has_validators(summary.has_validators); |
| 1363 resource_to_add->set_always_revalidate(summary.always_revalidate); | 1394 resource_to_add->set_always_revalidate(summary.always_revalidate); |
| 1364 | 1395 |
| 1365 resources_seen.insert(summary.resource_url); | 1396 resources_seen.insert(summary.resource_url); |
| 1366 } | 1397 } |
| 1367 } else { | 1398 } else { |
| 1368 PrefetchData& data = cache_entry->second; | 1399 PrefetchData& data = cache_entry->second; |
| 1369 data.set_last_visit_time(base::Time::Now().ToInternalValue()); | 1400 data.set_last_visit_time(base::Time::Now().ToInternalValue()); |
| 1370 | 1401 |
| 1371 // Build indices over the data. | 1402 // Build indices over the data. |
| (...skipping 29 matching lines...) Expand all Loading... |
| 1401 | 1432 |
| 1402 // Update the resource type since it could have changed. | 1433 // Update the resource type since it could have changed. |
| 1403 if (new_summary.resource_type != content::RESOURCE_TYPE_LAST_TYPE) { | 1434 if (new_summary.resource_type != content::RESOURCE_TYPE_LAST_TYPE) { |
| 1404 old_resource->set_resource_type( | 1435 old_resource->set_resource_type( |
| 1405 static_cast<ResourceData::ResourceType>( | 1436 static_cast<ResourceData::ResourceType>( |
| 1406 new_summary.resource_type)); | 1437 new_summary.resource_type)); |
| 1407 } | 1438 } |
| 1408 | 1439 |
| 1409 old_resource->set_priority( | 1440 old_resource->set_priority( |
| 1410 static_cast<ResourceData::Priority>(new_summary.priority)); | 1441 static_cast<ResourceData::Priority>(new_summary.priority)); |
| 1442 old_resource->set_before_first_contentful_paint( |
| 1443 new_summary.before_first_contentful_paint); |
| 1411 | 1444 |
| 1412 int position = new_index[resource_url] + 1; | 1445 int position = new_index[resource_url] + 1; |
| 1413 int total = | 1446 int total = |
| 1414 old_resource->number_of_hits() + old_resource->number_of_misses(); | 1447 old_resource->number_of_hits() + old_resource->number_of_misses(); |
| 1415 old_resource->set_average_position( | 1448 old_resource->set_average_position( |
| 1416 ((old_resource->average_position() * total) + position) / | 1449 ((old_resource->average_position() * total) + position) / |
| 1417 (total + 1)); | 1450 (total + 1)); |
| 1418 old_resource->set_number_of_hits(old_resource->number_of_hits() + 1); | 1451 old_resource->set_number_of_hits(old_resource->number_of_hits() + 1); |
| 1419 old_resource->set_consecutive_misses(0); | 1452 old_resource->set_consecutive_misses(0); |
| 1420 } | 1453 } |
| 1421 } | 1454 } |
| 1422 | 1455 |
| 1423 // Add the new ones that we have not seen before. | 1456 // Add the new ones that we have not seen before. |
| 1424 for (int i = 0; i < new_resources_size; ++i) { | 1457 for (int i = 0; i < new_resources_size; ++i) { |
| 1425 const URLRequestSummary& summary = new_resources[i]; | 1458 const URLRequestSummary& summary = new_resources[i]; |
| 1426 if (old_index.find(summary.resource_url) != old_index.end()) | 1459 if (old_index.find(summary.resource_url) != old_index.end()) |
| 1427 continue; | 1460 continue; |
| 1428 | 1461 |
| 1429 // Only need to add new stuff. | 1462 // Only need to add new stuff. |
| 1430 ResourceData* resource_to_add = data.add_resources(); | 1463 ResourceData* resource_to_add = data.add_resources(); |
| 1431 resource_to_add->set_resource_url(summary.resource_url.spec()); | 1464 resource_to_add->set_resource_url(summary.resource_url.spec()); |
| 1432 resource_to_add->set_resource_type( | 1465 resource_to_add->set_resource_type( |
| 1433 static_cast<ResourceData::ResourceType>(summary.resource_type)); | 1466 static_cast<ResourceData::ResourceType>(summary.resource_type)); |
| 1434 resource_to_add->set_number_of_hits(1); | 1467 resource_to_add->set_number_of_hits(1); |
| 1435 resource_to_add->set_average_position(i + 1); | 1468 resource_to_add->set_average_position(i + 1); |
| 1436 resource_to_add->set_priority( | 1469 resource_to_add->set_priority( |
| 1437 static_cast<ResourceData::Priority>(summary.priority)); | 1470 static_cast<ResourceData::Priority>(summary.priority)); |
| 1471 resource_to_add->set_before_first_contentful_paint( |
| 1472 summary.before_first_contentful_paint); |
| 1438 resource_to_add->set_has_validators(new_resources[i].has_validators); | 1473 resource_to_add->set_has_validators(new_resources[i].has_validators); |
| 1439 resource_to_add->set_always_revalidate( | 1474 resource_to_add->set_always_revalidate( |
| 1440 new_resources[i].always_revalidate); | 1475 new_resources[i].always_revalidate); |
| 1441 | 1476 |
| 1442 // To ensure we dont add the same url twice. | 1477 // To ensure we dont add the same url twice. |
| 1443 old_index[summary.resource_url] = 0; | 1478 old_index[summary.resource_url] = 0; |
| 1444 } | 1479 } |
| 1445 } | 1480 } |
| 1446 | 1481 |
| 1447 PrefetchData& data = cache_entry->second; | 1482 PrefetchData& data = cache_entry->second; |
| (...skipping 368 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1816 TestObserver::~TestObserver() { | 1851 TestObserver::~TestObserver() { |
| 1817 predictor_->SetObserverForTesting(nullptr); | 1852 predictor_->SetObserverForTesting(nullptr); |
| 1818 } | 1853 } |
| 1819 | 1854 |
| 1820 TestObserver::TestObserver(ResourcePrefetchPredictor* predictor) | 1855 TestObserver::TestObserver(ResourcePrefetchPredictor* predictor) |
| 1821 : predictor_(predictor) { | 1856 : predictor_(predictor) { |
| 1822 predictor_->SetObserverForTesting(this); | 1857 predictor_->SetObserverForTesting(this); |
| 1823 } | 1858 } |
| 1824 | 1859 |
| 1825 } // namespace predictors | 1860 } // namespace predictors |
| OLD | NEW |