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

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

Issue 2711633003: Reland of [ResourceScheduler] Yield after starting several requests (Closed)
Patch Set: Fix, and now tests pass 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"
16 #include "base/metrics/histogram_macros.h" 17 #include "base/metrics/histogram_macros.h"
17 #include "base/stl_util.h" 18 #include "base/stl_util.h"
18 #include "base/supports_user_data.h" 19 #include "base/supports_user_data.h"
19 #include "base/threading/thread_task_runner_handle.h" 20 #include "base/threading/thread_task_runner_handle.h"
20 #include "content/common/resource_messages.h" 21 #include "content/common/resource_messages.h"
21 #include "content/public/browser/resource_request_info.h" 22 #include "content/public/browser/resource_request_info.h"
22 #include "content/public/browser/resource_throttle.h" 23 #include "content/public/browser/resource_throttle.h"
23 #include "net/base/host_port_pair.h" 24 #include "net/base/host_port_pair.h"
24 #include "net/base/load_flags.h" 25 #include "net/base/load_flags.h"
25 #include "net/base/request_priority.h" 26 #include "net/base/request_priority.h"
26 #include "net/http/http_server_properties.h" 27 #include "net/http/http_server_properties.h"
27 #include "net/url_request/url_request.h" 28 #include "net/url_request/url_request.h"
28 #include "net/url_request/url_request_context.h" 29 #include "net/url_request/url_request_context.h"
29 #include "url/scheme_host_port.h" 30 #include "url/scheme_host_port.h"
30 31
31 namespace content { 32 namespace content {
32 33
33 namespace { 34 namespace {
34 35
35 // When kPrioritySupportedRequestsDelayable is enabled, requests for 36 // When kPrioritySupportedRequestsDelayable is enabled, requests for
36 // H2/QUIC/SPDY resources can be delayed by the ResourceScheduler just as 37 // 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 // HTTP/1.1 resources are. Disabling this appears to have negative performance
38 // impact, see https://crbug.com/655585. 39 // impact, see https://crbug.com/655585.
39 const base::Feature kPrioritySupportedRequestsDelayable{ 40 const base::Feature kPrioritySupportedRequestsDelayable{
40 "PrioritySupportedRequestsDelayable", base::FEATURE_DISABLED_BY_DEFAULT}; 41 "PrioritySupportedRequestsDelayable", base::FEATURE_DISABLED_BY_DEFAULT};
41 42
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
42 enum StartMode { 53 enum StartMode {
43 START_SYNC, 54 START_SYNC,
44 START_ASYNC 55 START_ASYNC
45 }; 56 };
46 57
47 // Flags identifying various attributes of the request that are used 58 // Flags identifying various attributes of the request that are used
48 // when making scheduling decisions. 59 // when making scheduling decisions.
49 using RequestAttributes = uint8_t; 60 using RequestAttributes = uint8_t;
50 const RequestAttributes kAttributeNone = 0x00; 61 const RequestAttributes kAttributeNone = 0x00;
51 const RequestAttributes kAttributeInFlight = 0x01; 62 const RequestAttributes kAttributeInFlight = 0x01;
52 const RequestAttributes kAttributeDelayable = 0x02; 63 const RequestAttributes kAttributeDelayable = 0x02;
53 const RequestAttributes kAttributeLayoutBlocking = 0x04; 64 const RequestAttributes kAttributeLayoutBlocking = 0x04;
54 65
55 // Reasons why pending requests may be started. For logging only. 66 // Reasons why pending requests may be started. For logging only.
56 enum class RequestStartTrigger { 67 enum class RequestStartTrigger {
57 NONE, 68 NONE,
58 COMPLETION_PRE_BODY, 69 COMPLETION_PRE_BODY,
59 COMPLETION_POST_BODY, 70 COMPLETION_POST_BODY,
60 BODY_REACHED, 71 BODY_REACHED,
61 CLIENT_KILL, 72 CLIENT_KILL,
62 SPDY_PROXY_DETECTED, 73 SPDY_PROXY_DETECTED,
63 REQUEST_REPRIORITIZED, 74 REQUEST_REPRIORITIZED,
75 START_WAS_YIELDED,
64 }; 76 };
65 77
66 const char* RequestStartTriggerString(RequestStartTrigger trigger) { 78 const char* RequestStartTriggerString(RequestStartTrigger trigger) {
67 switch (trigger) { 79 switch (trigger) {
68 case RequestStartTrigger::NONE: 80 case RequestStartTrigger::NONE:
69 return "NONE"; 81 return "NONE";
70 case RequestStartTrigger::COMPLETION_PRE_BODY: 82 case RequestStartTrigger::COMPLETION_PRE_BODY:
71 return "COMPLETION_PRE_BODY"; 83 return "COMPLETION_PRE_BODY";
72 case RequestStartTrigger::COMPLETION_POST_BODY: 84 case RequestStartTrigger::COMPLETION_POST_BODY:
73 return "COMPLETION_POST_BODY"; 85 return "COMPLETION_POST_BODY";
74 case RequestStartTrigger::BODY_REACHED: 86 case RequestStartTrigger::BODY_REACHED:
75 return "BODY_REACHED"; 87 return "BODY_REACHED";
76 case RequestStartTrigger::CLIENT_KILL: 88 case RequestStartTrigger::CLIENT_KILL:
77 return "CLIENT_KILL"; 89 return "CLIENT_KILL";
78 case RequestStartTrigger::SPDY_PROXY_DETECTED: 90 case RequestStartTrigger::SPDY_PROXY_DETECTED:
79 return "SPDY_PROXY_DETECTED"; 91 return "SPDY_PROXY_DETECTED";
80 case RequestStartTrigger::REQUEST_REPRIORITIZED: 92 case RequestStartTrigger::REQUEST_REPRIORITIZED:
81 return "REQUEST_REPRIORITIZED"; 93 return "REQUEST_REPRIORITIZED";
94 case RequestStartTrigger::START_WAS_YIELDED:
95 return "START_WAS_YIELDED";
82 } 96 }
83 NOTREACHED(); 97 NOTREACHED();
84 return "Unknown"; 98 return "Unknown";
85 } 99 }
86 100
87 } // namespace 101 } // namespace
88 102
89 // The maximum number of delayable requests to allow to be in-flight at any 103 // The maximum number of delayable requests to allow to be in-flight at any
90 // point in time (across all hosts). 104 // point in time (across all hosts).
91 static const size_t kMaxNumDelayableRequestsPerClient = 10; 105 static const size_t kMaxNumDelayableRequestsPerClient = 10;
(...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after
341 void ResourceScheduler::RequestQueue::Insert( 355 void ResourceScheduler::RequestQueue::Insert(
342 ScheduledResourceRequest* request) { 356 ScheduledResourceRequest* request) {
343 DCHECK(!base::ContainsKey(pointers_, request)); 357 DCHECK(!base::ContainsKey(pointers_, request));
344 request->set_fifo_ordering(MakeFifoOrderingId()); 358 request->set_fifo_ordering(MakeFifoOrderingId());
345 pointers_[request] = queue_.insert(request); 359 pointers_[request] = queue_.insert(request);
346 } 360 }
347 361
348 // Each client represents a tab. 362 // Each client represents a tab.
349 class ResourceScheduler::Client { 363 class ResourceScheduler::Client {
350 public: 364 public:
351 explicit Client(bool priority_requests_delayable) 365 Client(bool priority_requests_delayable,
366 bool yielding_scheduler_enabled,
367 int max_requests_before_yielding)
352 : is_loaded_(false), 368 : is_loaded_(false),
353 has_html_body_(false), 369 has_html_body_(false),
354 using_spdy_proxy_(false), 370 using_spdy_proxy_(false),
355 in_flight_delayable_count_(0), 371 in_flight_delayable_count_(0),
356 total_layout_blocking_count_(0), 372 total_layout_blocking_count_(0),
357 priority_requests_delayable_(priority_requests_delayable), 373 priority_requests_delayable_(priority_requests_delayable),
358 has_pending_start_task_(false), 374 has_pending_start_task_(false),
375 started_requests_since_yielding_(0),
376 did_scheduler_yield_(false),
377 yielding_scheduler_enabled_(yielding_scheduler_enabled),
378 max_requests_before_yielding_(max_requests_before_yielding),
359 weak_ptr_factory_(this) {} 379 weak_ptr_factory_(this) {}
360 380
361 ~Client() {} 381 ~Client() {}
362 382
363 void ScheduleRequest(net::URLRequest* url_request, 383 void ScheduleRequest(net::URLRequest* url_request,
364 ScheduledResourceRequest* request) { 384 ScheduledResourceRequest* request) {
365 SetRequestAttributes(request, DetermineRequestAttributes(request)); 385 SetRequestAttributes(request, DetermineRequestAttributes(request));
366 if (ShouldStartRequest(request) == START_REQUEST) { 386 ShouldStartReqResult should_start = ShouldStartRequest(request);
387 if (should_start == START_REQUEST) {
367 // New requests can be started synchronously without issue. 388 // New requests can be started synchronously without issue.
368 StartRequest(request, START_SYNC, RequestStartTrigger::NONE); 389 StartRequest(request, START_SYNC, RequestStartTrigger::NONE);
369 } else { 390 } else {
370 pending_requests_.Insert(request); 391 pending_requests_.Insert(request);
392 if (should_start == YIELD_SCHEDULER)
393 did_scheduler_yield_ = true;
371 } 394 }
372 } 395 }
373 396
374 void RemoveRequest(ScheduledResourceRequest* request) { 397 void RemoveRequest(ScheduledResourceRequest* request) {
375 if (pending_requests_.IsQueued(request)) { 398 if (pending_requests_.IsQueued(request)) {
376 pending_requests_.Erase(request); 399 pending_requests_.Erase(request);
377 DCHECK(!base::ContainsKey(in_flight_requests_, request)); 400 DCHECK(!base::ContainsKey(in_flight_requests_, request));
378 } else { 401 } else {
379 EraseInFlightRequest(request); 402 EraseInFlightRequest(request);
380 403
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
457 ScheduleLoadAnyStartablePendingRequests( 480 ScheduleLoadAnyStartablePendingRequests(
458 RequestStartTrigger::REQUEST_REPRIORITIZED); 481 RequestStartTrigger::REQUEST_REPRIORITIZED);
459 } 482 }
460 } 483 }
461 484
462 private: 485 private:
463 enum ShouldStartReqResult { 486 enum ShouldStartReqResult {
464 DO_NOT_START_REQUEST_AND_STOP_SEARCHING, 487 DO_NOT_START_REQUEST_AND_STOP_SEARCHING,
465 DO_NOT_START_REQUEST_AND_KEEP_SEARCHING, 488 DO_NOT_START_REQUEST_AND_KEEP_SEARCHING,
466 START_REQUEST, 489 START_REQUEST,
490 YIELD_SCHEDULER
467 }; 491 };
468 492
469 void InsertInFlightRequest(ScheduledResourceRequest* request) { 493 void InsertInFlightRequest(ScheduledResourceRequest* request) {
470 in_flight_requests_.insert(request); 494 in_flight_requests_.insert(request);
471 SetRequestAttributes(request, DetermineRequestAttributes(request)); 495 SetRequestAttributes(request, DetermineRequestAttributes(request));
472 } 496 }
473 497
474 void EraseInFlightRequest(ScheduledResourceRequest* request) { 498 void EraseInFlightRequest(ScheduledResourceRequest* request) {
475 size_t erased = in_flight_requests_.erase(request); 499 size_t erased = in_flight_requests_.erase(request);
476 DCHECK_EQ(1u, erased); 500 DCHECK_EQ(1u, erased);
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
596 if (same_host_count >= kMaxNumDelayableRequestsPerHostPerClient) 620 if (same_host_count >= kMaxNumDelayableRequestsPerHostPerClient)
597 return true; 621 return true;
598 } 622 }
599 } 623 }
600 return false; 624 return false;
601 } 625 }
602 626
603 void StartRequest(ScheduledResourceRequest* request, 627 void StartRequest(ScheduledResourceRequest* request,
604 StartMode start_mode, 628 StartMode start_mode,
605 RequestStartTrigger trigger) { 629 RequestStartTrigger trigger) {
630 started_requests_since_yielding_ += 1;
631 if (started_requests_since_yielding_ == 1) {
632 // This is the first started request since last yielding. Post a task to
633 // reset the counter and start any yielded tasks if necessary. We post
634 // this now instead of when we first yield so that if there is a pause
635 // between requests the counter is reset.
636 base::ThreadTaskRunnerHandle::Get()->PostTask(
637 FROM_HERE,
638 base::Bind(&Client::ResumeAfterYielding,
639 weak_ptr_factory_.GetWeakPtr()));
640 }
641
606 // Only log on requests that were blocked by the ResourceScheduler. 642 // Only log on requests that were blocked by the ResourceScheduler.
607 if (start_mode == START_ASYNC) { 643 if (start_mode == START_ASYNC) {
608 DCHECK_NE(RequestStartTrigger::NONE, trigger); 644 DCHECK_NE(RequestStartTrigger::NONE, trigger);
609 request->url_request()->net_log().AddEvent( 645 request->url_request()->net_log().AddEvent(
610 net::NetLogEventType::RESOURCE_SCHEDULER_REQUEST_STARTED, 646 net::NetLogEventType::RESOURCE_SCHEDULER_REQUEST_STARTED,
611 net::NetLog::StringCallback( 647 net::NetLog::StringCallback(
612 "trigger", RequestStartTriggerString(trigger))); 648 "trigger", RequestStartTriggerString(trigger)));
613 } 649 }
614 InsertInFlightRequest(request); 650 InsertInFlightRequest(request);
615 request->Start(start_mode); 651 request->Start(start_mode);
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
659 695
660 // TODO(simonjam): This may end up causing disk contention. We should 696 // TODO(simonjam): This may end up causing disk contention. We should
661 // experiment with throttling if that happens. 697 // experiment with throttling if that happens.
662 if (!url_request.url().SchemeIsHTTPOrHTTPS()) 698 if (!url_request.url().SchemeIsHTTPOrHTTPS())
663 return START_REQUEST; 699 return START_REQUEST;
664 700
665 const net::HostPortPair& host_port_pair = request->host_port_pair(); 701 const net::HostPortPair& host_port_pair = request->host_port_pair();
666 702
667 if (!priority_requests_delayable_) { 703 if (!priority_requests_delayable_) {
668 if (using_spdy_proxy_ && url_request.url().SchemeIs(url::kHttpScheme)) 704 if (using_spdy_proxy_ && url_request.url().SchemeIs(url::kHttpScheme))
669 return START_REQUEST; 705 return ShouldStartOrYieldRequest();
670 706
671 url::SchemeHostPort scheme_host_port(url_request.url()); 707 url::SchemeHostPort scheme_host_port(url_request.url());
672 708
673 net::HttpServerProperties& http_server_properties = 709 net::HttpServerProperties& http_server_properties =
674 *url_request.context()->http_server_properties(); 710 *url_request.context()->http_server_properties();
675 711
676 // TODO(willchan): We should really improve this algorithm as described in 712 // TODO(willchan): We should really improve this algorithm as described in
677 // crbug.com/164101. Also, theoretically we should not count a 713 // crbug.com/164101. Also, theoretically we should not count a
678 // request-priority capable request against the delayable requests limit. 714 // request-priority capable request against the delayable requests limit.
679 if (http_server_properties.SupportsRequestPriority(scheme_host_port)) 715 if (http_server_properties.SupportsRequestPriority(scheme_host_port))
680 return START_REQUEST; 716 return ShouldStartOrYieldRequest();
681 } 717 }
682 718
683 // Non-delayable requests. 719 // Non-delayable requests.
684 if (!RequestAttributesAreSet(request->attributes(), kAttributeDelayable)) 720 if (!RequestAttributesAreSet(request->attributes(), kAttributeDelayable))
685 return START_REQUEST; 721 return ShouldStartOrYieldRequest();
686 722
687 if (in_flight_delayable_count_ >= kMaxNumDelayableRequestsPerClient) 723 if (in_flight_delayable_count_ >= kMaxNumDelayableRequestsPerClient)
688 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING; 724 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING;
689 725
690 if (ShouldKeepSearching(host_port_pair)) { 726 if (ShouldKeepSearching(host_port_pair)) {
691 // There may be other requests for other hosts that may be allowed, 727 // There may be other requests for other hosts that may be allowed,
692 // so keep checking. 728 // so keep checking.
693 return DO_NOT_START_REQUEST_AND_KEEP_SEARCHING; 729 return DO_NOT_START_REQUEST_AND_KEEP_SEARCHING;
694 } 730 }
695 731
(...skipping 14 matching lines...) Expand all
710 if (in_flight_requests_.size() > 0 && 746 if (in_flight_requests_.size() > 0 &&
711 (in_flight_delayable_count_ >= 747 (in_flight_delayable_count_ >=
712 kMaxNumDelayableWhileLayoutBlockingPerClient)) { 748 kMaxNumDelayableWhileLayoutBlockingPerClient)) {
713 // Block the request if at least one request is in flight and the 749 // Block the request if at least one request is in flight and the
714 // number of in-flight delayable requests has hit the configured 750 // number of in-flight delayable requests has hit the configured
715 // limit. 751 // limit.
716 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING; 752 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING;
717 } 753 }
718 } 754 }
719 755
720 return START_REQUEST; 756 return ShouldStartOrYieldRequest();
721 } 757 }
722 758
723 // It is common for a burst of messages to come from the renderer which 759 // It is common for a burst of messages to come from the renderer which
724 // trigger starting pending requests. Naively, this would result in O(n*m) 760 // trigger starting pending requests. Naively, this would result in O(n*m)
725 // behavior for n pending requests and m <= n messages, as 761 // behavior for n pending requests and m <= n messages, as
726 // LoadAnyStartablePendingRequest is O(n) for n pending requests. To solve 762 // LoadAnyStartablePendingRequest is O(n) for n pending requests. To solve
727 // this, just post a task to the end of the queue to call the method, 763 // this, just post a task to the end of the queue to call the method,
728 // coalescing the m messages into a single call to 764 // coalescing the m messages into a single call to
729 // LoadAnyStartablePendingRequests. 765 // LoadAnyStartablePendingRequests.
730 // TODO(csharrison): Reconsider this if IPC batching becomes an easy to use 766 // TODO(csharrison): Reconsider this if IPC batching becomes an easy to use
731 // pattern. 767 // pattern.
732 void ScheduleLoadAnyStartablePendingRequests(RequestStartTrigger trigger) { 768 void ScheduleLoadAnyStartablePendingRequests(RequestStartTrigger trigger) {
733 if (has_pending_start_task_) 769 if (has_pending_start_task_)
734 return; 770 return;
735 has_pending_start_task_ = true; 771 has_pending_start_task_ = true;
736 base::ThreadTaskRunnerHandle::Get()->PostTask( 772 base::ThreadTaskRunnerHandle::Get()->PostTask(
737 FROM_HERE, base::Bind(&Client::LoadAnyStartablePendingRequests, 773 FROM_HERE, base::Bind(&Client::LoadAnyStartablePendingRequests,
738 weak_ptr_factory_.GetWeakPtr(), trigger)); 774 weak_ptr_factory_.GetWeakPtr(), trigger));
739 } 775 }
740 776
777 void ResumeAfterYielding() {
Charlie Harrison 2017/02/22 17:42:14 nit: I think a better name is "ResumeIfYielded"
jkarlin 2017/02/22 17:49:25 Done.
778 bool yielded = did_scheduler_yield_;
779 started_requests_since_yielding_ = 0;
780 did_scheduler_yield_ = false;
781
782 if (yielded)
783 LoadAnyStartablePendingRequests(RequestStartTrigger::START_WAS_YIELDED);
784 }
785
786 // For a request that is ready to start, return START_REQUEST if the
787 // scheduler doesn't need to yield, else YIELD_SCHEDULER.
788 ShouldStartReqResult ShouldStartOrYieldRequest() const {
789 DCHECK_GE(started_requests_since_yielding_, 0);
790 if (!yielding_scheduler_enabled_)
Charlie Harrison 2017/02/22 17:42:14 nit: merge this if statement into the below one:
jkarlin 2017/02/22 17:49:25 Done.
791 return START_REQUEST;
792
793 if (started_requests_since_yielding_ >= max_requests_before_yielding_)
794 return YIELD_SCHEDULER;
795 return START_REQUEST;
796 }
797
741 void LoadAnyStartablePendingRequests(RequestStartTrigger trigger) { 798 void LoadAnyStartablePendingRequests(RequestStartTrigger trigger) {
742 // We iterate through all the pending requests, starting with the highest 799 // We iterate through all the pending requests, starting with the highest
743 // priority one. For each entry, one of three things can happen: 800 // priority one. For each entry, one of three things can happen:
744 // 1) We start the request, remove it from the list, and keep checking. 801 // 1) We start the request, remove it from the list, and keep checking.
745 // 2) We do NOT start the request, but ShouldStartRequest() signals us that 802 // 2) We do NOT start the request, but ShouldStartRequest() signals us that
746 // there may be room for other requests, so we keep checking and leave 803 // there may be room for other requests, so we keep checking and leave
747 // the previous request still in the list. 804 // the previous request still in the list.
748 // 3) We do not start the request, same as above, but StartRequest() tells 805 // 3) We do not start the request, same as above, but StartRequest() tells
749 // us there's no point in checking any further requests. 806 // us there's no point in checking any further requests.
750 has_pending_start_task_ = false; 807 has_pending_start_task_ = false;
(...skipping 11 matching lines...) Expand all
762 // StartRequest can modify the pending list, so we (re)start evaluation 819 // StartRequest can modify the pending list, so we (re)start evaluation
763 // from the currently highest priority request. Avoid copying a singular 820 // from the currently highest priority request. Avoid copying a singular
764 // iterator, which would trigger undefined behavior. 821 // iterator, which would trigger undefined behavior.
765 if (pending_requests_.GetNextHighestIterator() == 822 if (pending_requests_.GetNextHighestIterator() ==
766 pending_requests_.End()) 823 pending_requests_.End())
767 break; 824 break;
768 request_iter = pending_requests_.GetNextHighestIterator(); 825 request_iter = pending_requests_.GetNextHighestIterator();
769 } else if (query_result == DO_NOT_START_REQUEST_AND_KEEP_SEARCHING) { 826 } else if (query_result == DO_NOT_START_REQUEST_AND_KEEP_SEARCHING) {
770 ++request_iter; 827 ++request_iter;
771 continue; 828 continue;
829 } else if (query_result == YIELD_SCHEDULER) {
830 did_scheduler_yield_ = true;
831 break;
772 } else { 832 } else {
773 DCHECK(query_result == DO_NOT_START_REQUEST_AND_STOP_SEARCHING); 833 DCHECK(query_result == DO_NOT_START_REQUEST_AND_STOP_SEARCHING);
774 break; 834 break;
775 } 835 }
776 } 836 }
777 } 837 }
778 838
779 bool is_loaded_; 839 bool is_loaded_;
780 // Tracks if the main HTML parser has reached the body which marks the end of 840 // Tracks if the main HTML parser has reached the body which marks the end of
781 // layout-blocking resources. 841 // layout-blocking resources.
782 bool has_html_body_; 842 bool has_html_body_;
783 bool using_spdy_proxy_; 843 bool using_spdy_proxy_;
784 RequestQueue pending_requests_; 844 RequestQueue pending_requests_;
785 RequestSet in_flight_requests_; 845 RequestSet in_flight_requests_;
786 // The number of delayable in-flight requests. 846 // The number of delayable in-flight requests.
787 size_t in_flight_delayable_count_; 847 size_t in_flight_delayable_count_;
788 // The number of layout-blocking in-flight requests. 848 // The number of layout-blocking in-flight requests.
789 size_t total_layout_blocking_count_; 849 size_t total_layout_blocking_count_;
790 850
791 // True if requests to servers that support priorities (e.g., H2/QUIC) can 851 // True if requests to servers that support priorities (e.g., H2/QUIC) can
792 // be delayed. 852 // be delayed.
793 bool priority_requests_delayable_; 853 bool priority_requests_delayable_;
794 854
795 bool has_pending_start_task_; 855 bool has_pending_start_task_;
796 856
857 // The number of started requests since the last ResumeFromYielding task was
858 // run.
859 int started_requests_since_yielding_;
860
861 // If the scheduler had to yield the start of a request since the last
862 // ResumeFromYielding task was run.
863 bool did_scheduler_yield_;
Charlie Harrison 2017/02/22 17:42:14 Do we really need this member? Can't we just use s
jkarlin 2017/02/22 17:49:25 We need it. started_requests_since_yielding_ won't
jkarlin 2017/02/22 17:58:37 Ah, what you said was a little more subtle. If we
Charlie Harrison 2017/02/22 18:01:36 I thought about that but it seemed weird and hard
864
865 // Whether or not to periodically yield when starting lots of requests.
866 bool yielding_scheduler_enabled_;
867
868 // The number of requests that can start before yielding.
869 int max_requests_before_yielding_;
870
797 base::WeakPtrFactory<ResourceScheduler::Client> weak_ptr_factory_; 871 base::WeakPtrFactory<ResourceScheduler::Client> weak_ptr_factory_;
798 }; 872 };
799 873
800 ResourceScheduler::ResourceScheduler() 874 ResourceScheduler::ResourceScheduler()
801 : priority_requests_delayable_( 875 : priority_requests_delayable_(
802 base::FeatureList::IsEnabled(kPrioritySupportedRequestsDelayable)) {} 876 base::FeatureList::IsEnabled(kPrioritySupportedRequestsDelayable)),
877 yielding_scheduler_enabled_(
878 base::FeatureList::IsEnabled(kNetworkSchedulerYielding)),
879 max_requests_before_yielding_(base::GetFieldTrialParamByFeatureAsInt(
880 kNetworkSchedulerYielding,
881 kMaxRequestsBeforeYieldingParam,
882 kMaxRequestsBeforeYieldingDefault)) {}
803 883
804 ResourceScheduler::~ResourceScheduler() { 884 ResourceScheduler::~ResourceScheduler() {
805 DCHECK(unowned_requests_.empty()); 885 DCHECK(unowned_requests_.empty());
806 DCHECK(client_map_.empty()); 886 DCHECK(client_map_.empty());
807 } 887 }
808 888
809 std::unique_ptr<ResourceThrottle> ResourceScheduler::ScheduleRequest( 889 std::unique_ptr<ResourceThrottle> ResourceScheduler::ScheduleRequest(
810 int child_id, 890 int child_id,
811 int route_id, 891 int route_id,
812 bool is_async, 892 bool is_async,
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
849 Client* client = client_it->second; 929 Client* client = client_it->second;
850 client->RemoveRequest(request); 930 client->RemoveRequest(request);
851 } 931 }
852 932
853 void ResourceScheduler::OnClientCreated(int child_id, 933 void ResourceScheduler::OnClientCreated(int child_id,
854 int route_id) { 934 int route_id) {
855 DCHECK(CalledOnValidThread()); 935 DCHECK(CalledOnValidThread());
856 ClientId client_id = MakeClientId(child_id, route_id); 936 ClientId client_id = MakeClientId(child_id, route_id);
857 DCHECK(!base::ContainsKey(client_map_, client_id)); 937 DCHECK(!base::ContainsKey(client_map_, client_id));
858 938
859 Client* client = new Client(priority_requests_delayable_); 939 Client* client =
940 new Client(priority_requests_delayable_, yielding_scheduler_enabled_,
941 max_requests_before_yielding_);
860 client_map_[client_id] = client; 942 client_map_[client_id] = client;
861 } 943 }
862 944
863 void ResourceScheduler::OnClientDeleted(int child_id, int route_id) { 945 void ResourceScheduler::OnClientDeleted(int child_id, int route_id) {
864 DCHECK(CalledOnValidThread()); 946 DCHECK(CalledOnValidThread());
865 ClientId client_id = MakeClientId(child_id, route_id); 947 ClientId client_id = MakeClientId(child_id, route_id);
866 ClientMap::iterator it = client_map_.find(client_id); 948 ClientMap::iterator it = client_map_.find(client_id);
867 DCHECK(it != client_map_.end()); 949 DCHECK(it != client_map_.end());
868 950
869 Client* client = it->second; 951 Client* client = it->second;
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
988 client->ReprioritizeRequest(scheduled_resource_request, old_priority_params, 1070 client->ReprioritizeRequest(scheduled_resource_request, old_priority_params,
989 new_priority_params); 1071 new_priority_params);
990 } 1072 }
991 1073
992 ResourceScheduler::ClientId ResourceScheduler::MakeClientId( 1074 ResourceScheduler::ClientId ResourceScheduler::MakeClientId(
993 int child_id, int route_id) { 1075 int child_id, int route_id) {
994 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id; 1076 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id;
995 } 1077 }
996 1078
997 } // namespace content 1079 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698