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

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

Issue 2708323002: Revert of [ResourceScheduler] Yield after starting several requests (Closed)
Patch Set: Created 3 years, 10 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/feature_list.h"
14 #include "base/macros.h" 14 #include "base/macros.h"
15 #include "base/metrics/field_trial.h" 15 #include "base/metrics/field_trial.h"
16 #include "base/metrics/field_trial_params.h"
17 #include "base/metrics/histogram_macros.h" 16 #include "base/metrics/histogram_macros.h"
18 #include "base/stl_util.h" 17 #include "base/stl_util.h"
19 #include "base/supports_user_data.h" 18 #include "base/supports_user_data.h"
20 #include "base/threading/thread_task_runner_handle.h" 19 #include "base/threading/thread_task_runner_handle.h"
21 #include "content/common/resource_messages.h" 20 #include "content/common/resource_messages.h"
22 #include "content/public/browser/resource_request_info.h" 21 #include "content/public/browser/resource_request_info.h"
23 #include "content/public/browser/resource_throttle.h" 22 #include "content/public/browser/resource_throttle.h"
24 #include "net/base/host_port_pair.h" 23 #include "net/base/host_port_pair.h"
25 #include "net/base/load_flags.h" 24 #include "net/base/load_flags.h"
26 #include "net/base/request_priority.h" 25 #include "net/base/request_priority.h"
27 #include "net/http/http_server_properties.h" 26 #include "net/http/http_server_properties.h"
28 #include "net/url_request/url_request.h" 27 #include "net/url_request/url_request.h"
29 #include "net/url_request/url_request_context.h" 28 #include "net/url_request/url_request_context.h"
30 #include "url/scheme_host_port.h" 29 #include "url/scheme_host_port.h"
31 30
32 namespace content { 31 namespace content {
33 32
34 namespace { 33 namespace {
35 34
36 // When kPrioritySupportedRequestsDelayable is enabled, requests for 35 // When kPrioritySupportedRequestsDelayable is enabled, requests for
37 // H2/QUIC/SPDY resources can be delayed by the ResourceScheduler just as 36 // H2/QUIC/SPDY resources can be delayed by the ResourceScheduler just as
38 // HTTP/1.1 resources are. Disabling this appears to have negative performance 37 // HTTP/1.1 resources are. Disabling this appears to have negative performance
39 // impact, see https://crbug.com/655585. 38 // impact, see https://crbug.com/655585.
40 const base::Feature kPrioritySupportedRequestsDelayable{ 39 const base::Feature kPrioritySupportedRequestsDelayable{
41 "PrioritySupportedRequestsDelayable", base::FEATURE_DISABLED_BY_DEFAULT}; 40 "PrioritySupportedRequestsDelayable", base::FEATURE_DISABLED_BY_DEFAULT};
42 41
43 // In the event that many resource requests are started quickly, this feature
44 // will periodically yield (e.g., delaying starting of requests) by posting a
45 // task and waiting for the task to run to resume. This allows other
46 // operations that rely on the IO thread (e.g., already running network
47 // requests) to make progress.
48 const base::Feature kNetworkSchedulerYielding{
49 "NetworkSchedulerYielding", base::FEATURE_DISABLED_BY_DEFAULT};
50 const char kMaxRequestsBeforeYieldingParam[] = "MaxRequestsBeforeYieldingParam";
51 const int kMaxRequestsBeforeYieldingDefault = 5;
52
53 enum StartMode { 42 enum StartMode {
54 START_SYNC, 43 START_SYNC,
55 START_ASYNC 44 START_ASYNC
56 }; 45 };
57 46
58 // Flags identifying various attributes of the request that are used 47 // Flags identifying various attributes of the request that are used
59 // when making scheduling decisions. 48 // when making scheduling decisions.
60 using RequestAttributes = uint8_t; 49 using RequestAttributes = uint8_t;
61 const RequestAttributes kAttributeNone = 0x00; 50 const RequestAttributes kAttributeNone = 0x00;
62 const RequestAttributes kAttributeInFlight = 0x01; 51 const RequestAttributes kAttributeInFlight = 0x01;
63 const RequestAttributes kAttributeDelayable = 0x02; 52 const RequestAttributes kAttributeDelayable = 0x02;
64 const RequestAttributes kAttributeLayoutBlocking = 0x04; 53 const RequestAttributes kAttributeLayoutBlocking = 0x04;
65 54
66 // Reasons why pending requests may be started. For logging only. 55 // Reasons why pending requests may be started. For logging only.
67 enum class RequestStartTrigger { 56 enum class RequestStartTrigger {
68 NONE, 57 NONE,
69 COMPLETION_PRE_BODY, 58 COMPLETION_PRE_BODY,
70 COMPLETION_POST_BODY, 59 COMPLETION_POST_BODY,
71 BODY_REACHED, 60 BODY_REACHED,
72 CLIENT_KILL, 61 CLIENT_KILL,
73 SPDY_PROXY_DETECTED, 62 SPDY_PROXY_DETECTED,
74 REQUEST_REPRIORITIZED, 63 REQUEST_REPRIORITIZED,
75 START_WAS_YIELDED,
76 }; 64 };
77 65
78 const char* RequestStartTriggerString(RequestStartTrigger trigger) { 66 const char* RequestStartTriggerString(RequestStartTrigger trigger) {
79 switch (trigger) { 67 switch (trigger) {
80 case RequestStartTrigger::NONE: 68 case RequestStartTrigger::NONE:
81 return "NONE"; 69 return "NONE";
82 case RequestStartTrigger::COMPLETION_PRE_BODY: 70 case RequestStartTrigger::COMPLETION_PRE_BODY:
83 return "COMPLETION_PRE_BODY"; 71 return "COMPLETION_PRE_BODY";
84 case RequestStartTrigger::COMPLETION_POST_BODY: 72 case RequestStartTrigger::COMPLETION_POST_BODY:
85 return "COMPLETION_POST_BODY"; 73 return "COMPLETION_POST_BODY";
86 case RequestStartTrigger::BODY_REACHED: 74 case RequestStartTrigger::BODY_REACHED:
87 return "BODY_REACHED"; 75 return "BODY_REACHED";
88 case RequestStartTrigger::CLIENT_KILL: 76 case RequestStartTrigger::CLIENT_KILL:
89 return "CLIENT_KILL"; 77 return "CLIENT_KILL";
90 case RequestStartTrigger::SPDY_PROXY_DETECTED: 78 case RequestStartTrigger::SPDY_PROXY_DETECTED:
91 return "SPDY_PROXY_DETECTED"; 79 return "SPDY_PROXY_DETECTED";
92 case RequestStartTrigger::REQUEST_REPRIORITIZED: 80 case RequestStartTrigger::REQUEST_REPRIORITIZED:
93 return "REQUEST_REPRIORITIZED"; 81 return "REQUEST_REPRIORITIZED";
94 case RequestStartTrigger::START_WAS_YIELDED:
95 return "START_WAS_YIELDED";
96 } 82 }
97 NOTREACHED(); 83 NOTREACHED();
98 return "Unknown"; 84 return "Unknown";
99 } 85 }
100 86
101 } // namespace 87 } // namespace
102 88
103 // The maximum number of delayable requests to allow to be in-flight at any 89 // The maximum number of delayable requests to allow to be in-flight at any
104 // point in time (across all hosts). 90 // point in time (across all hosts).
105 static const size_t kMaxNumDelayableRequestsPerClient = 10; 91 static const size_t kMaxNumDelayableRequestsPerClient = 10;
(...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after
355 void ResourceScheduler::RequestQueue::Insert( 341 void ResourceScheduler::RequestQueue::Insert(
356 ScheduledResourceRequest* request) { 342 ScheduledResourceRequest* request) {
357 DCHECK(!base::ContainsKey(pointers_, request)); 343 DCHECK(!base::ContainsKey(pointers_, request));
358 request->set_fifo_ordering(MakeFifoOrderingId()); 344 request->set_fifo_ordering(MakeFifoOrderingId());
359 pointers_[request] = queue_.insert(request); 345 pointers_[request] = queue_.insert(request);
360 } 346 }
361 347
362 // Each client represents a tab. 348 // Each client represents a tab.
363 class ResourceScheduler::Client { 349 class ResourceScheduler::Client {
364 public: 350 public:
365 Client(bool priority_requests_delayable, 351 explicit Client(bool priority_requests_delayable)
366 bool yielding_scheduler_enabled,
367 int max_requests_before_yielding)
368 : is_loaded_(false), 352 : is_loaded_(false),
369 has_html_body_(false), 353 has_html_body_(false),
370 using_spdy_proxy_(false), 354 using_spdy_proxy_(false),
371 in_flight_delayable_count_(0), 355 in_flight_delayable_count_(0),
372 total_layout_blocking_count_(0), 356 total_layout_blocking_count_(0),
373 priority_requests_delayable_(priority_requests_delayable), 357 priority_requests_delayable_(priority_requests_delayable),
374 has_pending_start_task_(false), 358 has_pending_start_task_(false),
375 requests_since_yielding_(0),
376 yielding_scheduler_enabled_(yielding_scheduler_enabled),
377 max_requests_before_yielding_(max_requests_before_yielding),
378 weak_ptr_factory_(this) {} 359 weak_ptr_factory_(this) {}
379 360
380 ~Client() {} 361 ~Client() {}
381 362
382 void ScheduleRequest(net::URLRequest* url_request, 363 void ScheduleRequest(net::URLRequest* url_request,
383 ScheduledResourceRequest* request) { 364 ScheduledResourceRequest* request) {
384 SetRequestAttributes(request, DetermineRequestAttributes(request)); 365 SetRequestAttributes(request, DetermineRequestAttributes(request));
385 if (ShouldStartRequest(request) == START_REQUEST && 366 if (ShouldStartRequest(request) == START_REQUEST) {
386 (!request->is_async() || !ShouldYieldScheduler())) {
387 // New requests can be started synchronously without issue. 367 // New requests can be started synchronously without issue.
388 StartRequest(request, START_SYNC, RequestStartTrigger::NONE); 368 StartRequest(request, START_SYNC, RequestStartTrigger::NONE);
389 } else { 369 } else {
390 pending_requests_.Insert(request); 370 pending_requests_.Insert(request);
391 } 371 }
392 } 372 }
393 373
394 void RemoveRequest(ScheduledResourceRequest* request) { 374 void RemoveRequest(ScheduledResourceRequest* request) {
395 if (pending_requests_.IsQueued(request)) { 375 if (pending_requests_.IsQueued(request)) {
396 pending_requests_.Erase(request); 376 pending_requests_.Erase(request);
(...skipping 354 matching lines...) Expand 10 before | Expand all | Expand 10 after
751 // pattern. 731 // pattern.
752 void ScheduleLoadAnyStartablePendingRequests(RequestStartTrigger trigger) { 732 void ScheduleLoadAnyStartablePendingRequests(RequestStartTrigger trigger) {
753 if (has_pending_start_task_) 733 if (has_pending_start_task_)
754 return; 734 return;
755 has_pending_start_task_ = true; 735 has_pending_start_task_ = true;
756 base::ThreadTaskRunnerHandle::Get()->PostTask( 736 base::ThreadTaskRunnerHandle::Get()->PostTask(
757 FROM_HERE, base::Bind(&Client::LoadAnyStartablePendingRequests, 737 FROM_HERE, base::Bind(&Client::LoadAnyStartablePendingRequests,
758 weak_ptr_factory_.GetWeakPtr(), trigger)); 738 weak_ptr_factory_.GetWeakPtr(), trigger));
759 } 739 }
760 740
761 void ResumeAfterYielding() {
762 bool yielded_requests =
763 requests_since_yielding_ > max_requests_before_yielding_;
764 requests_since_yielding_ = 0;
765
766 if (yielded_requests)
767 LoadAnyStartablePendingRequests(RequestStartTrigger::START_WAS_YIELDED);
768 }
769
770 // Returns true if the scheduler should not start the next request and
771 // instead return so that other tasks can run on the IO thread (e.g.,
772 // existing network requests). If it returns true, ShouldYieldScheduler will
773 // have already scheduled a task to resume after yielding.
774 bool ShouldYieldScheduler() {
775 if (!yielding_scheduler_enabled_)
776 return false;
777
778 requests_since_yielding_ += 1;
779
780 if (requests_since_yielding_ == 1) {
781 // This is the first request since last yielding. Post a task to reset the
782 // counter and start any yielded tasks if necessary. We post this now
783 // instead of when we first yield so that if there is a pause between
784 // requests the counter is reset.
785 base::ThreadTaskRunnerHandle::Get()->PostTask(
786 FROM_HERE, base::Bind(&Client::ResumeAfterYielding,
787 weak_ptr_factory_.GetWeakPtr()));
788 }
789
790 return requests_since_yielding_ > max_requests_before_yielding_;
791 }
792
793 void LoadAnyStartablePendingRequests(RequestStartTrigger trigger) { 741 void LoadAnyStartablePendingRequests(RequestStartTrigger trigger) {
794 // We iterate through all the pending requests, starting with the highest 742 // We iterate through all the pending requests, starting with the highest
795 // priority one. For each entry, one of three things can happen: 743 // priority one. For each entry, one of three things can happen:
796 // 1) We start the request, remove it from the list, and keep checking. 744 // 1) We start the request, remove it from the list, and keep checking.
797 // 2) We do NOT start the request, but ShouldStartRequest() signals us that 745 // 2) We do NOT start the request, but ShouldStartRequest() signals us that
798 // there may be room for other requests, so we keep checking and leave 746 // there may be room for other requests, so we keep checking and leave
799 // the previous request still in the list. 747 // the previous request still in the list.
800 // 3) We do not start the request, same as above, but StartRequest() tells 748 // 3) We do not start the request, same as above, but StartRequest() tells
801 // us there's no point in checking any further requests. 749 // us there's no point in checking any further requests.
802 has_pending_start_task_ = false; 750 has_pending_start_task_ = false;
803 RequestQueue::NetQueue::iterator request_iter = 751 RequestQueue::NetQueue::iterator request_iter =
804 pending_requests_.GetNextHighestIterator(); 752 pending_requests_.GetNextHighestIterator();
805 753
806 while (request_iter != pending_requests_.End()) { 754 while (request_iter != pending_requests_.End()) {
807 ScheduledResourceRequest* request = *request_iter; 755 ScheduledResourceRequest* request = *request_iter;
808 ShouldStartReqResult query_result = ShouldStartRequest(request); 756 ShouldStartReqResult query_result = ShouldStartRequest(request);
809 757
810 if (query_result == START_REQUEST) { 758 if (query_result == START_REQUEST) {
811 if (ShouldYieldScheduler())
812 break;
813
814 pending_requests_.Erase(request); 759 pending_requests_.Erase(request);
815 StartRequest(request, START_ASYNC, trigger); 760 StartRequest(request, START_ASYNC, trigger);
816 761
817 // StartRequest can modify the pending list, so we (re)start evaluation 762 // StartRequest can modify the pending list, so we (re)start evaluation
818 // from the currently highest priority request. Avoid copying a singular 763 // from the currently highest priority request. Avoid copying a singular
819 // iterator, which would trigger undefined behavior. 764 // iterator, which would trigger undefined behavior.
820 if (pending_requests_.GetNextHighestIterator() == 765 if (pending_requests_.GetNextHighestIterator() ==
821 pending_requests_.End()) 766 pending_requests_.End())
822 break; 767 break;
823 request_iter = pending_requests_.GetNextHighestIterator(); 768 request_iter = pending_requests_.GetNextHighestIterator();
(...skipping 18 matching lines...) Expand all
842 size_t in_flight_delayable_count_; 787 size_t in_flight_delayable_count_;
843 // The number of layout-blocking in-flight requests. 788 // The number of layout-blocking in-flight requests.
844 size_t total_layout_blocking_count_; 789 size_t total_layout_blocking_count_;
845 790
846 // True if requests to servers that support priorities (e.g., H2/QUIC) can 791 // True if requests to servers that support priorities (e.g., H2/QUIC) can
847 // be delayed. 792 // be delayed.
848 bool priority_requests_delayable_; 793 bool priority_requests_delayable_;
849 794
850 bool has_pending_start_task_; 795 bool has_pending_start_task_;
851 796
852 // The number of requests that have been started since the last
853 // ResumeAfterYielding task was posted.
854 int requests_since_yielding_;
855
856 // Whether or not to periodically yield when starting lots of requests.
857 bool yielding_scheduler_enabled_;
858
859 // The number of requests that can start before yielding.
860 int max_requests_before_yielding_;
861
862 base::WeakPtrFactory<ResourceScheduler::Client> weak_ptr_factory_; 797 base::WeakPtrFactory<ResourceScheduler::Client> weak_ptr_factory_;
863 }; 798 };
864 799
865 ResourceScheduler::ResourceScheduler() 800 ResourceScheduler::ResourceScheduler()
866 : priority_requests_delayable_( 801 : priority_requests_delayable_(
867 base::FeatureList::IsEnabled(kPrioritySupportedRequestsDelayable)), 802 base::FeatureList::IsEnabled(kPrioritySupportedRequestsDelayable)) {}
868 yielding_scheduler_enabled_(
869 base::FeatureList::IsEnabled(kNetworkSchedulerYielding)),
870 max_requests_before_yielding_(base::GetFieldTrialParamByFeatureAsInt(
871 kNetworkSchedulerYielding,
872 kMaxRequestsBeforeYieldingParam,
873 kMaxRequestsBeforeYieldingDefault)) {}
874 803
875 ResourceScheduler::~ResourceScheduler() { 804 ResourceScheduler::~ResourceScheduler() {
876 DCHECK(unowned_requests_.empty()); 805 DCHECK(unowned_requests_.empty());
877 DCHECK(client_map_.empty()); 806 DCHECK(client_map_.empty());
878 } 807 }
879 808
880 std::unique_ptr<ResourceThrottle> ResourceScheduler::ScheduleRequest( 809 std::unique_ptr<ResourceThrottle> ResourceScheduler::ScheduleRequest(
881 int child_id, 810 int child_id,
882 int route_id, 811 int route_id,
883 bool is_async, 812 bool is_async,
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
920 Client* client = client_it->second; 849 Client* client = client_it->second;
921 client->RemoveRequest(request); 850 client->RemoveRequest(request);
922 } 851 }
923 852
924 void ResourceScheduler::OnClientCreated(int child_id, 853 void ResourceScheduler::OnClientCreated(int child_id,
925 int route_id) { 854 int route_id) {
926 DCHECK(CalledOnValidThread()); 855 DCHECK(CalledOnValidThread());
927 ClientId client_id = MakeClientId(child_id, route_id); 856 ClientId client_id = MakeClientId(child_id, route_id);
928 DCHECK(!base::ContainsKey(client_map_, client_id)); 857 DCHECK(!base::ContainsKey(client_map_, client_id));
929 858
930 Client* client = 859 Client* client = new Client(priority_requests_delayable_);
931 new Client(priority_requests_delayable_, yielding_scheduler_enabled_,
932 max_requests_before_yielding_);
933 client_map_[client_id] = client; 860 client_map_[client_id] = client;
934 } 861 }
935 862
936 void ResourceScheduler::OnClientDeleted(int child_id, int route_id) { 863 void ResourceScheduler::OnClientDeleted(int child_id, int route_id) {
937 DCHECK(CalledOnValidThread()); 864 DCHECK(CalledOnValidThread());
938 ClientId client_id = MakeClientId(child_id, route_id); 865 ClientId client_id = MakeClientId(child_id, route_id);
939 ClientMap::iterator it = client_map_.find(client_id); 866 ClientMap::iterator it = client_map_.find(client_id);
940 DCHECK(it != client_map_.end()); 867 DCHECK(it != client_map_.end());
941 868
942 Client* client = it->second; 869 Client* client = it->second;
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
1061 client->ReprioritizeRequest(scheduled_resource_request, old_priority_params, 988 client->ReprioritizeRequest(scheduled_resource_request, old_priority_params,
1062 new_priority_params); 989 new_priority_params);
1063 } 990 }
1064 991
1065 ResourceScheduler::ClientId ResourceScheduler::MakeClientId( 992 ResourceScheduler::ClientId ResourceScheduler::MakeClientId(
1066 int child_id, int route_id) { 993 int child_id, int route_id) {
1067 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id; 994 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id;
1068 } 995 }
1069 996
1070 } // namespace content 997 } // 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