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

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

Issue 462813002: Changed resource scheduler to block until all critical resources actually load. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Updated the scheduler logic comment to match the new logic. Created 6 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 <set> 5 #include <set>
6 6
7 #include "content/browser/loader/resource_scheduler.h" 7 #include "content/browser/loader/resource_scheduler.h"
8 8
9 #include "base/stl_util.h" 9 #include "base/stl_util.h"
10 #include "content/common/resource_messages.h" 10 #include "content/common/resource_messages.h"
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
118 public: 118 public:
119 ScheduledResourceRequest(const ClientId& client_id, 119 ScheduledResourceRequest(const ClientId& client_id,
120 net::URLRequest* request, 120 net::URLRequest* request,
121 ResourceScheduler* scheduler, 121 ResourceScheduler* scheduler,
122 const RequestPriorityParams& priority) 122 const RequestPriorityParams& priority)
123 : ResourceMessageDelegate(request), 123 : ResourceMessageDelegate(request),
124 client_id_(client_id), 124 client_id_(client_id),
125 request_(request), 125 request_(request),
126 ready_(false), 126 ready_(false),
127 deferred_(false), 127 deferred_(false),
128 critical_(false),
128 scheduler_(scheduler), 129 scheduler_(scheduler),
129 priority_(priority), 130 priority_(priority),
130 fifo_ordering_(0), 131 fifo_ordering_(0),
131 accounted_as_delayable_request_(false) { 132 accounted_as_delayable_request_(false) {
132 TRACE_EVENT_ASYNC_BEGIN1("net", "URLRequest", request_, 133 TRACE_EVENT_ASYNC_BEGIN1("net", "URLRequest", request_,
133 "url", request->url().spec()); 134 "url", request->url().spec());
134 } 135 }
135 136
136 virtual ~ScheduledResourceRequest() { 137 virtual ~ScheduledResourceRequest() {
137 scheduler_->RemoveRequest(this); 138 scheduler_->RemoveRequest(this);
(...skipping 20 matching lines...) Expand all
158 uint32 fifo_ordering() const { return fifo_ordering_; } 159 uint32 fifo_ordering() const { return fifo_ordering_; }
159 void set_fifo_ordering(uint32 fifo_ordering) { 160 void set_fifo_ordering(uint32 fifo_ordering) {
160 fifo_ordering_ = fifo_ordering; 161 fifo_ordering_ = fifo_ordering;
161 } 162 }
162 bool accounted_as_delayable_request() const { 163 bool accounted_as_delayable_request() const {
163 return accounted_as_delayable_request_; 164 return accounted_as_delayable_request_;
164 } 165 }
165 void set_accounted_as_delayable_request(bool accounted) { 166 void set_accounted_as_delayable_request(bool accounted) {
166 accounted_as_delayable_request_ = accounted; 167 accounted_as_delayable_request_ = accounted;
167 } 168 }
169 bool critical() const {
170 return critical_;
171 }
172 void set_critical(bool critical) {
173 critical_ = critical;
174 }
168 175
169 private: 176 private:
170 // ResourceMessageDelegate interface: 177 // ResourceMessageDelegate interface:
171 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { 178 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
172 bool handled = true; 179 bool handled = true;
173 IPC_BEGIN_MESSAGE_MAP(ScheduledResourceRequest, message) 180 IPC_BEGIN_MESSAGE_MAP(ScheduledResourceRequest, message)
174 IPC_MESSAGE_HANDLER(ResourceHostMsg_DidChangePriority, DidChangePriority) 181 IPC_MESSAGE_HANDLER(ResourceHostMsg_DidChangePriority, DidChangePriority)
175 IPC_MESSAGE_UNHANDLED(handled = false) 182 IPC_MESSAGE_UNHANDLED(handled = false)
176 IPC_END_MESSAGE_MAP() 183 IPC_END_MESSAGE_MAP()
177 return handled; 184 return handled;
(...skipping 10 matching lines...) Expand all
188 195
189 void DidChangePriority(int request_id, net::RequestPriority new_priority, 196 void DidChangePriority(int request_id, net::RequestPriority new_priority,
190 int intra_priority_value) { 197 int intra_priority_value) {
191 scheduler_->ReprioritizeRequest(this, new_priority, intra_priority_value); 198 scheduler_->ReprioritizeRequest(this, new_priority, intra_priority_value);
192 } 199 }
193 200
194 ClientId client_id_; 201 ClientId client_id_;
195 net::URLRequest* request_; 202 net::URLRequest* request_;
196 bool ready_; 203 bool ready_;
197 bool deferred_; 204 bool deferred_;
205 bool critical_;
198 ResourceScheduler* scheduler_; 206 ResourceScheduler* scheduler_;
199 RequestPriorityParams priority_; 207 RequestPriorityParams priority_;
200 uint32 fifo_ordering_; 208 uint32 fifo_ordering_;
201 // True if the request is delayable in |in_flight_requests_|. 209 // True if the request is delayable in |in_flight_requests_|.
202 bool accounted_as_delayable_request_; 210 bool accounted_as_delayable_request_;
203 211
204 DISALLOW_COPY_AND_ASSIGN(ScheduledResourceRequest); 212 DISALLOW_COPY_AND_ASSIGN(ScheduledResourceRequest);
205 }; 213 };
206 214
207 bool ResourceScheduler::ScheduledResourceSorter::operator()( 215 bool ResourceScheduler::ScheduledResourceSorter::operator()(
(...skipping 23 matching lines...) Expand all
231 class ResourceScheduler::Client { 239 class ResourceScheduler::Client {
232 public: 240 public:
233 explicit Client(ResourceScheduler* scheduler) 241 explicit Client(ResourceScheduler* scheduler)
234 : is_audible_(false), 242 : is_audible_(false),
235 is_visible_(false), 243 is_visible_(false),
236 is_loaded_(false), 244 is_loaded_(false),
237 is_paused_(false), 245 is_paused_(false),
238 has_body_(false), 246 has_body_(false),
239 using_spdy_proxy_(false), 247 using_spdy_proxy_(false),
240 total_delayable_count_(0), 248 total_delayable_count_(0),
249 total_critical_count_(0),
241 throttle_state_(ResourceScheduler::THROTTLED) { 250 throttle_state_(ResourceScheduler::THROTTLED) {
242 scheduler_ = scheduler; 251 scheduler_ = scheduler;
243 } 252 }
244 253
245 ~Client() { 254 ~Client() {
246 // Update to default state and pause to ensure the scheduler has a 255 // Update to default state and pause to ensure the scheduler has a
247 // correct count of relevant types of clients. 256 // correct count of relevant types of clients.
248 is_visible_ = false; 257 is_visible_ = false;
249 is_audible_ = false; 258 is_audible_ = false;
250 is_paused_ = true; 259 is_paused_ = true;
(...skipping 21 matching lines...) Expand all
272 LoadAnyStartablePendingRequests(); 281 LoadAnyStartablePendingRequests();
273 } 282 }
274 } 283 }
275 284
276 RequestSet RemoveAllRequests() { 285 RequestSet RemoveAllRequests() {
277 RequestSet unowned_requests; 286 RequestSet unowned_requests;
278 for (RequestSet::iterator it = in_flight_requests_.begin(); 287 for (RequestSet::iterator it = in_flight_requests_.begin();
279 it != in_flight_requests_.end(); ++it) { 288 it != in_flight_requests_.end(); ++it) {
280 unowned_requests.insert(*it); 289 unowned_requests.insert(*it);
281 (*it)->set_accounted_as_delayable_request(false); 290 (*it)->set_accounted_as_delayable_request(false);
291 (*it)->set_critical(false);
282 } 292 }
283 ClearInFlightRequests(); 293 ClearInFlightRequests();
284 return unowned_requests; 294 return unowned_requests;
285 } 295 }
286 296
287 bool is_active() const { return is_visible_ || is_audible_; } 297 bool is_active() const { return is_visible_ || is_audible_; }
288 298
289 bool is_loaded() const { return is_loaded_; } 299 bool is_loaded() const { return is_loaded_; }
290 300
291 void OnAudibilityChanged(bool is_audible) { 301 void OnAudibilityChanged(bool is_audible) {
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
368 void ReprioritizeRequest(ScheduledResourceRequest* request, 378 void ReprioritizeRequest(ScheduledResourceRequest* request,
369 RequestPriorityParams old_priority_params, 379 RequestPriorityParams old_priority_params,
370 RequestPriorityParams new_priority_params) { 380 RequestPriorityParams new_priority_params) {
371 request->url_request()->SetPriority(new_priority_params.priority); 381 request->url_request()->SetPriority(new_priority_params.priority);
372 request->set_request_priority_params(new_priority_params); 382 request->set_request_priority_params(new_priority_params);
373 if (!pending_requests_.IsQueued(request)) { 383 if (!pending_requests_.IsQueued(request)) {
374 DCHECK(ContainsKey(in_flight_requests_, request)); 384 DCHECK(ContainsKey(in_flight_requests_, request));
375 // The priority and SPDY support may have changed, so update the 385 // The priority and SPDY support may have changed, so update the
376 // delayable count. 386 // delayable count.
377 SetRequestDelayable(request, IsDelayableRequest(request)); 387 SetRequestDelayable(request, IsDelayableRequest(request));
388 SetRequestCritical(request, IsCriticalRequest(request));
mmenke 2014/08/12 17:18:37 Should we have an enum instead of bools?
Pat Meenan 2014/08/13 00:20:12 Done.
378 // Request has already started. 389 // Request has already started.
379 return; 390 return;
380 } 391 }
381 392
382 pending_requests_.Erase(request); 393 pending_requests_.Erase(request);
383 pending_requests_.Insert(request); 394 pending_requests_.Insert(request);
384 395
385 if (new_priority_params.priority > old_priority_params.priority) { 396 if (new_priority_params.priority > old_priority_params.priority) {
386 // Check if this request is now able to load at its new priority. 397 // Check if this request is now able to load at its new priority.
387 LoadAnyStartablePendingRequests(); 398 LoadAnyStartablePendingRequests();
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
436 enum ShouldStartReqResult { 447 enum ShouldStartReqResult {
437 DO_NOT_START_REQUEST_AND_STOP_SEARCHING, 448 DO_NOT_START_REQUEST_AND_STOP_SEARCHING,
438 DO_NOT_START_REQUEST_AND_KEEP_SEARCHING, 449 DO_NOT_START_REQUEST_AND_KEEP_SEARCHING,
439 START_REQUEST, 450 START_REQUEST,
440 }; 451 };
441 452
442 void InsertInFlightRequest(ScheduledResourceRequest* request) { 453 void InsertInFlightRequest(ScheduledResourceRequest* request) {
443 in_flight_requests_.insert(request); 454 in_flight_requests_.insert(request);
444 if (IsDelayableRequest(request)) 455 if (IsDelayableRequest(request))
445 SetRequestDelayable(request, true); 456 SetRequestDelayable(request, true);
457 if (IsCriticalRequest(request))
458 SetRequestCritical(request, true);
446 } 459 }
447 460
448 void EraseInFlightRequest(ScheduledResourceRequest* request) { 461 void EraseInFlightRequest(ScheduledResourceRequest* request) {
449 size_t erased = in_flight_requests_.erase(request); 462 size_t erased = in_flight_requests_.erase(request);
450 DCHECK_EQ(1u, erased); 463 DCHECK_EQ(1u, erased);
451 SetRequestDelayable(request, false); 464 SetRequestDelayable(request, false);
452 DCHECK_LE(total_delayable_count_, in_flight_requests_.size()); 465 DCHECK_LE(total_delayable_count_, in_flight_requests_.size());
466 SetRequestCritical(request, false);
467 DCHECK_LE(total_critical_count_, in_flight_requests_.size());
453 } 468 }
454 469
455 void ClearInFlightRequests() { 470 void ClearInFlightRequests() {
456 in_flight_requests_.clear(); 471 in_flight_requests_.clear();
457 total_delayable_count_ = 0; 472 total_delayable_count_ = 0;
473 total_critical_count_ = 0;
458 } 474 }
459 475
460 bool IsDelayableRequest(ScheduledResourceRequest* request) { 476 bool IsDelayableRequest(ScheduledResourceRequest* request) {
461 if (request->url_request()->priority() < net::LOW) { 477 if (request->url_request()->priority() < net::LOW) {
462 net::HostPortPair host_port_pair = 478 net::HostPortPair host_port_pair =
463 net::HostPortPair::FromURL(request->url_request()->url()); 479 net::HostPortPair::FromURL(request->url_request()->url());
464 net::HttpServerProperties& http_server_properties = 480 net::HttpServerProperties& http_server_properties =
465 *request->url_request()->context()->http_server_properties(); 481 *request->url_request()->context()->http_server_properties();
466 if (!http_server_properties.SupportsSpdy(host_port_pair)) { 482 if (!http_server_properties.SupportsSpdy(host_port_pair)) {
467 return true; 483 return true;
468 } 484 }
469 } 485 }
470 return false; 486 return false;
471 } 487 }
472 488
473 void SetRequestDelayable(ScheduledResourceRequest* request, 489 void SetRequestDelayable(ScheduledResourceRequest* request,
474 bool delayable) { 490 bool delayable) {
475 if (request->accounted_as_delayable_request() == delayable) 491 if (request->accounted_as_delayable_request() == delayable)
476 return; 492 return;
477 if (delayable) 493 if (delayable)
478 total_delayable_count_++; 494 total_delayable_count_++;
479 else 495 else
480 total_delayable_count_--; 496 total_delayable_count_--;
481 request->set_accounted_as_delayable_request(delayable); 497 request->set_accounted_as_delayable_request(delayable);
482 } 498 }
483 499
500 bool IsCriticalRequest(ScheduledResourceRequest* request) {
501 if (!has_body_ && request->url_request()->priority() >= net::LOW)
502 return true;
503 return false;
504 }
505
506 void SetRequestCritical(ScheduledResourceRequest* request,
507 bool critical) {
508 if (request->critical() == critical)
509 return;
510 if (critical)
511 total_critical_count_++;
512 else
513 total_critical_count_--;
514 request->set_critical(critical);
515 }
516
484 bool ShouldKeepSearching( 517 bool ShouldKeepSearching(
485 const net::HostPortPair& active_request_host) const { 518 const net::HostPortPair& active_request_host) const {
486 size_t same_host_count = 0; 519 size_t same_host_count = 0;
487 for (RequestSet::const_iterator it = in_flight_requests_.begin(); 520 for (RequestSet::const_iterator it = in_flight_requests_.begin();
488 it != in_flight_requests_.end(); ++it) { 521 it != in_flight_requests_.end(); ++it) {
489 net::HostPortPair host_port_pair = 522 net::HostPortPair host_port_pair =
490 net::HostPortPair::FromURL((*it)->url_request()->url()); 523 net::HostPortPair::FromURL((*it)->url_request()->url());
491 if (active_request_host.Equals(host_port_pair)) { 524 if (active_request_host.Equals(host_port_pair)) {
492 same_host_count++; 525 same_host_count++;
493 if (same_host_count >= kMaxNumDelayableRequestsPerHost) 526 if (same_host_count >= kMaxNumDelayableRequestsPerHost)
494 return true; 527 return true;
495 } 528 }
496 } 529 }
497 return false; 530 return false;
498 } 531 }
499 532
500 void StartRequest(ScheduledResourceRequest* request) { 533 void StartRequest(ScheduledResourceRequest* request) {
501 InsertInFlightRequest(request); 534 InsertInFlightRequest(request);
502 request->Start(); 535 request->Start();
503 } 536 }
504 537
505 // ShouldStartRequest is the main scheduling algorithm. 538 // ShouldStartRequest is the main scheduling algorithm.
506 // 539 //
507 // Requests are categorized into three categories: 540 // Requests are categorized into five categories:
508 // 541 //
509 // 1. Non-delayable requests: 542 // 1. Non-delayable requests:
510 // * Synchronous requests. 543 // * Synchronous requests.
511 // * Non-HTTP[S] requests. 544 // * Non-HTTP[S] requests.
512 // 545 //
513 // 2. Requests to SPDY-capable origin servers. 546 // 2. Requests to SPDY-capable origin servers.
514 // 547 //
515 // 3. High-priority requests: 548 // 3. High-priority requests:
516 // * Higher priority requests (>= net::LOW). 549 // * Higher priority requests (>= net::LOW).
517 // 550 //
518 // 4. Low priority requests 551 // 4. Critical requests:
552 // * High-priority requests initiated before the renderer has a <body>.
553 //
554 // 5. Low priority requests
519 // 555 //
520 // The following rules are followed: 556 // The following rules are followed:
521 // 557 //
522 // ACTIVE_AND_LOADING and UNTHROTTLED Clients follow these rules: 558 // ACTIVE_AND_LOADING and UNTHROTTLED Clients follow these rules:
523 // * Non-delayable, High-priority and SDPY capable requests are issued 559 // * Non-delayable, High-priority and SDPY capable requests are issued
524 // immediately 560 // immediately.
525 // * If no high priority requests are in flight, start loading low priority 561 // * If no high priority requests are in flight, start loading low priority
526 // requests. 562 // requests.
527 // * Low priority requests are delayable. 563 // * Low priority requests are delayable.
528 // * Once the renderer has a <body>, start loading delayable requests. 564 // * Allow one delayable request toload at a time while critical requests
565 // are loading.
566 // * Once all critical requests have finished loading, start loading
567 // delayable requests.
529 // * Never exceed 10 delayable requests in flight per client. 568 // * Never exceed 10 delayable requests in flight per client.
530 // * Never exceed 6 delayable requests for a given host. 569 // * Never exceed 6 delayable requests for a given host.
531 // * Prior to <body>, allow one delayable request to load at a time.
532 // 570 //
533 // THROTTLED Clients follow these rules: 571 // THROTTLED Clients follow these rules:
534 // * Non-delayable and SPDY-capable requests are issued immediately. 572 // * Non-delayable and SPDY-capable requests are issued immediately.
535 // * At most one non-SPDY request will be issued per THROTTLED Client 573 // * At most one non-SPDY request will be issued per THROTTLED Client
536 // * If no high priority requests are in flight, start loading low priority 574 // * If no high priority requests are in flight, start loading low priority
537 // requests. 575 // requests.
538 // 576 //
539 // COALESCED Clients never load requests, with the following exceptions: 577 // COALESCED Clients never load requests, with the following exceptions:
540 // * Non-delayable requests are issued imediately. 578 // * Non-delayable requests are issued imediately.
541 // * On a (currently 5 second) heart beat, they load all requests as an 579 // * On a (currently 5 second) heart beat, they load all requests as an
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
595 } 633 }
596 634
597 if (ShouldKeepSearching(host_port_pair)) { 635 if (ShouldKeepSearching(host_port_pair)) {
598 // There may be other requests for other hosts we'd allow, 636 // There may be other requests for other hosts we'd allow,
599 // so keep checking. 637 // so keep checking.
600 return DO_NOT_START_REQUEST_AND_KEEP_SEARCHING; 638 return DO_NOT_START_REQUEST_AND_KEEP_SEARCHING;
601 } 639 }
602 640
603 bool have_immediate_requests_in_flight = 641 bool have_immediate_requests_in_flight =
604 in_flight_requests_.size() > num_delayable_requests_in_flight; 642 in_flight_requests_.size() > num_delayable_requests_in_flight;
605 if (have_immediate_requests_in_flight && !has_body_ && 643 if (have_immediate_requests_in_flight &&
644 total_critical_count_ != 0 &&
606 num_delayable_requests_in_flight != 0) { 645 num_delayable_requests_in_flight != 0) {
607 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING; 646 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING;
608 } 647 }
609 648
610 return START_REQUEST; 649 return START_REQUEST;
611 } 650 }
612 651
613 void LoadAnyStartablePendingRequests() { 652 void LoadAnyStartablePendingRequests() {
614 // We iterate through all the pending requests, starting with the highest 653 // We iterate through all the pending requests, starting with the highest
615 // priority one. For each entry, one of three things can happen: 654 // priority one. For each entry, one of three things can happen:
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
651 bool is_visible_; 690 bool is_visible_;
652 bool is_loaded_; 691 bool is_loaded_;
653 bool is_paused_; 692 bool is_paused_;
654 bool has_body_; 693 bool has_body_;
655 bool using_spdy_proxy_; 694 bool using_spdy_proxy_;
656 RequestQueue pending_requests_; 695 RequestQueue pending_requests_;
657 RequestSet in_flight_requests_; 696 RequestSet in_flight_requests_;
658 ResourceScheduler* scheduler_; 697 ResourceScheduler* scheduler_;
659 // The number of delayable in-flight requests. 698 // The number of delayable in-flight requests.
660 size_t total_delayable_count_; 699 size_t total_delayable_count_;
700 // The number of critical in-flight requests.
701 size_t total_critical_count_;
661 ResourceScheduler::ClientThrottleState throttle_state_; 702 ResourceScheduler::ClientThrottleState throttle_state_;
662 }; 703 };
663 704
664 ResourceScheduler::ResourceScheduler() 705 ResourceScheduler::ResourceScheduler()
665 : should_coalesce_(false), 706 : should_coalesce_(false),
666 should_throttle_(false), 707 should_throttle_(false),
667 active_clients_loading_(0), 708 active_clients_loading_(0),
668 coalesced_clients_(0), 709 coalesced_clients_(0),
669 coalescing_timer_(new base::Timer(true /* retain_user_task */, 710 coalescing_timer_(new base::Timer(true /* retain_user_task */,
670 true /* is_repeating */)) { 711 true /* is_repeating */)) {
(...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after
960 client->ReprioritizeRequest( 1001 client->ReprioritizeRequest(
961 request, old_priority_params, new_priority_params); 1002 request, old_priority_params, new_priority_params);
962 } 1003 }
963 1004
964 ResourceScheduler::ClientId ResourceScheduler::MakeClientId( 1005 ResourceScheduler::ClientId ResourceScheduler::MakeClientId(
965 int child_id, int route_id) { 1006 int child_id, int route_id) {
966 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id; 1007 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id;
967 } 1008 }
968 1009
969 } // namespace content 1010 } // namespace content
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698