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

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

Issue 1230133005: Fix Resource Priorities and Scheduling (Chrome Side) (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Switched the request classification to a bitfield of attributes Created 5 years, 4 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"
6
5 #include <set> 7 #include <set>
6 8
7 #include "content/browser/loader/resource_scheduler.h"
8
9 #include "base/metrics/field_trial.h" 9 #include "base/metrics/field_trial.h"
10 #include "base/metrics/histogram.h" 10 #include "base/metrics/histogram.h"
11 #include "base/stl_util.h" 11 #include "base/stl_util.h"
12 #include "base/strings/string_number_conversions.h" 12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_piece.h" 13 #include "base/strings/string_piece.h"
14 #include "base/time/time.h" 14 #include "base/time/time.h"
15 #include "content/common/resource_messages.h" 15 #include "content/common/resource_messages.h"
16 #include "content/browser/loader/resource_message_delegate.h" 16 #include "content/browser/loader/resource_message_delegate.h"
17 #include "content/public/browser/resource_controller.h" 17 #include "content/public/browser/resource_controller.h"
18 #include "content/public/browser/resource_request_info.h" 18 #include "content/public/browser/resource_request_info.h"
(...skipping 11 matching lines...) Expand all
30 namespace { 30 namespace {
31 31
32 // Field trial constants 32 // Field trial constants
33 const char kThrottleCoalesceFieldTrial[] = "RequestThrottlingAndCoalescing"; 33 const char kThrottleCoalesceFieldTrial[] = "RequestThrottlingAndCoalescing";
34 const char kThrottleCoalesceFieldTrialThrottle[] = "Throttle"; 34 const char kThrottleCoalesceFieldTrialThrottle[] = "Throttle";
35 const char kThrottleCoalesceFieldTrialCoalesce[] = "Coalesce"; 35 const char kThrottleCoalesceFieldTrialCoalesce[] = "Coalesce";
36 36
37 const char kRequestLimitFieldTrial[] = "OutstandingRequestLimiting"; 37 const char kRequestLimitFieldTrial[] = "OutstandingRequestLimiting";
38 const char kRequestLimitFieldTrialGroupPrefix[] = "Limit"; 38 const char kRequestLimitFieldTrialGroupPrefix[] = "Limit";
39 39
40 const char kResourcePrioritiesFieldTrial[] = "ResourcePriorities";
41
42 // Flags identifying various attributes of the request that are used
43 // when making scheduling decisions.
44 typedef uint8_t RequestAttributes;
mmenke 2015/08/13 21:27:44 nit: include <stdint.h>
mmenke 2015/08/13 21:27:45 I think "using RequestAttributes = uint8_t;" is no
Pat Meenan 2015/08/14 13:52:47 Done.
Pat Meenan 2015/08/14 13:52:47 Done.
45 const RequestAttributes kAttributeNone = 0x00;
46 const RequestAttributes kAttributeInFlight = 0x01;
47 const RequestAttributes kAttributeDelayable = 0x02;
48 const RequestAttributes kAttributeLayoutBlocking = 0x04;
49
40 // Post ResourceScheduler histograms of the following forms: 50 // Post ResourceScheduler histograms of the following forms:
41 // If |histogram_suffix| is NULL or the empty string: 51 // If |histogram_suffix| is NULL or the empty string:
42 // ResourceScheduler.base_name.histogram_name 52 // ResourceScheduler.base_name.histogram_name
43 // Else: 53 // Else:
44 // ResourceScheduler.base_name.histogram_name.histogram_suffix 54 // ResourceScheduler.base_name.histogram_name.histogram_suffix
45 void PostHistogram(const char* base_name, 55 void PostHistogram(const char* base_name,
46 const char* histogram_name, 56 const char* histogram_name,
47 const char* histogram_suffix, 57 const char* histogram_suffix,
48 base::TimeDelta time) { 58 base::TimeDelta time) {
49 std::string histogram = 59 std::string histogram =
(...skipping 17 matching lines...) Expand all
67 else if (num_clients <= 15) 77 else if (num_clients <= 15)
68 return "Max15Clients"; 78 return "Max15Clients";
69 else if (num_clients <= 30) 79 else if (num_clients <= 30)
70 return "Max30Clients"; 80 return "Max30Clients";
71 return "Over30Clients"; 81 return "Over30Clients";
72 } 82 }
73 83
74 } // namespace 84 } // namespace
75 85
76 static const size_t kCoalescedTimerPeriod = 5000; 86 static const size_t kCoalescedTimerPeriod = 5000;
77 static const size_t kMaxNumDelayableRequestsPerClient = 10; 87 static const size_t kDefaultMaxNumDelayableRequestsPerClient = 10;
78 static const size_t kMaxNumDelayableRequestsPerHost = 6; 88 static const size_t kMaxNumDelayableRequestsPerHost = 6;
79 static const size_t kMaxNumThrottledRequestsPerClient = 1; 89 static const size_t kMaxNumThrottledRequestsPerClient = 1;
90 static const size_t kDefaultMaxNumDelayableWhileLayoutBlocking = 1;
91 static const net::RequestPriority
92 kDefaultLayoutBlockingPriorityThreshold = net::LOW;
80 93
81 struct ResourceScheduler::RequestPriorityParams { 94 struct ResourceScheduler::RequestPriorityParams {
82 RequestPriorityParams() 95 RequestPriorityParams()
83 : priority(net::DEFAULT_PRIORITY), 96 : priority(net::DEFAULT_PRIORITY),
84 intra_priority(0) { 97 intra_priority(0) {
85 } 98 }
86 99
87 RequestPriorityParams(net::RequestPriority priority, int intra_priority) 100 RequestPriorityParams(net::RequestPriority priority, int intra_priority)
88 : priority(priority), 101 : priority(priority),
89 intra_priority(intra_priority) { 102 intra_priority(intra_priority) {
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
170 ScheduledResourceRequest(const ClientId& client_id, 183 ScheduledResourceRequest(const ClientId& client_id,
171 net::URLRequest* request, 184 net::URLRequest* request,
172 ResourceScheduler* scheduler, 185 ResourceScheduler* scheduler,
173 const RequestPriorityParams& priority) 186 const RequestPriorityParams& priority)
174 : ResourceMessageDelegate(request), 187 : ResourceMessageDelegate(request),
175 client_id_(client_id), 188 client_id_(client_id),
176 client_state_on_creation_(scheduler->GetClientState(client_id_)), 189 client_state_on_creation_(scheduler->GetClientState(client_id_)),
177 request_(request), 190 request_(request),
178 ready_(false), 191 ready_(false),
179 deferred_(false), 192 deferred_(false),
180 classification_(NORMAL_REQUEST), 193 attributes_(kAttributeNone),
181 scheduler_(scheduler), 194 scheduler_(scheduler),
182 priority_(priority), 195 priority_(priority),
183 fifo_ordering_(0) { 196 fifo_ordering_(0) {
184 } 197 }
185 198
186 ~ScheduledResourceRequest() override { scheduler_->RemoveRequest(this); } 199 ~ScheduledResourceRequest() override { scheduler_->RemoveRequest(this); }
187 200
188 void Start() { 201 void Start() {
189 ready_ = true; 202 ready_ = true;
190 if (!request_->status().is_success()) 203 if (!request_->status().is_success())
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
223 const RequestPriorityParams& get_request_priority_params() const { 236 const RequestPriorityParams& get_request_priority_params() const {
224 return priority_; 237 return priority_;
225 } 238 }
226 const ClientId& client_id() const { return client_id_; } 239 const ClientId& client_id() const { return client_id_; }
227 net::URLRequest* url_request() { return request_; } 240 net::URLRequest* url_request() { return request_; }
228 const net::URLRequest* url_request() const { return request_; } 241 const net::URLRequest* url_request() const { return request_; }
229 uint32 fifo_ordering() const { return fifo_ordering_; } 242 uint32 fifo_ordering() const { return fifo_ordering_; }
230 void set_fifo_ordering(uint32 fifo_ordering) { 243 void set_fifo_ordering(uint32 fifo_ordering) {
231 fifo_ordering_ = fifo_ordering; 244 fifo_ordering_ = fifo_ordering;
232 } 245 }
233 RequestClassification classification() const { 246 RequestAttributes attributes() const {
234 return classification_; 247 return attributes_;
235 } 248 }
236 void set_classification(RequestClassification classification) { 249 void set_attributes(RequestAttributes attributes) {
237 classification_ = classification; 250 attributes_ = attributes;
238 } 251 }
239 252
240 private: 253 private:
241 // ResourceMessageDelegate interface: 254 // ResourceMessageDelegate interface:
242 bool OnMessageReceived(const IPC::Message& message) override { 255 bool OnMessageReceived(const IPC::Message& message) override {
243 bool handled = true; 256 bool handled = true;
244 IPC_BEGIN_MESSAGE_MAP(ScheduledResourceRequest, message) 257 IPC_BEGIN_MESSAGE_MAP(ScheduledResourceRequest, message)
245 IPC_MESSAGE_HANDLER(ResourceHostMsg_DidChangePriority, DidChangePriority) 258 IPC_MESSAGE_HANDLER(ResourceHostMsg_DidChangePriority, DidChangePriority)
246 IPC_MESSAGE_UNHANDLED(handled = false) 259 IPC_MESSAGE_UNHANDLED(handled = false)
247 IPC_END_MESSAGE_MAP() 260 IPC_END_MESSAGE_MAP()
(...skipping 11 matching lines...) Expand all
259 void DidChangePriority(int request_id, net::RequestPriority new_priority, 272 void DidChangePriority(int request_id, net::RequestPriority new_priority,
260 int intra_priority_value) { 273 int intra_priority_value) {
261 scheduler_->ReprioritizeRequest(this, new_priority, intra_priority_value); 274 scheduler_->ReprioritizeRequest(this, new_priority, intra_priority_value);
262 } 275 }
263 276
264 const ClientId client_id_; 277 const ClientId client_id_;
265 const ResourceScheduler::ClientState client_state_on_creation_; 278 const ResourceScheduler::ClientState client_state_on_creation_;
266 net::URLRequest* request_; 279 net::URLRequest* request_;
267 bool ready_; 280 bool ready_;
268 bool deferred_; 281 bool deferred_;
269 RequestClassification classification_; 282 RequestAttributes attributes_;
270 ResourceScheduler* scheduler_; 283 ResourceScheduler* scheduler_;
271 RequestPriorityParams priority_; 284 RequestPriorityParams priority_;
272 uint32 fifo_ordering_; 285 uint32 fifo_ordering_;
273 base::TimeTicks time_deferred_; 286 base::TimeTicks time_deferred_;
274 287
275 DISALLOW_COPY_AND_ASSIGN(ScheduledResourceRequest); 288 DISALLOW_COPY_AND_ASSIGN(ScheduledResourceRequest);
276 }; 289 };
277 290
278 bool ResourceScheduler::ScheduledResourceSorter::operator()( 291 bool ResourceScheduler::ScheduledResourceSorter::operator()(
279 const ScheduledResourceRequest* a, 292 const ScheduledResourceRequest* a,
(...skipping 21 matching lines...) Expand all
301 // Each client represents a tab. 314 // Each client represents a tab.
302 class ResourceScheduler::Client { 315 class ResourceScheduler::Client {
303 public: 316 public:
304 explicit Client(ResourceScheduler* scheduler, 317 explicit Client(ResourceScheduler* scheduler,
305 bool is_visible, 318 bool is_visible,
306 bool is_audible) 319 bool is_audible)
307 : is_audible_(is_audible), 320 : is_audible_(is_audible),
308 is_visible_(is_visible), 321 is_visible_(is_visible),
309 is_loaded_(false), 322 is_loaded_(false),
310 is_paused_(false), 323 is_paused_(false),
311 has_body_(false), 324 has_html_body_(false),
312 using_spdy_proxy_(false), 325 using_spdy_proxy_(false),
313 load_started_time_(base::TimeTicks::Now()), 326 load_started_time_(base::TimeTicks::Now()),
314 scheduler_(scheduler), 327 scheduler_(scheduler),
315 in_flight_delayable_count_(0), 328 in_flight_delayable_count_(0),
316 total_layout_blocking_count_(0), 329 total_layout_blocking_count_(0),
317 throttle_state_(ResourceScheduler::THROTTLED) {} 330 throttle_state_(ResourceScheduler::THROTTLED) {
331 }
318 332
319 ~Client() { 333 ~Client() {
320 // Update to default state and pause to ensure the scheduler has a 334 // Update to default state and pause to ensure the scheduler has a
321 // correct count of relevant types of clients. 335 // correct count of relevant types of clients.
322 is_visible_ = false; 336 is_visible_ = false;
323 is_audible_ = false; 337 is_audible_ = false;
324 is_paused_ = true; 338 is_paused_ = true;
325 UpdateThrottleState(); 339 UpdateThrottleState();
326 } 340 }
327 341
328 void ScheduleRequest( 342 void ScheduleRequest(
329 net::URLRequest* url_request, 343 net::URLRequest* url_request,
330 ScheduledResourceRequest* request) { 344 ScheduledResourceRequest* request) {
345 SetRequestAttributes(request, DetermineRequestAttributes(request));
331 if (ShouldStartRequest(request) == START_REQUEST) 346 if (ShouldStartRequest(request) == START_REQUEST)
332 StartRequest(request); 347 StartRequest(request);
333 else 348 else
334 pending_requests_.Insert(request); 349 pending_requests_.Insert(request);
335 SetRequestClassification(request, ClassifyRequest(request));
336 } 350 }
337 351
338 void RemoveRequest(ScheduledResourceRequest* request) { 352 void RemoveRequest(ScheduledResourceRequest* request) {
339 if (pending_requests_.IsQueued(request)) { 353 if (pending_requests_.IsQueued(request)) {
340 pending_requests_.Erase(request); 354 pending_requests_.Erase(request);
341 DCHECK(!ContainsKey(in_flight_requests_, request)); 355 DCHECK(!ContainsKey(in_flight_requests_, request));
342 } else { 356 } else {
343 EraseInFlightRequest(request); 357 EraseInFlightRequest(request);
344 358
345 // Removing this request may have freed up another to load. 359 // Removing this request may have freed up another to load.
346 LoadAnyStartablePendingRequests(); 360 LoadAnyStartablePendingRequests();
347 } 361 }
348 } 362 }
349 363
350 RequestSet StartAndRemoveAllRequests() { 364 RequestSet StartAndRemoveAllRequests() {
351 // First start any pending requests so that they will be moved into 365 // First start any pending requests so that they will be moved into
352 // in_flight_requests_. This may exceed the limits 366 // in_flight_requests_. This may exceed the limits
353 // kMaxNumDelayableRequestsPerClient, kMaxNumDelayableRequestsPerHost and 367 // kDefaultMaxNumDelayableRequestsPerClient, kMaxNumDelayableRequestsPerHost
354 // kMaxNumThrottledRequestsPerClient, so this method must not do anything 368 // and kMaxNumThrottledRequestsPerClient, so this method must not do
355 // that depends on those limits before calling ClearInFlightRequests() 369 // anything that depends on those limits before calling
356 // below. 370 // ClearInFlightRequests() below.
357 while (!pending_requests_.IsEmpty()) { 371 while (!pending_requests_.IsEmpty()) {
358 ScheduledResourceRequest* request = 372 ScheduledResourceRequest* request =
359 *pending_requests_.GetNextHighestIterator(); 373 *pending_requests_.GetNextHighestIterator();
360 pending_requests_.Erase(request); 374 pending_requests_.Erase(request);
361 // StartRequest() may modify pending_requests_. TODO(ricea): Does it? 375 // StartRequest() may modify pending_requests_. TODO(ricea): Does it?
362 StartRequest(request); 376 StartRequest(request);
363 } 377 }
364 RequestSet unowned_requests; 378 RequestSet unowned_requests;
365 for (RequestSet::iterator it = in_flight_requests_.begin(); 379 for (RequestSet::iterator it = in_flight_requests_.begin();
366 it != in_flight_requests_.end(); ++it) { 380 it != in_flight_requests_.end(); ++it) {
367 unowned_requests.insert(*it); 381 unowned_requests.insert(*it);
368 (*it)->set_classification(NORMAL_REQUEST); 382 (*it)->set_attributes(kAttributeNone);
369 } 383 }
370 ClearInFlightRequests(); 384 ClearInFlightRequests();
371 return unowned_requests; 385 return unowned_requests;
372 } 386 }
373 387
374 bool is_active() const { return is_visible_ || is_audible_; } 388 bool is_active() const { return is_visible_ || is_audible_; }
375 389
376 bool is_loaded() const { return is_loaded_; } 390 bool is_loaded() const { return is_loaded_; }
377 391
378 bool is_visible() const { return is_visible_; } 392 bool is_visible() const { return is_visible_; }
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
463 scheduler_->DecrementActiveClientsLoading(); 477 scheduler_->DecrementActiveClientsLoading();
464 } 478 }
465 if (throttle_state_ == COALESCED) { 479 if (throttle_state_ == COALESCED) {
466 scheduler_->IncrementCoalescedClients(); 480 scheduler_->IncrementCoalescedClients();
467 } else if (old_throttle_state == COALESCED) { 481 } else if (old_throttle_state == COALESCED) {
468 scheduler_->DecrementCoalescedClients(); 482 scheduler_->DecrementCoalescedClients();
469 } 483 }
470 } 484 }
471 485
472 void OnNavigate() { 486 void OnNavigate() {
473 has_body_ = false; 487 has_html_body_ = false;
474 is_loaded_ = false; 488 is_loaded_ = false;
475 } 489 }
476 490
477 void OnWillInsertBody() { 491 void OnWillInsertBody() {
478 has_body_ = true; 492 has_html_body_ = true;
479 LoadAnyStartablePendingRequests(); 493 LoadAnyStartablePendingRequests();
480 } 494 }
481 495
482 void OnReceivedSpdyProxiedHttpResponse() { 496 void OnReceivedSpdyProxiedHttpResponse() {
483 if (!using_spdy_proxy_) { 497 if (!using_spdy_proxy_) {
484 using_spdy_proxy_ = true; 498 using_spdy_proxy_ = true;
485 LoadAnyStartablePendingRequests(); 499 LoadAnyStartablePendingRequests();
486 } 500 }
487 } 501 }
488 502
489 void ReprioritizeRequest(ScheduledResourceRequest* request, 503 void ReprioritizeRequest(ScheduledResourceRequest* request,
490 RequestPriorityParams old_priority_params, 504 RequestPriorityParams old_priority_params,
491 RequestPriorityParams new_priority_params) { 505 RequestPriorityParams new_priority_params) {
492 request->url_request()->SetPriority(new_priority_params.priority); 506 request->url_request()->SetPriority(new_priority_params.priority);
493 request->set_request_priority_params(new_priority_params); 507 request->set_request_priority_params(new_priority_params);
508 SetRequestAttributes(request, DetermineRequestAttributes(request));
494 if (!pending_requests_.IsQueued(request)) { 509 if (!pending_requests_.IsQueued(request)) {
495 DCHECK(ContainsKey(in_flight_requests_, request)); 510 DCHECK(ContainsKey(in_flight_requests_, request));
496 // The priority of the request and priority support of the server may
497 // have changed, so update the delayable count.
498 SetRequestClassification(request, ClassifyRequest(request));
499 // Request has already started. 511 // Request has already started.
500 return; 512 return;
501 } 513 }
502 514
503 pending_requests_.Erase(request); 515 pending_requests_.Erase(request);
504 pending_requests_.Insert(request); 516 pending_requests_.Insert(request);
505 517
506 if (new_priority_params.priority > old_priority_params.priority) { 518 if (new_priority_params.priority > old_priority_params.priority) {
507 // Check if this request is now able to load at its new priority. 519 // Check if this request is now able to load at its new priority.
508 LoadAnyStartablePendingRequests(); 520 LoadAnyStartablePendingRequests();
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
555 567
556 private: 568 private:
557 enum ShouldStartReqResult { 569 enum ShouldStartReqResult {
558 DO_NOT_START_REQUEST_AND_STOP_SEARCHING, 570 DO_NOT_START_REQUEST_AND_STOP_SEARCHING,
559 DO_NOT_START_REQUEST_AND_KEEP_SEARCHING, 571 DO_NOT_START_REQUEST_AND_KEEP_SEARCHING,
560 START_REQUEST, 572 START_REQUEST,
561 }; 573 };
562 574
563 void InsertInFlightRequest(ScheduledResourceRequest* request) { 575 void InsertInFlightRequest(ScheduledResourceRequest* request) {
564 in_flight_requests_.insert(request); 576 in_flight_requests_.insert(request);
565 SetRequestClassification(request, ClassifyRequest(request)); 577 SetRequestAttributes(request, DetermineRequestAttributes(request));
566 } 578 }
567 579
568 void EraseInFlightRequest(ScheduledResourceRequest* request) { 580 void EraseInFlightRequest(ScheduledResourceRequest* request) {
569 size_t erased = in_flight_requests_.erase(request); 581 size_t erased = in_flight_requests_.erase(request);
570 DCHECK_EQ(1u, erased); 582 DCHECK_EQ(1u, erased);
571 // Clear any special state that we were tracking for this request. 583 // Clear any special state that we were tracking for this request.
572 SetRequestClassification(request, NORMAL_REQUEST); 584 SetRequestAttributes(request, kAttributeNone);
573 } 585 }
574 586
575 void ClearInFlightRequests() { 587 void ClearInFlightRequests() {
576 in_flight_requests_.clear(); 588 in_flight_requests_.clear();
577 in_flight_delayable_count_ = 0; 589 in_flight_delayable_count_ = 0;
578 total_layout_blocking_count_ = 0; 590 total_layout_blocking_count_ = 0;
579 } 591 }
580 592
581 size_t CountRequestsWithClassification( 593 size_t CountRequestsWithAttributes(
582 const RequestClassification classification, const bool include_pending) { 594 const RequestAttributes attributes,
583 size_t classification_request_count = 0; 595 const bool include_pending) {
596 size_t matching_request_count = 0;
584 for (RequestSet::const_iterator it = in_flight_requests_.begin(); 597 for (RequestSet::const_iterator it = in_flight_requests_.begin();
585 it != in_flight_requests_.end(); ++it) { 598 it != in_flight_requests_.end(); ++it) {
586 if ((*it)->classification() == classification) 599 if (RequestAttributesAreSet((*it)->attributes(), attributes))
587 classification_request_count++; 600 matching_request_count++;
588 } 601 }
589 if (include_pending) { 602 if (include_pending) {
590 for (RequestQueue::NetQueue::const_iterator 603 for (RequestQueue::NetQueue::const_iterator
591 it = pending_requests_.GetNextHighestIterator(); 604 it = pending_requests_.GetNextHighestIterator();
592 it != pending_requests_.End(); ++it) { 605 it != pending_requests_.End(); ++it) {
593 if ((*it)->classification() == classification) 606 if (RequestAttributesAreSet((*it)->attributes(), attributes))
594 classification_request_count++; 607 matching_request_count++;
595 } 608 }
596 } 609 }
597 return classification_request_count; 610 return matching_request_count;
598 } 611 }
599 612
600 void SetRequestClassification(ScheduledResourceRequest* request, 613 bool RequestAttributesAreSet(RequestAttributes request_attributes,
601 RequestClassification classification) { 614 RequestAttributes matching_attributes) const {
602 RequestClassification old_classification = request->classification(); 615 return (request_attributes & matching_attributes) == matching_attributes;
603 if (old_classification == classification) 616 }
617
618 void SetRequestAttributes(ScheduledResourceRequest* request,
619 RequestAttributes attributes) {
620 RequestAttributes old_attributes = request->attributes();
621 if (old_attributes == attributes)
604 return; 622 return;
605 623
606 if (old_classification == IN_FLIGHT_DELAYABLE_REQUEST) 624 if (RequestAttributesAreSet(old_attributes,
625 kAttributeInFlight | kAttributeDelayable)) {
mmenke 2015/08/13 21:27:45 nit: +1 indent
Pat Meenan 2015/08/14 13:52:47 Done.
607 in_flight_delayable_count_--; 626 in_flight_delayable_count_--;
608 if (old_classification == LAYOUT_BLOCKING_REQUEST) 627 }
628 if (RequestAttributesAreSet(old_attributes, kAttributeLayoutBlocking))
609 total_layout_blocking_count_--; 629 total_layout_blocking_count_--;
610 630
611 if (classification == IN_FLIGHT_DELAYABLE_REQUEST) 631 if (RequestAttributesAreSet(attributes,
632 kAttributeInFlight | kAttributeDelayable)) {
mmenke 2015/08/13 21:27:45 nit: +1 indent
Pat Meenan 2015/08/14 13:52:47 Done.
612 in_flight_delayable_count_++; 633 in_flight_delayable_count_++;
613 if (classification == LAYOUT_BLOCKING_REQUEST) 634 }
635 if (RequestAttributesAreSet(attributes, kAttributeLayoutBlocking))
614 total_layout_blocking_count_++; 636 total_layout_blocking_count_++;
615 637
616 request->set_classification(classification); 638 request->set_attributes(attributes);
617 DCHECK_EQ( 639 DCHECK_EQ(CountRequestsWithAttributes(
618 CountRequestsWithClassification(IN_FLIGHT_DELAYABLE_REQUEST, false), 640 kAttributeInFlight | kAttributeDelayable, false),
619 in_flight_delayable_count_); 641 in_flight_delayable_count_);
620 DCHECK_EQ(CountRequestsWithClassification(LAYOUT_BLOCKING_REQUEST, true), 642 DCHECK_EQ(CountRequestsWithAttributes(kAttributeLayoutBlocking, true),
621 total_layout_blocking_count_); 643 total_layout_blocking_count_);
622 } 644 }
623 645
624 RequestClassification ClassifyRequest(ScheduledResourceRequest* request) { 646 RequestAttributes DetermineRequestAttributes(
625 // If a request is already marked as layout-blocking make sure to keep the 647 ScheduledResourceRequest* request) {
626 // classification across redirects unless the priority was lowered. 648 RequestAttributes attributes = kAttributeNone;
627 if (request->classification() == LAYOUT_BLOCKING_REQUEST &&
628 request->url_request()->priority() > net::LOW) {
629 return LAYOUT_BLOCKING_REQUEST;
630 }
631 649
632 if (!has_body_ && request->url_request()->priority() > net::LOW) 650 if (ContainsKey(in_flight_requests_, request))
633 return LAYOUT_BLOCKING_REQUEST; 651 attributes = attributes | kAttributeInFlight;
mmenke 2015/08/13 21:27:45 Any reason not to use |= on all of these?
Pat Meenan 2015/08/14 13:52:47 I wasn't sure if it would look too much like != an
634 652
635 if (request->url_request()->priority() < net::LOW) { 653 if (RequestAttributesAreSet(request->attributes(),
654 kAttributeLayoutBlocking)) {
655 // If a request is already marked as layout-blocking make sure to keep the
656 // attribute across redirects.
657 attributes = attributes | kAttributeLayoutBlocking;
658 } else if (!has_html_body_ &&
659 request->url_request()->priority() >
660 scheduler_->non_delayable_threshold()) {
661 // Requests that are above the non_delayable threshold before the HTML
662 // body has been parsed are inferred to be layout-blocking.
663 attributes = attributes | kAttributeLayoutBlocking;
664 } else if (request->url_request()->priority() <
665 scheduler_->non_delayable_threshold()) {
666 // Resources below the non_delayable_threshold that are being requested
667 // from a server that does not support native prioritization are
668 // considered delayable.
636 net::HostPortPair host_port_pair = 669 net::HostPortPair host_port_pair =
637 net::HostPortPair::FromURL(request->url_request()->url()); 670 net::HostPortPair::FromURL(request->url_request()->url());
638 net::HttpServerProperties& http_server_properties = 671 net::HttpServerProperties& http_server_properties =
639 *request->url_request()->context()->http_server_properties(); 672 *request->url_request()->context()->http_server_properties();
640 if (!http_server_properties.SupportsRequestPriority(host_port_pair) && 673 if (!http_server_properties.SupportsRequestPriority(host_port_pair))
641 ContainsKey(in_flight_requests_, request)) { 674 attributes = attributes | kAttributeDelayable;
642 return IN_FLIGHT_DELAYABLE_REQUEST;
643 }
644 } 675 }
645 return NORMAL_REQUEST; 676
677 return attributes;
646 } 678 }
647 679
648 bool ShouldKeepSearching( 680 bool ShouldKeepSearching(
649 const net::HostPortPair& active_request_host) const { 681 const net::HostPortPair& active_request_host) const {
650 size_t same_host_count = 0; 682 size_t same_host_count = 0;
651 for (RequestSet::const_iterator it = in_flight_requests_.begin(); 683 for (RequestSet::const_iterator it = in_flight_requests_.begin();
652 it != in_flight_requests_.end(); ++it) { 684 it != in_flight_requests_.end(); ++it) {
653 net::HostPortPair host_port_pair = 685 net::HostPortPair host_port_pair =
654 net::HostPortPair::FromURL((*it)->url_request()->url()); 686 net::HostPortPair::FromURL((*it)->url_request()->url());
655 if (active_request_host.Equals(host_port_pair)) { 687 if (active_request_host.Equals(host_port_pair)) {
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
761 return START_REQUEST; 793 return START_REQUEST;
762 } 794 }
763 795
764 if (throttle_state_ == THROTTLED && 796 if (throttle_state_ == THROTTLED &&
765 in_flight_requests_.size() >= kMaxNumThrottledRequestsPerClient) { 797 in_flight_requests_.size() >= kMaxNumThrottledRequestsPerClient) {
766 // There may still be request-priority-capable requests that should be 798 // There may still be request-priority-capable requests that should be
767 // issued. 799 // issued.
768 return DO_NOT_START_REQUEST_AND_KEEP_SEARCHING; 800 return DO_NOT_START_REQUEST_AND_KEEP_SEARCHING;
769 } 801 }
770 802
771 // High-priority and layout-blocking requests. 803 // non-delayable requests.
mmenke 2015/08/13 21:27:45 Nit: "Non-delayable requests." (capitalize)
Pat Meenan 2015/08/14 13:52:47 Done.
772 if (url_request.priority() >= net::LOW) { 804 if (!RequestAttributesAreSet(request->attributes(), kAttributeDelayable)) {
773 return START_REQUEST; 805 return START_REQUEST;
774 } 806 }
mmenke 2015/08/13 21:27:45 nit: Remove braces
Pat Meenan 2015/08/14 13:52:47 I had them to be consistent with the rest of the f
775 807
776 if (in_flight_delayable_count_ >= kMaxNumDelayableRequestsPerClient) { 808 if (in_flight_delayable_count_ >=
809 scheduler_->max_num_delayable_requests()) {
777 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING; 810 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING;
778 } 811 }
779 812
780 if (ShouldKeepSearching(host_port_pair)) { 813 if (ShouldKeepSearching(host_port_pair)) {
781 // There may be other requests for other hosts we'd allow, 814 // There may be other requests for other hosts we'd allow,
782 // so keep checking. 815 // so keep checking.
783 return DO_NOT_START_REQUEST_AND_KEEP_SEARCHING; 816 return DO_NOT_START_REQUEST_AND_KEEP_SEARCHING;
784 } 817 }
785 818
786 bool have_immediate_requests_in_flight = 819 // The in-flight requests consist of layout-blocking requests,
787 in_flight_requests_.size() > in_flight_delayable_count_; 820 // normal requests and delayable requests. Everything except for
788 if (have_immediate_requests_in_flight && 821 // delayable requests is handled above here so this is deciding what to
789 (!has_body_ || total_layout_blocking_count_ != 0) && 822 // do with a delayable request while we are in the layout-blocking phase
790 // Do not allow a low priority request through in parallel if 823 // of loading.
791 // we are in a limit field trial. 824 if (!has_html_body_ || total_layout_blocking_count_ != 0) {
792 (scheduler_->limit_outstanding_requests() || 825 size_t non_delayable_requests_in_flight_count =
793 in_flight_delayable_count_ != 0)) { 826 in_flight_requests_.size() - in_flight_delayable_count_;
794 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING; 827 if (scheduler_->enable_in_flight_non_delayable_threshold()) {
828 if (non_delayable_requests_in_flight_count >
829 scheduler_->in_flight_non_delayable_threshold()) {
830 // Too many higher priority in-flight requests to allow lower priority
831 // requests through.
832 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING;
833 }
834 if (in_flight_requests_.size() > 0 &&
835 (scheduler_->limit_outstanding_requests() ||
836 in_flight_delayable_count_ >=
837 scheduler_->max_num_delayable_while_layout_blocking())) {
838 // Block the request if at least one request is in flight and the
839 // number of in-flight delayable requests has hit the configured
840 // limit.
841 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING;
842 }
843 } else if (non_delayable_requests_in_flight_count > 0 &&
844 (scheduler_->limit_outstanding_requests() ||
845 in_flight_delayable_count_ >=
846 scheduler_->max_num_delayable_while_layout_blocking())) {
847 // If there are no high-priority requests in flight the floodgates open.
848 // If there are high-priority requests in-flight then limit the number
849 // of lower-priority requests (or zero if a limit field trial is
850 // active).
851 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING;
852 }
795 } 853 }
796 854
797 return START_REQUEST; 855 return START_REQUEST;
798 } 856 }
799 857
800 void LoadAnyStartablePendingRequests() { 858 void LoadAnyStartablePendingRequests() {
801 // We iterate through all the pending requests, starting with the highest 859 // We iterate through all the pending requests, starting with the highest
802 // priority one. For each entry, one of three things can happen: 860 // priority one. For each entry, one of three things can happen:
803 // 1) We start the request, remove it from the list, and keep checking. 861 // 1) We start the request, remove it from the list, and keep checking.
804 // 2) We do NOT start the request, but ShouldStartRequest() signals us that 862 // 2) We do NOT start the request, but ShouldStartRequest() signals us that
(...skipping 26 matching lines...) Expand all
831 DCHECK(query_result == DO_NOT_START_REQUEST_AND_STOP_SEARCHING); 889 DCHECK(query_result == DO_NOT_START_REQUEST_AND_STOP_SEARCHING);
832 break; 890 break;
833 } 891 }
834 } 892 }
835 } 893 }
836 894
837 bool is_audible_; 895 bool is_audible_;
838 bool is_visible_; 896 bool is_visible_;
839 bool is_loaded_; 897 bool is_loaded_;
840 bool is_paused_; 898 bool is_paused_;
841 bool has_body_; 899 // Tracks if the main HTML parser has reached the body which marks the end of
900 // layout-blocking resources.
901 bool has_html_body_;
842 bool using_spdy_proxy_; 902 bool using_spdy_proxy_;
843 RequestQueue pending_requests_; 903 RequestQueue pending_requests_;
844 RequestSet in_flight_requests_; 904 RequestSet in_flight_requests_;
845 base::TimeTicks load_started_time_; 905 base::TimeTicks load_started_time_;
846 // The last time the client switched state between active and background. 906 // The last time the client switched state between active and background.
847 base::TimeTicks last_active_switch_time_; 907 base::TimeTicks last_active_switch_time_;
848 ResourceScheduler* scheduler_; 908 ResourceScheduler* scheduler_;
849 // The number of delayable in-flight requests. 909 // The number of delayable in-flight requests.
850 size_t in_flight_delayable_count_; 910 size_t in_flight_delayable_count_;
851 // The number of layout-blocking in-flight requests. 911 // The number of layout-blocking in-flight requests.
852 size_t total_layout_blocking_count_; 912 size_t total_layout_blocking_count_;
853 ResourceScheduler::ClientThrottleState throttle_state_; 913 ResourceScheduler::ClientThrottleState throttle_state_;
854 }; 914 };
855 915
856 ResourceScheduler::ResourceScheduler() 916 ResourceScheduler::ResourceScheduler()
857 : should_coalesce_(false), 917 : should_coalesce_(false),
858 should_throttle_(false), 918 should_throttle_(false),
859 active_clients_loading_(0), 919 active_clients_loading_(0),
860 coalesced_clients_(0), 920 coalesced_clients_(0),
861 limit_outstanding_requests_(false), 921 limit_outstanding_requests_(false),
862 outstanding_request_limit_(0), 922 outstanding_request_limit_(0),
923 non_delayable_threshold_(
924 kDefaultLayoutBlockingPriorityThreshold),
925 enable_in_flight_non_delayable_threshold_(false),
926 in_flight_non_delayable_threshold_(0),
927 max_num_delayable_while_layout_blocking_(
928 kDefaultMaxNumDelayableWhileLayoutBlocking),
929 max_num_delayable_requests_(kDefaultMaxNumDelayableRequestsPerClient),
863 coalescing_timer_(new base::Timer(true /* retain_user_task */, 930 coalescing_timer_(new base::Timer(true /* retain_user_task */,
864 true /* is_repeating */)) { 931 true /* is_repeating */)) {
865 std::string throttling_trial_group = 932 std::string throttling_trial_group =
866 base::FieldTrialList::FindFullName(kThrottleCoalesceFieldTrial); 933 base::FieldTrialList::FindFullName(kThrottleCoalesceFieldTrial);
867 if (throttling_trial_group == kThrottleCoalesceFieldTrialThrottle) { 934 if (throttling_trial_group == kThrottleCoalesceFieldTrialThrottle) {
868 should_throttle_ = true; 935 should_throttle_ = true;
869 } else if (throttling_trial_group == kThrottleCoalesceFieldTrialCoalesce) { 936 } else if (throttling_trial_group == kThrottleCoalesceFieldTrialCoalesce) {
870 should_coalesce_ = true; 937 should_coalesce_ = true;
871 should_throttle_ = true; 938 should_throttle_ = true;
872 } 939 }
873 940
874 std::string outstanding_limit_trial_group = 941 std::string outstanding_limit_trial_group =
875 base::FieldTrialList::FindFullName(kRequestLimitFieldTrial); 942 base::FieldTrialList::FindFullName(kRequestLimitFieldTrial);
876 std::vector<std::string> split_group( 943 std::vector<std::string> split_group(
877 base::SplitString(outstanding_limit_trial_group, "=", 944 base::SplitString(outstanding_limit_trial_group, "=",
878 base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL)); 945 base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL));
879 int outstanding_limit = 0; 946 int outstanding_limit = 0;
880 if (split_group.size() == 2 && 947 if (split_group.size() == 2 &&
881 split_group[0] == kRequestLimitFieldTrialGroupPrefix && 948 split_group[0] == kRequestLimitFieldTrialGroupPrefix &&
882 base::StringToInt(split_group[1], &outstanding_limit) && 949 base::StringToInt(split_group[1], &outstanding_limit) &&
883 outstanding_limit > 0) { 950 outstanding_limit > 0) {
884 limit_outstanding_requests_ = true; 951 limit_outstanding_requests_ = true;
885 outstanding_request_limit_ = outstanding_limit; 952 outstanding_request_limit_ = outstanding_limit;
886 } 953 }
954
955 // Set up the ResourceScheduling field trial options.
956 // The field trial parameters are also encoded into the group name since
957 // the variations component is not available from here and plumbing the
958 // options through the code is overkill for a short experiment.
959 //
960 // The group name encoding looks like this:
961 // <descriptiveName>_ABCDE_E2_F_G
962 // A - fetchDeferLateScripts (1 for true, 0 for false)
963 // B - fetchIncreaseFontPriority (1 for true, 0 for false)
964 // C - fetchIncreaseAsyncScriptPriority (1 for true, 0 for false)
965 // D - fetchIncreasePriorities (1 for true, 0 for false)
966 // E - fetchEnableLayoutBlockingThreshold (1 for true, 0 for false)
967 // E2 - fetchLayoutBlockingThreshold (Numeric)
968 // F - fetchMaxNumDelayableWhileLayoutBlocking (Numeric)
969 // G - fetchMaxNumDelayableRequests (Numeric)
970 std::string resource_priorities_trial_group =
971 base::FieldTrialList::FindFullName(kResourcePrioritiesFieldTrial);
972 std::vector<std::string> resource_priorities_split_group(
973 base::SplitString(resource_priorities_trial_group, "_",
974 base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL));
975 if (resource_priorities_split_group.size() == 5 &&
976 resource_priorities_split_group[1].length() == 5) {
977 // fetchIncreasePriorities
978 if (resource_priorities_split_group[1].at(3) == '1')
979 non_delayable_threshold_ = net::MEDIUM;
980 enable_in_flight_non_delayable_threshold_ =
981 resource_priorities_split_group[1].at(4) == '1';
982 size_t numeric_value = 0;
983 if (base::StringToSizeT(resource_priorities_split_group[2], &numeric_value))
984 in_flight_non_delayable_threshold_ = numeric_value;
985 if (base::StringToSizeT(resource_priorities_split_group[3], &numeric_value))
986 max_num_delayable_while_layout_blocking_ = numeric_value;
987 if (base::StringToSizeT(resource_priorities_split_group[4], &numeric_value))
988 max_num_delayable_requests_ = numeric_value;
989 }
887 } 990 }
888 991
889 ResourceScheduler::~ResourceScheduler() { 992 ResourceScheduler::~ResourceScheduler() {
890 DCHECK(unowned_requests_.empty()); 993 DCHECK(unowned_requests_.empty());
891 DCHECK(client_map_.empty()); 994 DCHECK(client_map_.empty());
892 } 995 }
893 996
894 void ResourceScheduler::SetThrottleOptionsForTesting(bool should_throttle, 997 void ResourceScheduler::SetThrottleOptionsForTesting(bool should_throttle,
895 bool should_coalesce) { 998 bool should_coalesce) {
896 should_coalesce_ = should_coalesce; 999 should_coalesce_ = should_coalesce;
(...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after
1202 client->ReprioritizeRequest( 1305 client->ReprioritizeRequest(
1203 request, old_priority_params, new_priority_params); 1306 request, old_priority_params, new_priority_params);
1204 } 1307 }
1205 1308
1206 ResourceScheduler::ClientId ResourceScheduler::MakeClientId( 1309 ResourceScheduler::ClientId ResourceScheduler::MakeClientId(
1207 int child_id, int route_id) { 1310 int child_id, int route_id) {
1208 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id; 1311 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id;
1209 } 1312 }
1210 1313
1211 } // namespace content 1314 } // 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