| Index: content/browser/loader/resource_scheduler.cc
|
| diff --git a/content/browser/loader/resource_scheduler.cc b/content/browser/loader/resource_scheduler.cc
|
| index 1d118f0ffbc2ae3be243e75f8eb227a1073edfcf..919262129c3c9de0bb9819c91152d48317b9590d 100644
|
| --- a/content/browser/loader/resource_scheduler.cc
|
| +++ b/content/browser/loader/resource_scheduler.cc
|
| @@ -2,10 +2,10 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| -#include <set>
|
| -
|
| #include "content/browser/loader/resource_scheduler.h"
|
|
|
| +#include <set>
|
| +
|
| #include "base/metrics/field_trial.h"
|
| #include "base/metrics/histogram.h"
|
| #include "base/stl_util.h"
|
| @@ -37,6 +37,8 @@ const char kThrottleCoalesceFieldTrialCoalesce[] = "Coalesce";
|
| const char kRequestLimitFieldTrial[] = "OutstandingRequestLimiting";
|
| const char kRequestLimitFieldTrialGroupPrefix[] = "Limit";
|
|
|
| +const char kResourcePrioritiesFieldTrial[] = "ResourcePriorities";
|
| +
|
| // Post ResourceScheduler histograms of the following forms:
|
| // If |histogram_suffix| is NULL or the empty string:
|
| // ResourceScheduler.base_name.histogram_name
|
| @@ -74,9 +76,12 @@ const char* GetNumClientsString(size_t num_clients) {
|
| } // namespace
|
|
|
| static const size_t kCoalescedTimerPeriod = 5000;
|
| -static const size_t kMaxNumDelayableRequestsPerClient = 10;
|
| +static const size_t kDefaultMaxNumDelayableRequestsPerClient = 10;
|
| static const size_t kMaxNumDelayableRequestsPerHost = 6;
|
| static const size_t kMaxNumThrottledRequestsPerClient = 1;
|
| +static const size_t kDefaultMaxNumDelayableWhileLayoutBlocking = 1;
|
| +static const net::RequestPriority
|
| + kDefaultLayoutBlockingPriorityThreshold = net::LOW;
|
|
|
| struct ResourceScheduler::RequestPriorityParams {
|
| RequestPriorityParams()
|
| @@ -308,13 +313,14 @@ class ResourceScheduler::Client {
|
| is_visible_(is_visible),
|
| is_loaded_(false),
|
| is_paused_(false),
|
| - has_body_(false),
|
| + has_html_body_(false),
|
| using_spdy_proxy_(false),
|
| load_started_time_(base::TimeTicks::Now()),
|
| scheduler_(scheduler),
|
| in_flight_delayable_count_(0),
|
| total_layout_blocking_count_(0),
|
| - throttle_state_(ResourceScheduler::THROTTLED) {}
|
| + throttle_state_(ResourceScheduler::THROTTLED) {
|
| + }
|
|
|
| ~Client() {
|
| // Update to default state and pause to ensure the scheduler has a
|
| @@ -350,10 +356,10 @@ class ResourceScheduler::Client {
|
| RequestSet StartAndRemoveAllRequests() {
|
| // First start any pending requests so that they will be moved into
|
| // in_flight_requests_. This may exceed the limits
|
| - // kMaxNumDelayableRequestsPerClient, kMaxNumDelayableRequestsPerHost and
|
| - // kMaxNumThrottledRequestsPerClient, so this method must not do anything
|
| - // that depends on those limits before calling ClearInFlightRequests()
|
| - // below.
|
| + // kDefaultMaxNumDelayableRequestsPerClient, kMaxNumDelayableRequestsPerHost
|
| + // and kMaxNumThrottledRequestsPerClient, so this method must not do
|
| + // anything that depends on those limits before calling
|
| + // ClearInFlightRequests() below.
|
| while (!pending_requests_.IsEmpty()) {
|
| ScheduledResourceRequest* request =
|
| *pending_requests_.GetNextHighestIterator();
|
| @@ -470,12 +476,12 @@ class ResourceScheduler::Client {
|
| }
|
|
|
| void OnNavigate() {
|
| - has_body_ = false;
|
| + has_html_body_ = false;
|
| is_loaded_ = false;
|
| }
|
|
|
| void OnWillInsertBody() {
|
| - has_body_ = true;
|
| + has_html_body_ = true;
|
| LoadAnyStartablePendingRequests();
|
| }
|
|
|
| @@ -623,16 +629,18 @@ class ResourceScheduler::Client {
|
|
|
| RequestClassification ClassifyRequest(ScheduledResourceRequest* request) {
|
| // If a request is already marked as layout-blocking make sure to keep the
|
| - // classification across redirects unless the priority was lowered.
|
| - if (request->classification() == LAYOUT_BLOCKING_REQUEST &&
|
| - request->url_request()->priority() > net::LOW) {
|
| + // classification across redirects.
|
| + if (request->classification() == LAYOUT_BLOCKING_REQUEST)
|
| return LAYOUT_BLOCKING_REQUEST;
|
| - }
|
|
|
| - if (!has_body_ && request->url_request()->priority() > net::LOW)
|
| + if (!has_html_body_ &&
|
| + request->url_request()->priority() >
|
| + scheduler_->layout_blocking_or_high_priority_threshold()) {
|
| return LAYOUT_BLOCKING_REQUEST;
|
| + }
|
|
|
| - if (request->url_request()->priority() < net::LOW) {
|
| + if (request->url_request()->priority() <
|
| + scheduler_->layout_blocking_or_high_priority_threshold()) {
|
| net::HostPortPair host_port_pair =
|
| net::HostPortPair::FromURL(request->url_request()->url());
|
| net::HttpServerProperties& http_server_properties =
|
| @@ -769,11 +777,13 @@ class ResourceScheduler::Client {
|
| }
|
|
|
| // High-priority and layout-blocking requests.
|
| - if (url_request.priority() >= net::LOW) {
|
| + if (url_request.priority() >=
|
| + scheduler_->layout_blocking_or_high_priority_threshold()) {
|
| return START_REQUEST;
|
| }
|
|
|
| - if (in_flight_delayable_count_ >= kMaxNumDelayableRequestsPerClient) {
|
| + if (in_flight_delayable_count_ >=
|
| + scheduler_->max_num_delayable_requests()) {
|
| return DO_NOT_START_REQUEST_AND_STOP_SEARCHING;
|
| }
|
|
|
| @@ -783,15 +793,40 @@ class ResourceScheduler::Client {
|
| return DO_NOT_START_REQUEST_AND_KEEP_SEARCHING;
|
| }
|
|
|
| - bool have_immediate_requests_in_flight =
|
| - in_flight_requests_.size() > in_flight_delayable_count_;
|
| - if (have_immediate_requests_in_flight &&
|
| - (!has_body_ || total_layout_blocking_count_ != 0) &&
|
| - // Do not allow a low priority request through in parallel if
|
| - // we are in a limit field trial.
|
| - (scheduler_->limit_outstanding_requests() ||
|
| - in_flight_delayable_count_ != 0)) {
|
| - return DO_NOT_START_REQUEST_AND_STOP_SEARCHING;
|
| + // The in-flight requests consist of layout-blocking requests,
|
| + // normal requests and delayable requests. Everything except for
|
| + // delayable requests is handled above here so this is deciding what to
|
| + // do with a delayable request while we are in the layout-blocking phase
|
| + // of loading.
|
| + if (!has_html_body_ || total_layout_blocking_count_ != 0) {
|
| + size_t non_delayable_requests_in_flight_count =
|
| + in_flight_requests_.size() - in_flight_delayable_count_;
|
| + if (scheduler_->enable_in_flight_layout_blocking_threshold()) {
|
| + if (non_delayable_requests_in_flight_count >
|
| + scheduler_->in_flight_layout_blocking_threshold()) {
|
| + // Too many higher priority in-flight requests to allow lower priority
|
| + // requests through.
|
| + return DO_NOT_START_REQUEST_AND_STOP_SEARCHING;
|
| + }
|
| + if (in_flight_requests_.size() > 0 &&
|
| + (scheduler_->limit_outstanding_requests() ||
|
| + in_flight_delayable_count_ >=
|
| + scheduler_->max_num_delayable_while_layout_blocking())) {
|
| + // Block the request if at least one request is in flight and the
|
| + // number of in-flight delayable requests has hit the configured
|
| + // limit.
|
| + return DO_NOT_START_REQUEST_AND_STOP_SEARCHING;
|
| + }
|
| + } else if (non_delayable_requests_in_flight_count > 0 &&
|
| + (scheduler_->limit_outstanding_requests() ||
|
| + in_flight_delayable_count_ >=
|
| + scheduler_->max_num_delayable_while_layout_blocking())) {
|
| + // If there are no high-priority requests in flight the floodgates open.
|
| + // If there are high-priority requests in-flight then limit the number
|
| + // of lower-priority requests (or zero if a limit field trial is
|
| + // active).
|
| + return DO_NOT_START_REQUEST_AND_STOP_SEARCHING;
|
| + }
|
| }
|
|
|
| return START_REQUEST;
|
| @@ -838,7 +873,9 @@ class ResourceScheduler::Client {
|
| bool is_visible_;
|
| bool is_loaded_;
|
| bool is_paused_;
|
| - bool has_body_;
|
| + // Tracks if the main HTML parser has reached the body which marks the end of
|
| + // layout-blocking resources.
|
| + bool has_html_body_;
|
| bool using_spdy_proxy_;
|
| RequestQueue pending_requests_;
|
| RequestSet in_flight_requests_;
|
| @@ -860,6 +897,13 @@ ResourceScheduler::ResourceScheduler()
|
| coalesced_clients_(0),
|
| limit_outstanding_requests_(false),
|
| outstanding_request_limit_(0),
|
| + layout_blocking_or_high_priority_threshold_(
|
| + kDefaultLayoutBlockingPriorityThreshold),
|
| + enable_in_flight_layout_blocking_threshold_(false),
|
| + in_flight_layout_blocking_threshold_(0),
|
| + max_num_delayable_while_layout_blocking_(
|
| + kDefaultMaxNumDelayableWhileLayoutBlocking),
|
| + max_num_delayable_requests_(kDefaultMaxNumDelayableRequestsPerClient),
|
| coalescing_timer_(new base::Timer(true /* retain_user_task */,
|
| true /* is_repeating */)) {
|
| std::string throttling_trial_group =
|
| @@ -884,6 +928,42 @@ ResourceScheduler::ResourceScheduler()
|
| limit_outstanding_requests_ = true;
|
| outstanding_request_limit_ = outstanding_limit;
|
| }
|
| +
|
| + // Set up the ResourceScheduling field trial options.
|
| + // The field trial parameters are also encoded into the group name since
|
| + // the variations component is not available from here and plumbing the
|
| + // options through the code is overkill for a short experiment.
|
| + //
|
| + // The group name encoding looks like this:
|
| + // <descriptiveName>_ABCDE_E2_F_G
|
| + // A - fetchDeferLateScripts (1 for true, 0 for false)
|
| + // B - fetchIncreaseFontPriority (1 for true, 0 for false)
|
| + // C - fetchIncreaseAsyncScriptPriority (1 for true, 0 for false)
|
| + // D - fetchIncreasePriorities (1 for true, 0 for false)
|
| + // E - fetchEnableLayoutBlockingThreshold (1 for true, 0 for false)
|
| + // E2 - fetchLayoutBlockingThreshold (Numeric)
|
| + // F - fetchMaxNumDelayableWhileLayoutBlocking (Numeric)
|
| + // G - fetchMaxNumDelayableRequests (Numeric)
|
| + std::string resource_priorities_trial_group =
|
| + base::FieldTrialList::FindFullName(kResourcePrioritiesFieldTrial);
|
| + std::vector<std::string> resource_priorities_split_group(
|
| + base::SplitString(resource_priorities_trial_group, "_",
|
| + base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL));
|
| + if (resource_priorities_split_group.size() == 5 &&
|
| + resource_priorities_split_group[1].length() == 5) {
|
| + // fetchIncreasePriorities
|
| + if (resource_priorities_split_group[1].at(3) == '1')
|
| + layout_blocking_or_high_priority_threshold_ = net::MEDIUM;
|
| + enable_in_flight_layout_blocking_threshold_ =
|
| + resource_priorities_split_group[1].at(4) == '1';
|
| + size_t numeric_value = 0;
|
| + if (base::StringToSizeT(resource_priorities_split_group[2], &numeric_value))
|
| + in_flight_layout_blocking_threshold_ = numeric_value;
|
| + if (base::StringToSizeT(resource_priorities_split_group[3], &numeric_value))
|
| + max_num_delayable_while_layout_blocking_ = numeric_value;
|
| + if (base::StringToSizeT(resource_priorities_split_group[4], &numeric_value))
|
| + max_num_delayable_requests_ = numeric_value;
|
| + }
|
| }
|
|
|
| ResourceScheduler::~ResourceScheduler() {
|
|
|