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

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

Issue 2670843007: Get rid of quadratic behavior in ResourceScheduler (Closed)
Patch Set: properly initialize members, more comment 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 unified diff | Download patch
« 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 "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>
(...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after
347 347
348 // Each client represents a tab. 348 // Each client represents a tab.
349 class ResourceScheduler::Client { 349 class ResourceScheduler::Client {
350 public: 350 public:
351 explicit Client(bool priority_requests_delayable) 351 explicit Client(bool priority_requests_delayable)
352 : is_loaded_(false), 352 : is_loaded_(false),
353 has_html_body_(false), 353 has_html_body_(false),
354 using_spdy_proxy_(false), 354 using_spdy_proxy_(false),
355 in_flight_delayable_count_(0), 355 in_flight_delayable_count_(0),
356 total_layout_blocking_count_(0), 356 total_layout_blocking_count_(0),
357 priority_requests_delayable_(priority_requests_delayable) {} 357 priority_requests_delayable_(priority_requests_delayable),
358 has_pending_start_task_(false),
359 weak_ptr_factory_(this) {}
358 360
359 ~Client() {} 361 ~Client() {}
360 362
361 void ScheduleRequest(net::URLRequest* url_request, 363 void ScheduleRequest(net::URLRequest* url_request,
362 ScheduledResourceRequest* request) { 364 ScheduledResourceRequest* request) {
363 SetRequestAttributes(request, DetermineRequestAttributes(request)); 365 SetRequestAttributes(request, DetermineRequestAttributes(request));
364 if (ShouldStartRequest(request) == START_REQUEST) { 366 if (ShouldStartRequest(request) == START_REQUEST) {
365 // New requests can be started synchronously without issue. 367 // New requests can be started synchronously without issue.
366 StartRequest(request, START_SYNC, RequestStartTrigger::NONE); 368 StartRequest(request, START_SYNC, RequestStartTrigger::NONE);
367 } else { 369 } else {
368 pending_requests_.Insert(request); 370 pending_requests_.Insert(request);
369 } 371 }
370 } 372 }
371 373
372 void RemoveRequest(ScheduledResourceRequest* request) { 374 void RemoveRequest(ScheduledResourceRequest* request) {
373 if (pending_requests_.IsQueued(request)) { 375 if (pending_requests_.IsQueued(request)) {
374 pending_requests_.Erase(request); 376 pending_requests_.Erase(request);
375 DCHECK(!base::ContainsKey(in_flight_requests_, request)); 377 DCHECK(!base::ContainsKey(in_flight_requests_, request));
376 } else { 378 } else {
377 EraseInFlightRequest(request); 379 EraseInFlightRequest(request);
378 380
379 // Removing this request may have freed up another to load. 381 // Removing this request may have freed up another to load.
380 LoadAnyStartablePendingRequests( 382 ScheduleLoadAnyStartablePendingRequests(
381 has_html_body_ 383 has_html_body_ ? RequestStartTrigger::COMPLETION_POST_BODY
382 ? RequestStartTrigger::COMPLETION_POST_BODY 384 : RequestStartTrigger::COMPLETION_PRE_BODY);
383 : RequestStartTrigger::COMPLETION_PRE_BODY);
384 } 385 }
385 } 386 }
386 387
387 RequestSet StartAndRemoveAllRequests() { 388 RequestSet StartAndRemoveAllRequests() {
388 // First start any pending requests so that they will be moved into 389 // First start any pending requests so that they will be moved into
389 // in_flight_requests_. This may exceed the limits 390 // in_flight_requests_. This may exceed the limits
390 // kDefaultMaxNumDelayableRequestsPerClient and 391 // kDefaultMaxNumDelayableRequestsPerClient and
391 // kMaxNumDelayableRequestsPerHostPerClient, so this method must not do 392 // kMaxNumDelayableRequestsPerHostPerClient, so this method must not do
392 // anything that depends on those limits before calling 393 // anything that depends on those limits before calling
393 // ClearInFlightRequests() below. 394 // ClearInFlightRequests() below.
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
446 DCHECK(base::ContainsKey(in_flight_requests_, request)); 447 DCHECK(base::ContainsKey(in_flight_requests_, request));
447 // Request has already started. 448 // Request has already started.
448 return; 449 return;
449 } 450 }
450 451
451 pending_requests_.Erase(request); 452 pending_requests_.Erase(request);
452 pending_requests_.Insert(request); 453 pending_requests_.Insert(request);
453 454
454 if (new_priority_params.priority > old_priority_params.priority) { 455 if (new_priority_params.priority > old_priority_params.priority) {
455 // Check if this request is now able to load at its new priority. 456 // Check if this request is now able to load at its new priority.
456 LoadAnyStartablePendingRequests( 457 ScheduleLoadAnyStartablePendingRequests(
457 RequestStartTrigger::REQUEST_REPRIORITIZED); 458 RequestStartTrigger::REQUEST_REPRIORITIZED);
458 } 459 }
459 } 460 }
460 461
461 private: 462 private:
462 enum ShouldStartReqResult { 463 enum ShouldStartReqResult {
463 DO_NOT_START_REQUEST_AND_STOP_SEARCHING, 464 DO_NOT_START_REQUEST_AND_STOP_SEARCHING,
464 DO_NOT_START_REQUEST_AND_KEEP_SEARCHING, 465 DO_NOT_START_REQUEST_AND_KEEP_SEARCHING,
465 START_REQUEST, 466 START_REQUEST,
466 }; 467 };
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after
712 // Block the request if at least one request is in flight and the 713 // Block the request if at least one request is in flight and the
713 // number of in-flight delayable requests has hit the configured 714 // number of in-flight delayable requests has hit the configured
714 // limit. 715 // limit.
715 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING; 716 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING;
716 } 717 }
717 } 718 }
718 719
719 return START_REQUEST; 720 return START_REQUEST;
720 } 721 }
721 722
723 // It is common for a burst of messages to come from the renderer which
724 // trigger starting pending requests. Naively, this would result in O(n*m)
725 // behavior for n pending requests and m <= n messages, as
726 // LoadAnyStartablePendingRequest is O(n) for n pending requests. To solve
727 // this, just post a task to the end of the queue to call the method,
728 // coalescing the m messages into a single call to
729 // LoadAnyStartablePendingRequests.
730 // TODO(csharrison): Reconsider this if IPC batching becomes an easy to use
731 // pattern.
732 void ScheduleLoadAnyStartablePendingRequests(RequestStartTrigger trigger) {
733 if (has_pending_start_task_)
734 return;
735 has_pending_start_task_ = true;
736 base::ThreadTaskRunnerHandle::Get()->PostTask(
737 FROM_HERE, base::Bind(&Client::LoadAnyStartablePendingRequests,
738 weak_ptr_factory_.GetWeakPtr(), trigger));
kinuko 2017/02/06 20:57:14 This changes when we actually triggers startable r
Charlie Harrison 2017/02/06 21:24:29 This is a valid concern. We currently "schedule" t
739 }
740
722 void LoadAnyStartablePendingRequests(RequestStartTrigger trigger) { 741 void LoadAnyStartablePendingRequests(RequestStartTrigger trigger) {
723 // We iterate through all the pending requests, starting with the highest 742 // We iterate through all the pending requests, starting with the highest
724 // priority one. For each entry, one of three things can happen: 743 // priority one. For each entry, one of three things can happen:
725 // 1) We start the request, remove it from the list, and keep checking. 744 // 1) We start the request, remove it from the list, and keep checking.
726 // 2) We do NOT start the request, but ShouldStartRequest() signals us that 745 // 2) We do NOT start the request, but ShouldStartRequest() signals us that
727 // there may be room for other requests, so we keep checking and leave 746 // there may be room for other requests, so we keep checking and leave
728 // the previous request still in the list. 747 // the previous request still in the list.
729 // 3) We do not start the request, same as above, but StartRequest() tells 748 // 3) We do not start the request, same as above, but StartRequest() tells
730 // us there's no point in checking any further requests. 749 // us there's no point in checking any further requests.
750 has_pending_start_task_ = false;
731 RequestQueue::NetQueue::iterator request_iter = 751 RequestQueue::NetQueue::iterator request_iter =
732 pending_requests_.GetNextHighestIterator(); 752 pending_requests_.GetNextHighestIterator();
733 753
734 while (request_iter != pending_requests_.End()) { 754 while (request_iter != pending_requests_.End()) {
735 ScheduledResourceRequest* request = *request_iter; 755 ScheduledResourceRequest* request = *request_iter;
736 ShouldStartReqResult query_result = ShouldStartRequest(request); 756 ShouldStartReqResult query_result = ShouldStartRequest(request);
737 757
738 if (query_result == START_REQUEST) { 758 if (query_result == START_REQUEST) {
739 pending_requests_.Erase(request); 759 pending_requests_.Erase(request);
740 StartRequest(request, START_ASYNC, trigger); 760 StartRequest(request, START_ASYNC, trigger);
(...skipping 23 matching lines...) Expand all
764 RequestQueue pending_requests_; 784 RequestQueue pending_requests_;
765 RequestSet in_flight_requests_; 785 RequestSet in_flight_requests_;
766 // The number of delayable in-flight requests. 786 // The number of delayable in-flight requests.
767 size_t in_flight_delayable_count_; 787 size_t in_flight_delayable_count_;
768 // The number of layout-blocking in-flight requests. 788 // The number of layout-blocking in-flight requests.
769 size_t total_layout_blocking_count_; 789 size_t total_layout_blocking_count_;
770 790
771 // True if requests to servers that support priorities (e.g., H2/QUIC) can 791 // True if requests to servers that support priorities (e.g., H2/QUIC) can
772 // be delayed. 792 // be delayed.
773 bool priority_requests_delayable_; 793 bool priority_requests_delayable_;
794
795 bool has_pending_start_task_;
796
797 base::WeakPtrFactory<ResourceScheduler::Client> weak_ptr_factory_;
774 }; 798 };
775 799
776 ResourceScheduler::ResourceScheduler() 800 ResourceScheduler::ResourceScheduler()
777 : priority_requests_delayable_( 801 : priority_requests_delayable_(
778 base::FeatureList::IsEnabled(kPrioritySupportedRequestsDelayable)) {} 802 base::FeatureList::IsEnabled(kPrioritySupportedRequestsDelayable)) {}
779 803
780 ResourceScheduler::~ResourceScheduler() { 804 ResourceScheduler::~ResourceScheduler() {
781 DCHECK(unowned_requests_.empty()); 805 DCHECK(unowned_requests_.empty());
782 DCHECK(client_map_.empty()); 806 DCHECK(client_map_.empty());
783 } 807 }
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after
964 client->ReprioritizeRequest(scheduled_resource_request, old_priority_params, 988 client->ReprioritizeRequest(scheduled_resource_request, old_priority_params,
965 new_priority_params); 989 new_priority_params);
966 } 990 }
967 991
968 ResourceScheduler::ClientId ResourceScheduler::MakeClientId( 992 ResourceScheduler::ClientId ResourceScheduler::MakeClientId(
969 int child_id, int route_id) { 993 int child_id, int route_id) {
970 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id; 994 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id;
971 } 995 }
972 996
973 } // namespace content 997 } // 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