Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(81)

Side by Side Diff: content/browser/loader/resource_scheduler.cc

Issue 2435743002: [ResourceScheduler] Throttle H2/QUIC requests just like we do for 1.1 (Closed)
Patch Set: Nit Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "content/browser/loader/resource_scheduler.h" 5 #include "content/browser/loader/resource_scheduler.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 #include <set> 8 #include <set>
9 #include <string> 9 #include <string>
10 #include <utility> 10 #include <utility>
11 #include <vector> 11 #include <vector>
12 12
13 #include "base/feature_list.h"
13 #include "base/macros.h" 14 #include "base/macros.h"
14 #include "base/metrics/field_trial.h" 15 #include "base/metrics/field_trial.h"
15 #include "base/metrics/histogram_macros.h" 16 #include "base/metrics/histogram_macros.h"
16 #include "base/stl_util.h" 17 #include "base/stl_util.h"
17 #include "base/supports_user_data.h" 18 #include "base/supports_user_data.h"
18 #include "content/common/resource_messages.h" 19 #include "content/common/resource_messages.h"
19 #include "content/public/browser/resource_controller.h" 20 #include "content/public/browser/resource_controller.h"
20 #include "content/public/browser/resource_request_info.h" 21 #include "content/public/browser/resource_request_info.h"
21 #include "content/public/browser/resource_throttle.h" 22 #include "content/public/browser/resource_throttle.h"
22 #include "net/base/host_port_pair.h" 23 #include "net/base/host_port_pair.h"
23 #include "net/base/load_flags.h" 24 #include "net/base/load_flags.h"
24 #include "net/base/request_priority.h" 25 #include "net/base/request_priority.h"
25 #include "net/http/http_server_properties.h" 26 #include "net/http/http_server_properties.h"
26 #include "net/url_request/url_request.h" 27 #include "net/url_request/url_request.h"
27 #include "net/url_request/url_request_context.h" 28 #include "net/url_request/url_request_context.h"
28 #include "url/scheme_host_port.h" 29 #include "url/scheme_host_port.h"
29 30
30 namespace content { 31 namespace content {
31 32
32 namespace { 33 namespace {
33 34
35 // When kPrioritySupportedRequestsDelayable is enabled, requests for
36 // H2/QUIC/SPDY resources can be delayed by the ResourceScheduler just as
37 // HTTP/1.1 resources are. Disabling this appears to have negative performance
38 // impact, see https://crbug.com/655585.
39 const base::Feature kPrioritySupportedRequestsDelayable{
40 "PrioritySupportedRequestsDelayable", base::FEATURE_ENABLED_BY_DEFAULT};
41
34 enum StartMode { 42 enum StartMode {
35 START_SYNC, 43 START_SYNC,
36 START_ASYNC 44 START_ASYNC
37 }; 45 };
38 46
39 // Flags identifying various attributes of the request that are used 47 // Flags identifying various attributes of the request that are used
40 // when making scheduling decisions. 48 // when making scheduling decisions.
41 using RequestAttributes = uint8_t; 49 using RequestAttributes = uint8_t;
42 const RequestAttributes kAttributeNone = 0x00; 50 const RequestAttributes kAttributeNone = 0x00;
43 const RequestAttributes kAttributeInFlight = 0x01; 51 const RequestAttributes kAttributeInFlight = 0x01;
(...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after
297 void ResourceScheduler::RequestQueue::Insert( 305 void ResourceScheduler::RequestQueue::Insert(
298 ScheduledResourceRequest* request) { 306 ScheduledResourceRequest* request) {
299 DCHECK(!base::ContainsKey(pointers_, request)); 307 DCHECK(!base::ContainsKey(pointers_, request));
300 request->set_fifo_ordering(MakeFifoOrderingId()); 308 request->set_fifo_ordering(MakeFifoOrderingId());
301 pointers_[request] = queue_.insert(request); 309 pointers_[request] = queue_.insert(request);
302 } 310 }
303 311
304 // Each client represents a tab. 312 // Each client represents a tab.
305 class ResourceScheduler::Client { 313 class ResourceScheduler::Client {
306 public: 314 public:
307 explicit Client(ResourceScheduler* scheduler) 315 explicit Client(bool priority_requests_delayable)
308 : is_loaded_(false), 316 : is_loaded_(false),
309 has_html_body_(false), 317 has_html_body_(false),
310 using_spdy_proxy_(false), 318 using_spdy_proxy_(false),
311 in_flight_delayable_count_(0), 319 in_flight_delayable_count_(0),
312 total_layout_blocking_count_(0) {} 320 total_layout_blocking_count_(0),
321 priority_requests_delayable_(priority_requests_delayable) {}
313 322
314 ~Client() {} 323 ~Client() {}
315 324
316 void ScheduleRequest(net::URLRequest* url_request, 325 void ScheduleRequest(net::URLRequest* url_request,
317 ScheduledResourceRequest* request) { 326 ScheduledResourceRequest* request) {
318 SetRequestAttributes(request, DetermineRequestAttributes(request)); 327 SetRequestAttributes(request, DetermineRequestAttributes(request));
319 if (ShouldStartRequest(request) == START_REQUEST) { 328 if (ShouldStartRequest(request) == START_REQUEST) {
320 // New requests can be started synchronously without issue. 329 // New requests can be started synchronously without issue.
321 StartRequest(request, START_SYNC); 330 StartRequest(request, START_SYNC);
322 } else { 331 } else {
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after
506 // attribute across redirects. 515 // attribute across redirects.
507 attributes |= kAttributeLayoutBlocking; 516 attributes |= kAttributeLayoutBlocking;
508 } else if (!has_html_body_ && 517 } else if (!has_html_body_ &&
509 request->url_request()->priority() > 518 request->url_request()->priority() >
510 kLayoutBlockingPriorityThreshold) { 519 kLayoutBlockingPriorityThreshold) {
511 // Requests that are above the non_delayable threshold before the HTML 520 // Requests that are above the non_delayable threshold before the HTML
512 // body has been parsed are inferred to be layout-blocking. 521 // body has been parsed are inferred to be layout-blocking.
513 attributes |= kAttributeLayoutBlocking; 522 attributes |= kAttributeLayoutBlocking;
514 } else if (request->url_request()->priority() < 523 } else if (request->url_request()->priority() <
515 kDelayablePriorityThreshold) { 524 kDelayablePriorityThreshold) {
516 // Resources below the delayable priority threshold that are being 525 if (priority_requests_delayable_) {
517 // requested from a server that does not support native prioritization are 526 // Resources below the delayable priority threshold that are considered
518 // considered delayable. 527 // delayable.
519 url::SchemeHostPort scheme_host_port(request->url_request()->url());
520 net::HttpServerProperties& http_server_properties =
521 *request->url_request()->context()->http_server_properties();
522 if (!http_server_properties.SupportsRequestPriority(scheme_host_port))
523 attributes |= kAttributeDelayable; 528 attributes |= kAttributeDelayable;
529 } else {
530 // Resources below the delayable priority threshold that are being
531 // requested from a server that does not support native prioritization
532 // are considered delayable.
533 url::SchemeHostPort scheme_host_port(request->url_request()->url());
534 net::HttpServerProperties& http_server_properties =
535 *request->url_request()->context()->http_server_properties();
536 if (!http_server_properties.SupportsRequestPriority(scheme_host_port))
537 attributes |= kAttributeDelayable;
538 }
524 } 539 }
525 540
526 return attributes; 541 return attributes;
527 } 542 }
528 543
529 bool ShouldKeepSearching( 544 bool ShouldKeepSearching(
530 const net::HostPortPair& active_request_host) const { 545 const net::HostPortPair& active_request_host) const {
531 size_t same_host_count = 0; 546 size_t same_host_count = 0;
532 for (RequestSet::const_iterator it = in_flight_requests_.begin(); 547 for (RequestSet::const_iterator it = in_flight_requests_.begin();
533 it != in_flight_requests_.end(); ++it) { 548 it != in_flight_requests_.end(); ++it) {
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
588 // Syncronous requests could block the entire render, which could impact 603 // Syncronous requests could block the entire render, which could impact
589 // user-observable Clients. 604 // user-observable Clients.
590 if (!request->is_async()) 605 if (!request->is_async())
591 return START_REQUEST; 606 return START_REQUEST;
592 607
593 // TODO(simonjam): This may end up causing disk contention. We should 608 // TODO(simonjam): This may end up causing disk contention. We should
594 // experiment with throttling if that happens. 609 // experiment with throttling if that happens.
595 if (!url_request.url().SchemeIsHTTPOrHTTPS()) 610 if (!url_request.url().SchemeIsHTTPOrHTTPS())
596 return START_REQUEST; 611 return START_REQUEST;
597 612
598 if (using_spdy_proxy_ && url_request.url().SchemeIs(url::kHttpScheme))
599 return START_REQUEST;
600
601 net::HostPortPair host_port_pair = 613 net::HostPortPair host_port_pair =
602 net::HostPortPair::FromURL(url_request.url()); 614 net::HostPortPair::FromURL(url_request.url());
603 url::SchemeHostPort scheme_host_port(url_request.url());
604 net::HttpServerProperties& http_server_properties =
605 *url_request.context()->http_server_properties();
606 615
607 // TODO(willchan): We should really improve this algorithm as described in 616 if (!priority_requests_delayable_) {
608 // crbug.com/164101. Also, theoretically we should not count a 617 if (using_spdy_proxy_ && url_request.url().SchemeIs(url::kHttpScheme))
609 // request-priority capable request against the delayable requests limit. 618 return START_REQUEST;
610 if (http_server_properties.SupportsRequestPriority(scheme_host_port)) 619
611 return START_REQUEST; 620 url::SchemeHostPort scheme_host_port(url_request.url());
621
622 net::HttpServerProperties& http_server_properties =
623 *url_request.context()->http_server_properties();
624
625 // TODO(willchan): We should really improve this algorithm as described in
626 // crbug.com/164101. Also, theoretically we should not count a
627 // request-priority capable request against the delayable requests limit.
628 if (http_server_properties.SupportsRequestPriority(scheme_host_port))
629 return START_REQUEST;
630 }
612 631
613 // Non-delayable requests. 632 // Non-delayable requests.
614 if (!RequestAttributesAreSet(request->attributes(), kAttributeDelayable)) 633 if (!RequestAttributesAreSet(request->attributes(), kAttributeDelayable))
615 return START_REQUEST; 634 return START_REQUEST;
616 635
617 if (in_flight_delayable_count_ >= kMaxNumDelayableRequestsPerClient) 636 if (in_flight_delayable_count_ >= kMaxNumDelayableRequestsPerClient)
618 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING; 637 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING;
619 638
620 if (ShouldKeepSearching(host_port_pair)) { 639 if (ShouldKeepSearching(host_port_pair)) {
621 // There may be other requests for other hosts that may be allowed, 640 // There may be other requests for other hosts that may be allowed,
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
691 // Tracks if the main HTML parser has reached the body which marks the end of 710 // Tracks if the main HTML parser has reached the body which marks the end of
692 // layout-blocking resources. 711 // layout-blocking resources.
693 bool has_html_body_; 712 bool has_html_body_;
694 bool using_spdy_proxy_; 713 bool using_spdy_proxy_;
695 RequestQueue pending_requests_; 714 RequestQueue pending_requests_;
696 RequestSet in_flight_requests_; 715 RequestSet in_flight_requests_;
697 // The number of delayable in-flight requests. 716 // The number of delayable in-flight requests.
698 size_t in_flight_delayable_count_; 717 size_t in_flight_delayable_count_;
699 // The number of layout-blocking in-flight requests. 718 // The number of layout-blocking in-flight requests.
700 size_t total_layout_blocking_count_; 719 size_t total_layout_blocking_count_;
720
721 // True if requests to servers that support priorities (e.g., H2/QUIC) can
722 // be delayed.
723 bool priority_requests_delayable_;
701 }; 724 };
702 725
703 ResourceScheduler::ResourceScheduler() {} 726 ResourceScheduler::ResourceScheduler()
727 : priority_requests_delayable_(
728 base::FeatureList::IsEnabled(kPrioritySupportedRequestsDelayable)) {}
704 729
705 ResourceScheduler::~ResourceScheduler() { 730 ResourceScheduler::~ResourceScheduler() {
706 DCHECK(unowned_requests_.empty()); 731 DCHECK(unowned_requests_.empty());
707 DCHECK(client_map_.empty()); 732 DCHECK(client_map_.empty());
708 } 733 }
709 734
710 std::unique_ptr<ResourceThrottle> ResourceScheduler::ScheduleRequest( 735 std::unique_ptr<ResourceThrottle> ResourceScheduler::ScheduleRequest(
711 int child_id, 736 int child_id,
712 int route_id, 737 int route_id,
713 bool is_async, 738 bool is_async,
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
750 Client* client = client_it->second; 775 Client* client = client_it->second;
751 client->RemoveRequest(request); 776 client->RemoveRequest(request);
752 } 777 }
753 778
754 void ResourceScheduler::OnClientCreated(int child_id, 779 void ResourceScheduler::OnClientCreated(int child_id,
755 int route_id) { 780 int route_id) {
756 DCHECK(CalledOnValidThread()); 781 DCHECK(CalledOnValidThread());
757 ClientId client_id = MakeClientId(child_id, route_id); 782 ClientId client_id = MakeClientId(child_id, route_id);
758 DCHECK(!base::ContainsKey(client_map_, client_id)); 783 DCHECK(!base::ContainsKey(client_map_, client_id));
759 784
760 Client* client = new Client(this); 785 Client* client = new Client(priority_requests_delayable_);
761 client_map_[client_id] = client; 786 client_map_[client_id] = client;
762 } 787 }
763 788
764 void ResourceScheduler::OnClientDeleted(int child_id, int route_id) { 789 void ResourceScheduler::OnClientDeleted(int child_id, int route_id) {
765 DCHECK(CalledOnValidThread()); 790 DCHECK(CalledOnValidThread());
766 ClientId client_id = MakeClientId(child_id, route_id); 791 ClientId client_id = MakeClientId(child_id, route_id);
767 ClientMap::iterator it = client_map_.find(client_id); 792 ClientMap::iterator it = client_map_.find(client_id);
768 DCHECK(it != client_map_.end()); 793 DCHECK(it != client_map_.end());
769 794
770 Client* client = it->second; 795 Client* client = it->second;
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
889 client->ReprioritizeRequest(scheduled_resource_request, old_priority_params, 914 client->ReprioritizeRequest(scheduled_resource_request, old_priority_params,
890 new_priority_params); 915 new_priority_params);
891 } 916 }
892 917
893 ResourceScheduler::ClientId ResourceScheduler::MakeClientId( 918 ResourceScheduler::ClientId ResourceScheduler::MakeClientId(
894 int child_id, int route_id) { 919 int child_id, int route_id) {
895 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id; 920 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id;
896 } 921 }
897 922
898 } // namespace content 923 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/loader/resource_scheduler.h ('k') | content/browser/loader/resource_scheduler_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698