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

Unified Diff: content/browser/loader/resource_scheduler.cc

Issue 2711633003: Reland of [ResourceScheduler] Yield after starting several requests (Closed)
Patch Set: Address comments from PS3 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 side-by-side diff with in-line comments
Download patch
« 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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: content/browser/loader/resource_scheduler.cc
diff --git a/content/browser/loader/resource_scheduler.cc b/content/browser/loader/resource_scheduler.cc
index 6d68cf1c438dd7b22621500e2dcc70af6fa917b0..5f8c5743eaa942546b867035cabaa9a94d6baefb 100644
--- a/content/browser/loader/resource_scheduler.cc
+++ b/content/browser/loader/resource_scheduler.cc
@@ -13,6 +13,7 @@
#include "base/feature_list.h"
#include "base/macros.h"
#include "base/metrics/field_trial.h"
+#include "base/metrics/field_trial_params.h"
#include "base/metrics/histogram_macros.h"
#include "base/stl_util.h"
#include "base/supports_user_data.h"
@@ -39,6 +40,16 @@ namespace {
const base::Feature kPrioritySupportedRequestsDelayable{
"PrioritySupportedRequestsDelayable", base::FEATURE_DISABLED_BY_DEFAULT};
+// In the event that many resource requests are started quickly, this feature
+// will periodically yield (e.g., delaying starting of requests) by posting a
+// task and waiting for the task to run to resume. This allows other
+// operations that rely on the IO thread (e.g., already running network
+// requests) to make progress.
+const base::Feature kNetworkSchedulerYielding{
+ "NetworkSchedulerYielding", base::FEATURE_DISABLED_BY_DEFAULT};
+const char kMaxRequestsBeforeYieldingParam[] = "MaxRequestsBeforeYieldingParam";
+const int kMaxRequestsBeforeYieldingDefault = 5;
+
enum StartMode {
START_SYNC,
START_ASYNC
@@ -61,6 +72,7 @@ enum class RequestStartTrigger {
CLIENT_KILL,
SPDY_PROXY_DETECTED,
REQUEST_REPRIORITIZED,
+ START_WAS_YIELDED,
};
const char* RequestStartTriggerString(RequestStartTrigger trigger) {
@@ -79,6 +91,8 @@ const char* RequestStartTriggerString(RequestStartTrigger trigger) {
return "SPDY_PROXY_DETECTED";
case RequestStartTrigger::REQUEST_REPRIORITIZED:
return "REQUEST_REPRIORITIZED";
+ case RequestStartTrigger::START_WAS_YIELDED:
+ return "START_WAS_YIELDED";
}
NOTREACHED();
return "Unknown";
@@ -348,7 +362,9 @@ void ResourceScheduler::RequestQueue::Insert(
// Each client represents a tab.
class ResourceScheduler::Client {
public:
- explicit Client(bool priority_requests_delayable)
+ Client(bool priority_requests_delayable,
+ bool yielding_scheduler_enabled,
+ int max_requests_before_yielding)
: is_loaded_(false),
has_html_body_(false),
using_spdy_proxy_(false),
@@ -356,6 +372,10 @@ class ResourceScheduler::Client {
total_layout_blocking_count_(0),
priority_requests_delayable_(priority_requests_delayable),
has_pending_start_task_(false),
+ started_requests_since_yielding_(0),
+ did_scheduler_yield_(false),
+ yielding_scheduler_enabled_(yielding_scheduler_enabled),
+ max_requests_before_yielding_(max_requests_before_yielding),
weak_ptr_factory_(this) {}
~Client() {}
@@ -363,11 +383,14 @@ class ResourceScheduler::Client {
void ScheduleRequest(net::URLRequest* url_request,
ScheduledResourceRequest* request) {
SetRequestAttributes(request, DetermineRequestAttributes(request));
- if (ShouldStartRequest(request) == START_REQUEST) {
+ ShouldStartReqResult should_start = ShouldStartRequest(request);
+ if (should_start == START_REQUEST) {
// New requests can be started synchronously without issue.
StartRequest(request, START_SYNC, RequestStartTrigger::NONE);
} else {
pending_requests_.Insert(request);
+ if (should_start == YIELD_SCHEDULER)
+ did_scheduler_yield_ = true;
}
}
@@ -464,6 +487,7 @@ class ResourceScheduler::Client {
DO_NOT_START_REQUEST_AND_STOP_SEARCHING,
DO_NOT_START_REQUEST_AND_KEEP_SEARCHING,
START_REQUEST,
+ YIELD_SCHEDULER
};
void InsertInFlightRequest(ScheduledResourceRequest* request) {
@@ -603,6 +627,17 @@ class ResourceScheduler::Client {
void StartRequest(ScheduledResourceRequest* request,
StartMode start_mode,
RequestStartTrigger trigger) {
+ started_requests_since_yielding_ += 1;
+ if (started_requests_since_yielding_ == 1) {
+ // This is the first started request since last yielding. Post a task to
+ // reset the counter and start any yielded tasks if necessary. We post
+ // this now instead of when we first yield so that if there is a pause
+ // between requests the counter is reset.
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(&Client::ResumeIfYielded, weak_ptr_factory_.GetWeakPtr()));
+ }
+
// Only log on requests that were blocked by the ResourceScheduler.
if (start_mode == START_ASYNC) {
DCHECK_NE(RequestStartTrigger::NONE, trigger);
@@ -666,7 +701,7 @@ class ResourceScheduler::Client {
if (!priority_requests_delayable_) {
if (using_spdy_proxy_ && url_request.url().SchemeIs(url::kHttpScheme))
- return START_REQUEST;
+ return ShouldStartOrYieldRequest();
url::SchemeHostPort scheme_host_port(url_request.url());
@@ -677,12 +712,12 @@ class ResourceScheduler::Client {
// crbug.com/164101. Also, theoretically we should not count a
// request-priority capable request against the delayable requests limit.
if (http_server_properties.SupportsRequestPriority(scheme_host_port))
- return START_REQUEST;
+ return ShouldStartOrYieldRequest();
}
// Non-delayable requests.
if (!RequestAttributesAreSet(request->attributes(), kAttributeDelayable))
- return START_REQUEST;
+ return ShouldStartOrYieldRequest();
if (in_flight_delayable_count_ >= kMaxNumDelayableRequestsPerClient)
return DO_NOT_START_REQUEST_AND_STOP_SEARCHING;
@@ -717,7 +752,7 @@ class ResourceScheduler::Client {
}
}
- return START_REQUEST;
+ return ShouldStartOrYieldRequest();
}
// It is common for a burst of messages to come from the renderer which
@@ -738,6 +773,27 @@ class ResourceScheduler::Client {
weak_ptr_factory_.GetWeakPtr(), trigger));
}
+ void ResumeIfYielded() {
+ bool yielded = did_scheduler_yield_;
+ started_requests_since_yielding_ = 0;
+ did_scheduler_yield_ = false;
+
+ if (yielded)
+ LoadAnyStartablePendingRequests(RequestStartTrigger::START_WAS_YIELDED);
+ }
+
+ // For a request that is ready to start, return START_REQUEST if the
+ // scheduler doesn't need to yield, else YIELD_SCHEDULER.
+ ShouldStartReqResult ShouldStartOrYieldRequest() const {
+ DCHECK_GE(started_requests_since_yielding_, 0);
+
+ if (!yielding_scheduler_enabled_ ||
+ started_requests_since_yielding_ < max_requests_before_yielding_) {
+ return START_REQUEST;
+ }
+ return YIELD_SCHEDULER;
+ }
+
void LoadAnyStartablePendingRequests(RequestStartTrigger trigger) {
// We iterate through all the pending requests, starting with the highest
// priority one. For each entry, one of three things can happen:
@@ -769,6 +825,9 @@ class ResourceScheduler::Client {
} else if (query_result == DO_NOT_START_REQUEST_AND_KEEP_SEARCHING) {
++request_iter;
continue;
+ } else if (query_result == YIELD_SCHEDULER) {
+ did_scheduler_yield_ = true;
+ break;
} else {
DCHECK(query_result == DO_NOT_START_REQUEST_AND_STOP_SEARCHING);
break;
@@ -794,12 +853,32 @@ class ResourceScheduler::Client {
bool has_pending_start_task_;
+ // The number of started requests since the last ResumeIfYielded task was
+ // run.
+ int started_requests_since_yielding_;
+
+ // If the scheduler had to yield the start of a request since the last
+ // ResumeIfYielded task was run.
+ bool did_scheduler_yield_;
+
+ // Whether or not to periodically yield when starting lots of requests.
+ bool yielding_scheduler_enabled_;
+
+ // The number of requests that can start before yielding.
+ int max_requests_before_yielding_;
+
base::WeakPtrFactory<ResourceScheduler::Client> weak_ptr_factory_;
};
ResourceScheduler::ResourceScheduler()
: priority_requests_delayable_(
- base::FeatureList::IsEnabled(kPrioritySupportedRequestsDelayable)) {}
+ base::FeatureList::IsEnabled(kPrioritySupportedRequestsDelayable)),
+ yielding_scheduler_enabled_(
+ base::FeatureList::IsEnabled(kNetworkSchedulerYielding)),
+ max_requests_before_yielding_(base::GetFieldTrialParamByFeatureAsInt(
+ kNetworkSchedulerYielding,
+ kMaxRequestsBeforeYieldingParam,
+ kMaxRequestsBeforeYieldingDefault)) {}
ResourceScheduler::~ResourceScheduler() {
DCHECK(unowned_requests_.empty());
@@ -856,7 +935,9 @@ void ResourceScheduler::OnClientCreated(int child_id,
ClientId client_id = MakeClientId(child_id, route_id);
DCHECK(!base::ContainsKey(client_map_, client_id));
- Client* client = new Client(priority_requests_delayable_);
+ Client* client =
+ new Client(priority_requests_delayable_, yielding_scheduler_enabled_,
+ max_requests_before_yielding_);
client_map_[client_id] = client;
}
« 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