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

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

Issue 1230133005: Fix Resource Priorities and Scheduling (Chrome Side) (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixed holdback of low priority resources Created 5 years, 4 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 <set> 5 #include <set>
6 6
7 #include "content/browser/loader/resource_scheduler.h"
8
9 #include "base/metrics/field_trial.h" 7 #include "base/metrics/field_trial.h"
10 #include "base/metrics/histogram.h" 8 #include "base/metrics/histogram.h"
11 #include "base/stl_util.h" 9 #include "base/stl_util.h"
12 #include "base/strings/string_number_conversions.h" 10 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_piece.h" 11 #include "base/strings/string_piece.h"
14 #include "base/time/time.h" 12 #include "base/time/time.h"
15 #include "content/common/resource_messages.h" 13 #include "content/common/resource_messages.h"
16 #include "content/browser/loader/resource_message_delegate.h" 14 #include "content/browser/loader/resource_message_delegate.h"
15 #include "content/browser/loader/resource_scheduler.h"
mmenke 2015/08/07 16:55:10 This should actually go at the top, before the <se
Pat Meenan 2015/08/07 20:48:10 Done.
17 #include "content/public/browser/resource_controller.h" 16 #include "content/public/browser/resource_controller.h"
18 #include "content/public/browser/resource_request_info.h" 17 #include "content/public/browser/resource_request_info.h"
19 #include "content/public/browser/resource_throttle.h" 18 #include "content/public/browser/resource_throttle.h"
20 #include "ipc/ipc_message_macros.h" 19 #include "ipc/ipc_message_macros.h"
21 #include "net/base/host_port_pair.h" 20 #include "net/base/host_port_pair.h"
22 #include "net/base/load_flags.h" 21 #include "net/base/load_flags.h"
23 #include "net/base/request_priority.h" 22 #include "net/base/request_priority.h"
24 #include "net/http/http_server_properties.h" 23 #include "net/http/http_server_properties.h"
25 #include "net/url_request/url_request.h" 24 #include "net/url_request/url_request.h"
26 #include "net/url_request/url_request_context.h" 25 #include "net/url_request/url_request_context.h"
27 26
28 namespace content { 27 namespace content {
29 28
30 namespace { 29 namespace {
31 30
32 // Field trial constants 31 // Field trial constants
33 const char kThrottleCoalesceFieldTrial[] = "RequestThrottlingAndCoalescing"; 32 const char kThrottleCoalesceFieldTrial[] = "RequestThrottlingAndCoalescing";
34 const char kThrottleCoalesceFieldTrialThrottle[] = "Throttle"; 33 const char kThrottleCoalesceFieldTrialThrottle[] = "Throttle";
35 const char kThrottleCoalesceFieldTrialCoalesce[] = "Coalesce"; 34 const char kThrottleCoalesceFieldTrialCoalesce[] = "Coalesce";
36 35
37 const char kRequestLimitFieldTrial[] = "OutstandingRequestLimiting"; 36 const char kRequestLimitFieldTrial[] = "OutstandingRequestLimiting";
38 const char kRequestLimitFieldTrialGroupPrefix[] = "Limit"; 37 const char kRequestLimitFieldTrialGroupPrefix[] = "Limit";
39 38
39 const char kResourcePrioritiesFieldTrial[] = "ResourcePriorities";
40
40 // Post ResourceScheduler histograms of the following forms: 41 // Post ResourceScheduler histograms of the following forms:
41 // If |histogram_suffix| is NULL or the empty string: 42 // If |histogram_suffix| is NULL or the empty string:
42 // ResourceScheduler.base_name.histogram_name 43 // ResourceScheduler.base_name.histogram_name
43 // Else: 44 // Else:
44 // ResourceScheduler.base_name.histogram_name.histogram_suffix 45 // ResourceScheduler.base_name.histogram_name.histogram_suffix
45 void PostHistogram(const char* base_name, 46 void PostHistogram(const char* base_name,
46 const char* histogram_name, 47 const char* histogram_name,
47 const char* histogram_suffix, 48 const char* histogram_suffix,
48 base::TimeDelta time) { 49 base::TimeDelta time) {
49 std::string histogram = 50 std::string histogram =
(...skipping 19 matching lines...) Expand all
69 else if (num_clients <= 30) 70 else if (num_clients <= 30)
70 return "Max30Clients"; 71 return "Max30Clients";
71 return "Over30Clients"; 72 return "Over30Clients";
72 } 73 }
73 74
74 } // namespace 75 } // namespace
75 76
76 static const size_t kCoalescedTimerPeriod = 5000; 77 static const size_t kCoalescedTimerPeriod = 5000;
77 static const size_t kMaxNumDelayableRequestsPerClient = 10; 78 static const size_t kMaxNumDelayableRequestsPerClient = 10;
78 static const size_t kMaxNumDelayableRequestsPerHost = 6; 79 static const size_t kMaxNumDelayableRequestsPerHost = 6;
79 static const size_t kMaxNumThrottledRequestsPerClient = 1; 80 static const size_t kMaxNumThrottledRequestsPerClient = 1;
mmenke 2015/08/07 16:55:10 +Default
Pat Meenan 2015/08/07 20:48:10 Done.
81 static const size_t kMaxNumDelayableWhileLayoutBlocking = 1;
mmenke 2015/08/07 16:55:11 +Default
Pat Meenan 2015/08/07 20:48:09 Done.
82 static const net::RequestPriority kLayoutBlockingPriorityThreshold = net::LOW;
mmenke 2015/08/07 16:55:11 +Default
Pat Meenan 2015/08/07 20:48:10 Done.
80 83
81 struct ResourceScheduler::RequestPriorityParams { 84 struct ResourceScheduler::RequestPriorityParams {
82 RequestPriorityParams() 85 RequestPriorityParams()
83 : priority(net::DEFAULT_PRIORITY), 86 : priority(net::DEFAULT_PRIORITY),
84 intra_priority(0) { 87 intra_priority(0) {
85 } 88 }
86 89
87 RequestPriorityParams(net::RequestPriority priority, int intra_priority) 90 RequestPriorityParams(net::RequestPriority priority, int intra_priority)
88 : priority(priority), 91 : priority(priority),
89 intra_priority(intra_priority) { 92 intra_priority(intra_priority) {
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after
307 : is_audible_(is_audible), 310 : is_audible_(is_audible),
308 is_visible_(is_visible), 311 is_visible_(is_visible),
309 is_loaded_(false), 312 is_loaded_(false),
310 is_paused_(false), 313 is_paused_(false),
311 has_body_(false), 314 has_body_(false),
312 using_spdy_proxy_(false), 315 using_spdy_proxy_(false),
313 load_started_time_(base::TimeTicks::Now()), 316 load_started_time_(base::TimeTicks::Now()),
314 scheduler_(scheduler), 317 scheduler_(scheduler),
315 in_flight_delayable_count_(0), 318 in_flight_delayable_count_(0),
316 total_layout_blocking_count_(0), 319 total_layout_blocking_count_(0),
317 throttle_state_(ResourceScheduler::THROTTLED) {} 320 throttle_state_(ResourceScheduler::THROTTLED),
321 max_num_delayable_requests_(kMaxNumDelayableRequestsPerClient),
322 max_num_delayable_while_layout_blocking_(
323 kMaxNumDelayableWhileLayoutBlocking),
324 enable_layout_blocking_threshold_(false),
325 in_flight_layout_blocking_threshold_(0),
326 layout_blocking_priority_threshold_(kLayoutBlockingPriorityThreshold) {
327 // The field trial parameters are also encoded into the group name since
328 // the variations component is not available from here and plumbing the
329 // options through the code is overkill for a short experiment.
330 //
331 // The group name encoding looks like this:
332 // <descriptiveName>_ABCDE_E2_F_G
333 // A - fetchDeferLateScripts (1 for true, 0 for false)
334 // B - fetchIncreaseFontPriority (1 for true, 0 for false)
335 // C - fetchIncreaseAsyncScriptPriority (1 for true, 0 for false)
336 // D - fetchIncreasePriorities (1 for true, 0 for false)
337 // E - fetchEnableLayoutBlockingThreshold (1 for true, 0 for false)
338 // E2 - fetchLayoutBlockingThreshold (Numeric)
339 // F - fetchMaxNumDelayableWhileLayoutBlocking (Numeric)
340 // G - fetchMaxNumDelayableRequests (Numeric)
341 std::string resource_priorities_trial_group =
342 base::FieldTrialList::FindFullName(kResourcePrioritiesFieldTrial);
343 std::vector<std::string> split_group(
344 base::SplitString(resource_priorities_trial_group, "_",
345 base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL));
346 if (split_group.size() == 5 && split_group[1].length() == 5) {
347 // fetchIncreasePriorities
348 if (split_group[1].at(3) == '1')
349 layout_blocking_priority_threshold_ = net::MEDIUM;
350 enable_layout_blocking_threshold_ = split_group[1].at(4) == '1';
351 size_t numeric_value = 0;
352 if (base::StringToSizeT(split_group[2], &numeric_value))
353 in_flight_layout_blocking_threshold_ = numeric_value;
354 if (base::StringToSizeT(split_group[3], &numeric_value))
355 max_num_delayable_while_layout_blocking_ = numeric_value;
356 if (base::StringToSizeT(split_group[4], &numeric_value))
357 max_num_delayable_requests_ = numeric_value;
358 }
mmenke 2015/08/07 16:55:11 Why are these per-client variables, and not in the
Pat Meenan 2015/08/07 20:48:10 Moved to the scheduler itself and pass into each c
359 }
318 360
319 ~Client() { 361 ~Client() {
320 // Update to default state and pause to ensure the scheduler has a 362 // Update to default state and pause to ensure the scheduler has a
321 // correct count of relevant types of clients. 363 // correct count of relevant types of clients.
322 is_visible_ = false; 364 is_visible_ = false;
323 is_audible_ = false; 365 is_audible_ = false;
324 is_paused_ = true; 366 is_paused_ = true;
325 UpdateThrottleState(); 367 UpdateThrottleState();
326 } 368 }
327 369
(...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after
618 CountRequestsWithClassification(IN_FLIGHT_DELAYABLE_REQUEST, false), 660 CountRequestsWithClassification(IN_FLIGHT_DELAYABLE_REQUEST, false),
619 in_flight_delayable_count_); 661 in_flight_delayable_count_);
620 DCHECK_EQ(CountRequestsWithClassification(LAYOUT_BLOCKING_REQUEST, true), 662 DCHECK_EQ(CountRequestsWithClassification(LAYOUT_BLOCKING_REQUEST, true),
621 total_layout_blocking_count_); 663 total_layout_blocking_count_);
622 } 664 }
623 665
624 RequestClassification ClassifyRequest(ScheduledResourceRequest* request) { 666 RequestClassification ClassifyRequest(ScheduledResourceRequest* request) {
625 // If a request is already marked as layout-blocking make sure to keep the 667 // If a request is already marked as layout-blocking make sure to keep the
626 // classification across redirects unless the priority was lowered. 668 // classification across redirects unless the priority was lowered.
627 if (request->classification() == LAYOUT_BLOCKING_REQUEST && 669 if (request->classification() == LAYOUT_BLOCKING_REQUEST &&
628 request->url_request()->priority() > net::LOW) { 670 request->url_request()->priority() >
671 layout_blocking_priority_threshold_) {
629 return LAYOUT_BLOCKING_REQUEST; 672 return LAYOUT_BLOCKING_REQUEST;
630 } 673 }
631 674
632 if (!has_body_ && request->url_request()->priority() > net::LOW) 675 if (!has_body_ &&
676 request->url_request()->priority() >
677 layout_blocking_priority_threshold_)
633 return LAYOUT_BLOCKING_REQUEST; 678 return LAYOUT_BLOCKING_REQUEST;
mmenke 2015/08/07 16:55:11 Add braces
mmenke 2015/08/07 16:55:11 Perhaps we should rename this? Either a request b
Pat Meenan 2015/08/07 20:48:09 There are effectively 3 levels of groupings that w
Pat Meenan 2015/08/07 20:48:09 Done.
634 679
635 if (request->url_request()->priority() < net::LOW) { 680 if (request->url_request()->priority() <
636 net::HostPortPair host_port_pair = 681 layout_blocking_priority_threshold_ &&
Bryan McQuade 2015/08/07 18:02:26 why did the hostportpair logic get removed?
Pat Meenan 2015/08/07 20:48:09 It was doing more harm than good. If the resource
637 net::HostPortPair::FromURL(request->url_request()->url()); 682 ContainsKey(in_flight_requests_, request)) {
638 net::HttpServerProperties& http_server_properties = 683 return IN_FLIGHT_DELAYABLE_REQUEST;
639 *request->url_request()->context()->http_server_properties();
640 if (!http_server_properties.SupportsRequestPriority(host_port_pair) &&
641 ContainsKey(in_flight_requests_, request)) {
642 return IN_FLIGHT_DELAYABLE_REQUEST;
643 }
644 } 684 }
645 return NORMAL_REQUEST; 685 return NORMAL_REQUEST;
646 } 686 }
647 687
648 bool ShouldKeepSearching( 688 bool ShouldKeepSearching(
649 const net::HostPortPair& active_request_host) const { 689 const net::HostPortPair& active_request_host) const {
650 size_t same_host_count = 0; 690 size_t same_host_count = 0;
651 for (RequestSet::const_iterator it = in_flight_requests_.begin(); 691 for (RequestSet::const_iterator it = in_flight_requests_.begin();
652 it != in_flight_requests_.end(); ++it) { 692 it != in_flight_requests_.end(); ++it) {
653 net::HostPortPair host_port_pair = 693 net::HostPortPair host_port_pair =
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
762 } 802 }
763 803
764 if (throttle_state_ == THROTTLED && 804 if (throttle_state_ == THROTTLED &&
765 in_flight_requests_.size() >= kMaxNumThrottledRequestsPerClient) { 805 in_flight_requests_.size() >= kMaxNumThrottledRequestsPerClient) {
766 // There may still be request-priority-capable requests that should be 806 // There may still be request-priority-capable requests that should be
767 // issued. 807 // issued.
768 return DO_NOT_START_REQUEST_AND_KEEP_SEARCHING; 808 return DO_NOT_START_REQUEST_AND_KEEP_SEARCHING;
769 } 809 }
770 810
771 // High-priority and layout-blocking requests. 811 // High-priority and layout-blocking requests.
772 if (url_request.priority() >= net::LOW) { 812 if (url_request.priority() >= layout_blocking_priority_threshold_) {
773 return START_REQUEST; 813 return START_REQUEST;
774 } 814 }
775 815
776 if (in_flight_delayable_count_ >= kMaxNumDelayableRequestsPerClient) { 816 if (in_flight_delayable_count_ >= max_num_delayable_requests_) {
777 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING; 817 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING;
778 } 818 }
779 819
780 if (ShouldKeepSearching(host_port_pair)) { 820 if (ShouldKeepSearching(host_port_pair)) {
781 // There may be other requests for other hosts we'd allow, 821 // There may be other requests for other hosts we'd allow,
782 // so keep checking. 822 // so keep checking.
783 return DO_NOT_START_REQUEST_AND_KEEP_SEARCHING; 823 return DO_NOT_START_REQUEST_AND_KEEP_SEARCHING;
784 } 824 }
785 825
786 bool have_immediate_requests_in_flight = 826 if (!has_body_ || total_layout_blocking_count_ != 0) {
787 in_flight_requests_.size() > in_flight_delayable_count_; 827 // Layout-blocking phase of resource loading
mmenke 2015/08/07 16:55:10 Add period (More consistent with other comments he
mmenke 2015/08/07 16:55:11 Suggest comment above the if (I find it easier to
Pat Meenan 2015/08/07 20:48:09 Done.
788 if (have_immediate_requests_in_flight && 828 size_t immediate_requests_in_flight_count =
mmenke 2015/08/07 16:55:11 non_delayable_...?
Pat Meenan 2015/08/07 20:48:09 Done.
789 (!has_body_ || total_layout_blocking_count_ != 0) && 829 in_flight_requests_.size() - in_flight_delayable_count_;
790 // Do not allow a low priority request through in parallel if 830 if (enable_layout_blocking_threshold_) {
791 // we are in a limit field trial. 831 if (immediate_requests_in_flight_count >
792 (scheduler_->limit_outstanding_requests() || 832 in_flight_layout_blocking_threshold_) {
793 in_flight_delayable_count_ != 0)) { 833 // Too many higher priority in-flight requests to allow lower priority
794 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING; 834 // requests through.
835 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING;
836 }
837 if (in_flight_requests_.size() > 0 &&
mmenke 2015/08/07 16:55:11 The other branch only does this if immediate_reque
Pat Meenan 2015/08/07 20:48:09 The difference between the two is pretty significa
838 // Allow the request if nothing is in flight or if the limit of
839 // concurrent lower priority requests has not been hit.
840 (scheduler_->limit_outstanding_requests() ||
841 in_flight_delayable_count_ >=
842 max_num_delayable_while_layout_blocking_)) {
843 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING;
844 }
845 } else if (immediate_requests_in_flight_count > 0 &&
mmenke 2015/08/07 16:55:11 if "total_layout_blocking_count_" is greater than
Pat Meenan 2015/08/07 20:48:09 Sadly, no. This is where the middle group of requ
mmenke 2015/08/07 20:56:02 Oh, I missed that this block is "!has_body_ || tot
846 // If there are no high-priority requests in flight the floodgates
847 // open.
848 // If there are high-priority requests in-flight then limit the number
849 // of lower-priority requests (or zero if a limit field trial is
850 // active).
851 (scheduler_->limit_outstanding_requests() ||
852 in_flight_delayable_count_ >=
853 max_num_delayable_while_layout_blocking_)) {
854 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING;
855 }
795 } 856 }
796 857
797 return START_REQUEST; 858 return START_REQUEST;
798 } 859 }
799 860
800 void LoadAnyStartablePendingRequests() { 861 void LoadAnyStartablePendingRequests() {
801 // We iterate through all the pending requests, starting with the highest 862 // We iterate through all the pending requests, starting with the highest
802 // priority one. For each entry, one of three things can happen: 863 // priority one. For each entry, one of three things can happen:
803 // 1) We start the request, remove it from the list, and keep checking. 864 // 1) We start the request, remove it from the list, and keep checking.
804 // 2) We do NOT start the request, but ShouldStartRequest() signals us that 865 // 2) We do NOT start the request, but ShouldStartRequest() signals us that
(...skipping 26 matching lines...) Expand all
831 DCHECK(query_result == DO_NOT_START_REQUEST_AND_STOP_SEARCHING); 892 DCHECK(query_result == DO_NOT_START_REQUEST_AND_STOP_SEARCHING);
832 break; 893 break;
833 } 894 }
834 } 895 }
835 } 896 }
836 897
837 bool is_audible_; 898 bool is_audible_;
838 bool is_visible_; 899 bool is_visible_;
839 bool is_loaded_; 900 bool is_loaded_;
840 bool is_paused_; 901 bool is_paused_;
841 bool has_body_; 902 bool has_body_;
mmenke 2015/08/07 16:55:10 Please add a description here, and maybe rename it
Pat Meenan 2015/08/07 20:48:10 Done.
842 bool using_spdy_proxy_; 903 bool using_spdy_proxy_;
843 RequestQueue pending_requests_; 904 RequestQueue pending_requests_;
844 RequestSet in_flight_requests_; 905 RequestSet in_flight_requests_;
845 base::TimeTicks load_started_time_; 906 base::TimeTicks load_started_time_;
846 // The last time the client switched state between active and background. 907 // The last time the client switched state between active and background.
847 base::TimeTicks last_active_switch_time_; 908 base::TimeTicks last_active_switch_time_;
848 ResourceScheduler* scheduler_; 909 ResourceScheduler* scheduler_;
849 // The number of delayable in-flight requests. 910 // The number of delayable in-flight requests.
850 size_t in_flight_delayable_count_; 911 size_t in_flight_delayable_count_;
851 // The number of layout-blocking in-flight requests. 912 // The number of layout-blocking in-flight requests.
852 size_t total_layout_blocking_count_; 913 size_t total_layout_blocking_count_;
853 ResourceScheduler::ClientThrottleState throttle_state_; 914 ResourceScheduler::ClientThrottleState throttle_state_;
915 size_t max_num_delayable_requests_;
916 size_t max_num_delayable_while_layout_blocking_;
917 bool enable_layout_blocking_threshold_;
918 size_t in_flight_layout_blocking_threshold_;
919 net::RequestPriority layout_blocking_priority_threshold_;
mmenke 2015/08/07 16:55:10 These really need docs, and could use clearer name
Pat Meenan 2015/08/07 20:48:10 Added docs. Let me know if threshold still doesn'
854 }; 920 };
855 921
856 ResourceScheduler::ResourceScheduler() 922 ResourceScheduler::ResourceScheduler()
857 : should_coalesce_(false), 923 : should_coalesce_(false),
858 should_throttle_(false), 924 should_throttle_(false),
859 active_clients_loading_(0), 925 active_clients_loading_(0),
860 coalesced_clients_(0), 926 coalesced_clients_(0),
861 limit_outstanding_requests_(false), 927 limit_outstanding_requests_(false),
862 outstanding_request_limit_(0), 928 outstanding_request_limit_(0),
863 coalescing_timer_(new base::Timer(true /* retain_user_task */, 929 coalescing_timer_(new base::Timer(true /* retain_user_task */,
(...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after
1202 client->ReprioritizeRequest( 1268 client->ReprioritizeRequest(
1203 request, old_priority_params, new_priority_params); 1269 request, old_priority_params, new_priority_params);
1204 } 1270 }
1205 1271
1206 ResourceScheduler::ClientId ResourceScheduler::MakeClientId( 1272 ResourceScheduler::ClientId ResourceScheduler::MakeClientId(
1207 int child_id, int route_id) { 1273 int child_id, int route_id) {
1208 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id; 1274 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id;
1209 } 1275 }
1210 1276
1211 } // namespace content 1277 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698