Chromium Code Reviews| OLD | NEW |
|---|---|
| 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/field_trial_params.h" |
| 17 #include "base/metrics/histogram_macros.h" | 17 #include "base/metrics/histogram_macros.h" |
| 18 #include "base/stl_util.h" | 18 #include "base/stl_util.h" |
| 19 #include "base/supports_user_data.h" | 19 #include "base/supports_user_data.h" |
| 20 #include "base/threading/thread_task_runner_handle.h" | 20 #include "base/threading/thread_task_runner_handle.h" |
| 21 #include "base/trace_event/trace_event.h" | |
| 21 #include "content/common/resource_messages.h" | 22 #include "content/common/resource_messages.h" |
| 22 #include "content/public/browser/resource_request_info.h" | 23 #include "content/public/browser/resource_request_info.h" |
| 23 #include "content/public/browser/resource_throttle.h" | 24 #include "content/public/browser/resource_throttle.h" |
| 24 #include "net/base/host_port_pair.h" | 25 #include "net/base/host_port_pair.h" |
| 25 #include "net/base/load_flags.h" | 26 #include "net/base/load_flags.h" |
| 26 #include "net/base/request_priority.h" | 27 #include "net/base/request_priority.h" |
| 27 #include "net/http/http_server_properties.h" | 28 #include "net/http/http_server_properties.h" |
| 28 #include "net/url_request/url_request.h" | 29 #include "net/url_request/url_request.h" |
| 29 #include "net/url_request/url_request_context.h" | 30 #include "net/url_request/url_request_context.h" |
| 30 #include "url/scheme_host_port.h" | 31 #include "url/scheme_host_port.h" |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 175 } | 176 } |
| 176 | 177 |
| 177 NetQueue::iterator GetNextHighestIterator() { | 178 NetQueue::iterator GetNextHighestIterator() { |
| 178 return queue_.begin(); | 179 return queue_.begin(); |
| 179 } | 180 } |
| 180 | 181 |
| 181 NetQueue::iterator End() { | 182 NetQueue::iterator End() { |
| 182 return queue_.end(); | 183 return queue_.end(); |
| 183 } | 184 } |
| 184 | 185 |
| 186 size_t size() { return queue_.size(); } | |
| 187 | |
| 185 // Returns true if |request| is queued. | 188 // Returns true if |request| is queued. |
| 186 bool IsQueued(ScheduledResourceRequest* request) const { | 189 bool IsQueued(ScheduledResourceRequest* request) const { |
| 187 return base::ContainsKey(pointers_, request); | 190 return base::ContainsKey(pointers_, request); |
| 188 } | 191 } |
| 189 | 192 |
| 190 // Returns true if no requests are queued. | 193 // Returns true if no requests are queued. |
| 191 bool IsEmpty() const { return queue_.size() == 0; } | 194 bool IsEmpty() const { return queue_.size() == 0; } |
| 192 | 195 |
| 193 private: | 196 private: |
| 194 typedef std::map<ScheduledResourceRequest*, NetQueue::iterator> PointerMap; | 197 typedef std::map<ScheduledResourceRequest*, NetQueue::iterator> PointerMap; |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 364 public: | 367 public: |
| 365 Client(bool priority_requests_delayable, | 368 Client(bool priority_requests_delayable, |
| 366 bool yielding_scheduler_enabled, | 369 bool yielding_scheduler_enabled, |
| 367 int max_requests_before_yielding) | 370 int max_requests_before_yielding) |
| 368 : is_loaded_(false), | 371 : is_loaded_(false), |
| 369 has_html_body_(false), | 372 has_html_body_(false), |
| 370 using_spdy_proxy_(false), | 373 using_spdy_proxy_(false), |
| 371 in_flight_delayable_count_(0), | 374 in_flight_delayable_count_(0), |
| 372 total_layout_blocking_count_(0), | 375 total_layout_blocking_count_(0), |
| 373 priority_requests_delayable_(priority_requests_delayable), | 376 priority_requests_delayable_(priority_requests_delayable), |
| 374 has_pending_start_task_(false), | 377 num_skipped_request_scans_for_delayed_start_(0), |
| 375 started_requests_since_yielding_(0), | 378 started_requests_since_yielding_(0), |
| 376 did_scheduler_yield_(false), | 379 did_scheduler_yield_(false), |
| 377 yielding_scheduler_enabled_(yielding_scheduler_enabled), | 380 yielding_scheduler_enabled_(yielding_scheduler_enabled), |
| 378 max_requests_before_yielding_(max_requests_before_yielding), | 381 max_requests_before_yielding_(max_requests_before_yielding), |
| 379 weak_ptr_factory_(this) {} | 382 weak_ptr_factory_(this) {} |
| 380 | 383 |
| 381 ~Client() {} | 384 ~Client() {} |
| 382 | 385 |
| 383 void ScheduleRequest(net::URLRequest* url_request, | 386 void ScheduleRequest(net::URLRequest* url_request, |
| 384 ScheduledResourceRequest* request) { | 387 ScheduledResourceRequest* request) { |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 395 } | 398 } |
| 396 | 399 |
| 397 void RemoveRequest(ScheduledResourceRequest* request) { | 400 void RemoveRequest(ScheduledResourceRequest* request) { |
| 398 if (pending_requests_.IsQueued(request)) { | 401 if (pending_requests_.IsQueued(request)) { |
| 399 pending_requests_.Erase(request); | 402 pending_requests_.Erase(request); |
| 400 DCHECK(!base::ContainsKey(in_flight_requests_, request)); | 403 DCHECK(!base::ContainsKey(in_flight_requests_, request)); |
| 401 } else { | 404 } else { |
| 402 EraseInFlightRequest(request); | 405 EraseInFlightRequest(request); |
| 403 | 406 |
| 404 // Removing this request may have freed up another to load. | 407 // Removing this request may have freed up another to load. |
| 405 ScheduleLoadAnyStartablePendingRequests( | 408 LoadAnyStartablePendingRequests( |
| 406 has_html_body_ ? RequestStartTrigger::COMPLETION_POST_BODY | 409 has_html_body_ ? RequestStartTrigger::COMPLETION_POST_BODY |
| 407 : RequestStartTrigger::COMPLETION_PRE_BODY); | 410 : RequestStartTrigger::COMPLETION_PRE_BODY); |
| 408 } | 411 } |
| 409 } | 412 } |
| 410 | 413 |
| 411 RequestSet StartAndRemoveAllRequests() { | 414 RequestSet StartAndRemoveAllRequests() { |
| 412 // First start any pending requests so that they will be moved into | 415 // First start any pending requests so that they will be moved into |
| 413 // in_flight_requests_. This may exceed the limits | 416 // in_flight_requests_. This may exceed the limits |
| 414 // kDefaultMaxNumDelayableRequestsPerClient and | 417 // kDefaultMaxNumDelayableRequestsPerClient and |
| 415 // kMaxNumDelayableRequestsPerHostPerClient, so this method must not do | 418 // kMaxNumDelayableRequestsPerHostPerClient, so this method must not do |
| (...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 758 // It is common for a burst of messages to come from the renderer which | 761 // It is common for a burst of messages to come from the renderer which |
| 759 // trigger starting pending requests. Naively, this would result in O(n*m) | 762 // trigger starting pending requests. Naively, this would result in O(n*m) |
| 760 // behavior for n pending requests and m <= n messages, as | 763 // behavior for n pending requests and m <= n messages, as |
| 761 // LoadAnyStartablePendingRequest is O(n) for n pending requests. To solve | 764 // LoadAnyStartablePendingRequest is O(n) for n pending requests. To solve |
| 762 // this, just post a task to the end of the queue to call the method, | 765 // this, just post a task to the end of the queue to call the method, |
| 763 // coalescing the m messages into a single call to | 766 // coalescing the m messages into a single call to |
| 764 // LoadAnyStartablePendingRequests. | 767 // LoadAnyStartablePendingRequests. |
| 765 // TODO(csharrison): Reconsider this if IPC batching becomes an easy to use | 768 // TODO(csharrison): Reconsider this if IPC batching becomes an easy to use |
| 766 // pattern. | 769 // pattern. |
| 767 void ScheduleLoadAnyStartablePendingRequests(RequestStartTrigger trigger) { | 770 void ScheduleLoadAnyStartablePendingRequests(RequestStartTrigger trigger) { |
| 768 if (has_pending_start_task_) | 771 if (num_skipped_request_scans_for_delayed_start_ == 0) { |
| 769 return; | 772 TRACE_EVENT0("loading", "ScheduleLoadAnyStartablePendingRequests"); |
| 770 has_pending_start_task_ = true; | 773 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 771 base::ThreadTaskRunnerHandle::Get()->PostTask( | 774 FROM_HERE, |
| 772 FROM_HERE, base::Bind(&Client::LoadAnyStartablePendingRequests, | 775 base::Bind(&Client::LoadAnyStartablePendingRequests, |
| 773 weak_ptr_factory_.GetWeakPtr(), trigger)); | 776 weak_ptr_factory_.GetWeakPtr(), trigger)); |
| 777 } | |
| 778 num_skipped_request_scans_for_delayed_start_ += pending_requests_.size(); | |
|
kinuko
2017/02/24 01:38:28
Why do we add pending_requests_ here?
kinuko
2017/02/24 01:55:45
I think this wants to get the numbers that we migh
Charlie Harrison
2017/02/24 02:02:00
Hm... I'm not sure what better signal to use. Note
| |
| 774 } | 779 } |
| 775 | 780 |
| 776 void ResumeIfYielded() { | 781 void ResumeIfYielded() { |
| 777 bool yielded = did_scheduler_yield_; | 782 bool yielded = did_scheduler_yield_; |
| 778 started_requests_since_yielding_ = 0; | 783 started_requests_since_yielding_ = 0; |
| 779 did_scheduler_yield_ = false; | 784 did_scheduler_yield_ = false; |
| 780 | 785 |
| 781 if (yielded) | 786 if (yielded) |
| 782 LoadAnyStartablePendingRequests(RequestStartTrigger::START_WAS_YIELDED); | 787 LoadAnyStartablePendingRequests(RequestStartTrigger::START_WAS_YIELDED); |
| 783 } | 788 } |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 796 | 801 |
| 797 void LoadAnyStartablePendingRequests(RequestStartTrigger trigger) { | 802 void LoadAnyStartablePendingRequests(RequestStartTrigger trigger) { |
| 798 // We iterate through all the pending requests, starting with the highest | 803 // We iterate through all the pending requests, starting with the highest |
| 799 // priority one. For each entry, one of three things can happen: | 804 // priority one. For each entry, one of three things can happen: |
| 800 // 1) We start the request, remove it from the list, and keep checking. | 805 // 1) We start the request, remove it from the list, and keep checking. |
| 801 // 2) We do NOT start the request, but ShouldStartRequest() signals us that | 806 // 2) We do NOT start the request, but ShouldStartRequest() signals us that |
| 802 // there may be room for other requests, so we keep checking and leave | 807 // there may be room for other requests, so we keep checking and leave |
| 803 // the previous request still in the list. | 808 // the previous request still in the list. |
| 804 // 3) We do not start the request, same as above, but StartRequest() tells | 809 // 3) We do not start the request, same as above, but StartRequest() tells |
| 805 // us there's no point in checking any further requests. | 810 // us there's no point in checking any further requests. |
| 806 has_pending_start_task_ = false; | 811 TRACE_EVENT0("loading", "LoadAnyStartablePendingRequests"); |
| 812 if (num_skipped_request_scans_for_delayed_start_ > 0) { | |
| 813 UMA_HISTOGRAM_COUNTS_1M( | |
| 814 "ResourceScheduler.NumSkippedRequestScans.ScheduleStart", | |
| 815 num_skipped_request_scans_for_delayed_start_); | |
| 816 } | |
| 817 num_skipped_request_scans_for_delayed_start_ = 0; | |
| 807 RequestQueue::NetQueue::iterator request_iter = | 818 RequestQueue::NetQueue::iterator request_iter = |
| 808 pending_requests_.GetNextHighestIterator(); | 819 pending_requests_.GetNextHighestIterator(); |
| 809 | 820 |
| 810 while (request_iter != pending_requests_.End()) { | 821 while (request_iter != pending_requests_.End()) { |
| 811 ScheduledResourceRequest* request = *request_iter; | 822 ScheduledResourceRequest* request = *request_iter; |
| 812 ShouldStartReqResult query_result = ShouldStartRequest(request); | 823 ShouldStartReqResult query_result = ShouldStartRequest(request); |
| 813 | 824 |
| 814 if (query_result == START_REQUEST) { | 825 if (query_result == START_REQUEST) { |
| 815 pending_requests_.Erase(request); | 826 pending_requests_.Erase(request); |
| 816 StartRequest(request, START_ASYNC, trigger); | 827 StartRequest(request, START_ASYNC, trigger); |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 844 RequestSet in_flight_requests_; | 855 RequestSet in_flight_requests_; |
| 845 // The number of delayable in-flight requests. | 856 // The number of delayable in-flight requests. |
| 846 size_t in_flight_delayable_count_; | 857 size_t in_flight_delayable_count_; |
| 847 // The number of layout-blocking in-flight requests. | 858 // The number of layout-blocking in-flight requests. |
| 848 size_t total_layout_blocking_count_; | 859 size_t total_layout_blocking_count_; |
| 849 | 860 |
| 850 // True if requests to servers that support priorities (e.g., H2/QUIC) can | 861 // True if requests to servers that support priorities (e.g., H2/QUIC) can |
| 851 // be delayed. | 862 // be delayed. |
| 852 bool priority_requests_delayable_; | 863 bool priority_requests_delayable_; |
| 853 | 864 |
| 854 bool has_pending_start_task_; | 865 // The upper bound for the number of requests that were not scanned due to |
| 866 // logic in ScheduleLoadAnyStartablePendingRequests. This number also doubles | |
| 867 // as a signal for whether a task has already been scheduled. | |
| 868 int num_skipped_request_scans_for_delayed_start_; | |
| 855 | 869 |
| 856 // The number of started requests since the last ResumeIfYielded task was | 870 // The number of started requests since the last ResumeIfYielded task was |
| 857 // run. | 871 // run. |
| 858 int started_requests_since_yielding_; | 872 int started_requests_since_yielding_; |
| 859 | 873 |
| 860 // If the scheduler had to yield the start of a request since the last | 874 // If the scheduler had to yield the start of a request since the last |
| 861 // ResumeIfYielded task was run. | 875 // ResumeIfYielded task was run. |
| 862 bool did_scheduler_yield_; | 876 bool did_scheduler_yield_; |
| 863 | 877 |
| 864 // Whether or not to periodically yield when starting lots of requests. | 878 // Whether or not to periodically yield when starting lots of requests. |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1069 client->ReprioritizeRequest(scheduled_resource_request, old_priority_params, | 1083 client->ReprioritizeRequest(scheduled_resource_request, old_priority_params, |
| 1070 new_priority_params); | 1084 new_priority_params); |
| 1071 } | 1085 } |
| 1072 | 1086 |
| 1073 ResourceScheduler::ClientId ResourceScheduler::MakeClientId( | 1087 ResourceScheduler::ClientId ResourceScheduler::MakeClientId( |
| 1074 int child_id, int route_id) { | 1088 int child_id, int route_id) { |
| 1075 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id; | 1089 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id; |
| 1076 } | 1090 } |
| 1077 | 1091 |
| 1078 } // namespace content | 1092 } // namespace content |
| OLD | NEW |