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

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

Issue 393163003: Add coalescing timer to ResourceScheduler. CL 2 from BUG=128035. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@rsblank
Patch Set: Review changes Created 6 years, 5 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 <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"
11 #include "content/browser/loader/resource_message_delegate.h" 11 #include "content/browser/loader/resource_message_delegate.h"
12 #include "content/public/browser/resource_controller.h" 12 #include "content/public/browser/resource_controller.h"
13 #include "content/public/browser/resource_request_info.h" 13 #include "content/public/browser/resource_request_info.h"
14 #include "content/public/browser/resource_throttle.h" 14 #include "content/public/browser/resource_throttle.h"
15 #include "ipc/ipc_message_macros.h" 15 #include "ipc/ipc_message_macros.h"
16 #include "net/base/host_port_pair.h" 16 #include "net/base/host_port_pair.h"
17 #include "net/base/load_flags.h" 17 #include "net/base/load_flags.h"
18 #include "net/base/request_priority.h" 18 #include "net/base/request_priority.h"
19 #include "net/http/http_server_properties.h" 19 #include "net/http/http_server_properties.h"
20 #include "net/url_request/url_request.h" 20 #include "net/url_request/url_request.h"
21 #include "net/url_request/url_request_context.h" 21 #include "net/url_request/url_request_context.h"
22 22
23 namespace content { 23 namespace content {
24 24
25 static const size_t kCoalescedTimerPeriod = 5000;
25 static const size_t kMaxNumDelayableRequestsPerClient = 10; 26 static const size_t kMaxNumDelayableRequestsPerClient = 10;
26 static const size_t kMaxNumDelayableRequestsPerHost = 6; 27 static const size_t kMaxNumDelayableRequestsPerHost = 6;
27 static const size_t kMaxNumThrottledRequestsPerClient = 1; 28 static const size_t kMaxNumThrottledRequestsPerClient = 1;
28 29
29 struct ResourceScheduler::RequestPriorityParams { 30 struct ResourceScheduler::RequestPriorityParams {
30 RequestPriorityParams() 31 RequestPriorityParams()
31 : priority(net::DEFAULT_PRIORITY), 32 : priority(net::DEFAULT_PRIORITY),
32 intra_priority(0) { 33 intra_priority(0) {
33 } 34 }
34 35
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after
271 (*it)->set_accounted_as_delayable_request(false); 272 (*it)->set_accounted_as_delayable_request(false);
272 } 273 }
273 ClearInFlightRequests(); 274 ClearInFlightRequests();
274 return unowned_requests; 275 return unowned_requests;
275 } 276 }
276 277
277 bool is_active() const { return is_visible_ || is_audible_; } 278 bool is_active() const { return is_visible_ || is_audible_; }
278 279
279 bool is_loaded() const { return is_loaded_; } 280 bool is_loaded() const { return is_loaded_; }
280 281
282 // Reset state to default values for client deletion.
mmenke 2014/07/25 16:33:27 Should mention this must be called prior to deleti
283 void ResetState() {
mmenke 2014/07/25 16:33:27 Why can't you just do this on destruction? I seem
aiolos (Not reviewing) 2014/07/25 16:54:50 Good point.
284 is_visible_ = false;
285 is_audible_ = false;
286 is_loaded_ = false;
287 UpdateThrottleState();
mmenke 2014/07/25 16:33:27 This strikes me as regression-prone logic. We're
aiolos (Not reviewing) 2014/07/25 16:54:50 I'd considered doing that. I was planning on addin
mmenke 2014/07/25 17:02:41 If we just use it for shutdown for now, and then m
aiolos (Not reviewing) 2014/07/25 17:12:58 Agreed. Although shouldn't sync requests get issue
mmenke 2014/07/25 17:22:19 Good point - a test for that definitely makes sens
288 }
289
281 void OnAudibilityChanged(bool is_audible) { 290 void OnAudibilityChanged(bool is_audible) {
282 if (is_audible == is_audible_) { 291 if (is_audible == is_audible_) {
283 return; 292 return;
284 } 293 }
285 is_audible_ = is_audible; 294 is_audible_ = is_audible;
286 UpdateThrottleState(); 295 UpdateThrottleState();
287 } 296 }
288 297
289 void OnVisibilityChanged(bool is_visible) { 298 void OnVisibilityChanged(bool is_visible) {
290 if (is_visible == is_visible_) { 299 if (is_visible == is_visible_) {
(...skipping 17 matching lines...) Expand all
308 SetThrottleState(ACTIVE_AND_LOADING); 317 SetThrottleState(ACTIVE_AND_LOADING);
309 } else if (is_active()) { 318 } else if (is_active()) {
310 SetThrottleState(UNTHROTTLED); 319 SetThrottleState(UNTHROTTLED);
311 } else if (!scheduler_->active_clients_loaded()) { 320 } else if (!scheduler_->active_clients_loaded()) {
312 SetThrottleState(THROTTLED); 321 SetThrottleState(THROTTLED);
313 } else if (is_loaded_ && scheduler_->should_coalesce()) { 322 } else if (is_loaded_ && scheduler_->should_coalesce()) {
314 SetThrottleState(COALESCED); 323 SetThrottleState(COALESCED);
315 } else if (!is_active()) { 324 } else if (!is_active()) {
316 SetThrottleState(UNTHROTTLED); 325 SetThrottleState(UNTHROTTLED);
317 } 326 }
327
318 if (throttle_state_ == old_throttle_state) { 328 if (throttle_state_ == old_throttle_state) {
319 return; 329 return;
320 } 330 }
321 if (throttle_state_ == ACTIVE_AND_LOADING) { 331 if (throttle_state_ == ACTIVE_AND_LOADING) {
322 scheduler_->IncrementActiveClientsLoading(); 332 scheduler_->IncrementActiveClientsLoading();
323 } else if (old_throttle_state == ACTIVE_AND_LOADING) { 333 } else if (old_throttle_state == ACTIVE_AND_LOADING) {
324 scheduler_->DecrementActiveClientsLoading(); 334 scheduler_->DecrementActiveClientsLoading();
325 } 335 }
336 if (throttle_state_ == COALESCED) {
337 scheduler_->IncrementCoalescedClients();
338 } else if (old_throttle_state == COALESCED) {
339 scheduler_->DecrementCoalescedClients();
340 }
326 } 341 }
327 342
328 void OnNavigate() { 343 void OnNavigate() {
329 has_body_ = false; 344 has_body_ = false;
330 is_loaded_ = false; 345 is_loaded_ = false;
331 } 346 }
332 347
333 void OnWillInsertBody() { 348 void OnWillInsertBody() {
334 has_body_ = true; 349 has_body_ = true;
335 LoadAnyStartablePendingRequests(); 350 LoadAnyStartablePendingRequests();
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
386 throttle_state_ = throttle_state; 401 throttle_state_ = throttle_state;
387 LoadAnyStartablePendingRequests(); 402 LoadAnyStartablePendingRequests();
388 // TODO(aiolos): Stop any started but not inflght requests when 403 // TODO(aiolos): Stop any started but not inflght requests when
389 // switching to stricter throttle state? 404 // switching to stricter throttle state?
390 } 405 }
391 406
392 ResourceScheduler::ClientThrottleState throttle_state() const { 407 ResourceScheduler::ClientThrottleState throttle_state() const {
393 return throttle_state_; 408 return throttle_state_;
394 } 409 }
395 410
396 void LoadCoalescedRequests() { 411 void LoadRequestsForAllCoalescedClients() {
mmenke 2014/07/25 16:33:27 Undo this rename.
397 if (throttle_state_ != COALESCED) { 412 if (throttle_state_ != COALESCED) {
398 return; 413 return;
399 } 414 }
400 if (scheduler_->active_clients_loaded()) { 415 if (scheduler_->active_clients_loaded()) {
401 SetThrottleState(UNTHROTTLED); 416 SetThrottleState(UNTHROTTLED);
402 } else { 417 } else {
403 SetThrottleState(THROTTLED); 418 SetThrottleState(THROTTLED);
404 } 419 }
405 LoadAnyStartablePendingRequests(); 420 LoadAnyStartablePendingRequests();
406 SetThrottleState(COALESCED); 421 SetThrottleState(COALESCED);
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after
627 bool has_body_; 642 bool has_body_;
628 bool using_spdy_proxy_; 643 bool using_spdy_proxy_;
629 RequestQueue pending_requests_; 644 RequestQueue pending_requests_;
630 RequestSet in_flight_requests_; 645 RequestSet in_flight_requests_;
631 ResourceScheduler* scheduler_; 646 ResourceScheduler* scheduler_;
632 // The number of delayable in-flight requests. 647 // The number of delayable in-flight requests.
633 size_t total_delayable_count_; 648 size_t total_delayable_count_;
634 ResourceScheduler::ClientThrottleState throttle_state_; 649 ResourceScheduler::ClientThrottleState throttle_state_;
635 }; 650 };
636 651
637 ResourceScheduler::ResourceScheduler(): should_coalesce_(false), 652 ResourceScheduler::ResourceScheduler()
638 should_throttle_(false), 653 : should_coalesce_(false),
639 active_clients_loading_(0) { 654 should_throttle_(false),
655 active_clients_loading_(0),
656 coalesced_clients_(0),
657 coalescing_timer_(new base::Timer(true /* retain_user_task */,
658 true /* is_repeating */)) {
640 } 659 }
641 660
642 ResourceScheduler::~ResourceScheduler() { 661 ResourceScheduler::~ResourceScheduler() {
643 DCHECK(unowned_requests_.empty()); 662 DCHECK(unowned_requests_.empty());
644 DCHECK(client_map_.empty()); 663 DCHECK(client_map_.empty());
645 } 664 }
646 665
647 void ResourceScheduler::SetThrottleOptionsForTesting(bool should_throttle, 666 void ResourceScheduler::SetThrottleOptionsForTesting(bool should_throttle,
648 bool should_coalesce) { 667 bool should_coalesce) {
649 should_coalesce_ = should_coalesce; 668 should_coalesce_ = should_coalesce;
650 should_throttle_ = should_throttle; 669 should_throttle_ = should_throttle;
651 OnLoadingActiveClientsStateChanged(); 670 OnLoadingActiveClientsStateChangedForAllClients();
652 } 671 }
653 672
654 ResourceScheduler::ClientThrottleState 673 ResourceScheduler::ClientThrottleState
655 ResourceScheduler::GetClientStateForTesting(int child_id, int route_id) { 674 ResourceScheduler::GetClientStateForTesting(int child_id, int route_id) {
656 Client* client = GetClient(child_id, route_id); 675 Client* client = GetClient(child_id, route_id);
657 DCHECK(client); 676 DCHECK(client);
658 return client->throttle_state(); 677 return client->throttle_state();
659 } 678 }
660 679
661 scoped_ptr<ResourceThrottle> ResourceScheduler::ScheduleRequest( 680 scoped_ptr<ResourceThrottle> ResourceScheduler::ScheduleRequest(
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
715 734
716 void ResourceScheduler::OnClientDeleted(int child_id, int route_id) { 735 void ResourceScheduler::OnClientDeleted(int child_id, int route_id) {
717 DCHECK(CalledOnValidThread()); 736 DCHECK(CalledOnValidThread());
718 ClientId client_id = MakeClientId(child_id, route_id); 737 ClientId client_id = MakeClientId(child_id, route_id);
719 DCHECK(ContainsKey(client_map_, client_id)); 738 DCHECK(ContainsKey(client_map_, client_id));
720 ClientMap::iterator it = client_map_.find(client_id); 739 ClientMap::iterator it = client_map_.find(client_id);
721 if (it == client_map_.end()) 740 if (it == client_map_.end())
722 return; 741 return;
723 742
724 Client* client = it->second; 743 Client* client = it->second;
725 client->OnLoadingStateChanged(true); 744 client->ResetState();
726 // FYI, ResourceDispatcherHost cancels all of the requests after this function 745 // FYI, ResourceDispatcherHost cancels all of the requests after this function
727 // is called. It should end up canceling all of the requests except for a 746 // is called. It should end up canceling all of the requests except for a
728 // cross-renderer navigation. 747 // cross-renderer navigation.
729 RequestSet client_unowned_requests = client->RemoveAllRequests(); 748 RequestSet client_unowned_requests = client->RemoveAllRequests();
730 for (RequestSet::iterator it = client_unowned_requests.begin(); 749 for (RequestSet::iterator it = client_unowned_requests.begin();
731 it != client_unowned_requests.end(); ++it) { 750 it != client_unowned_requests.end(); ++it) {
732 unowned_requests_.insert(*it); 751 unowned_requests_.insert(*it);
733 } 752 }
mmenke 2014/07/25 16:33:27 Should this be done before changing the state?
734 753
735 delete client; 754 delete client;
736 client_map_.erase(it); 755 client_map_.erase(it);
737 } 756 }
738 757
739 void ResourceScheduler::OnNavigate(int child_id, int route_id) { 758 void ResourceScheduler::OnNavigate(int child_id, int route_id) {
740 DCHECK(CalledOnValidThread()); 759 DCHECK(CalledOnValidThread());
741 ClientId client_id = MakeClientId(child_id, route_id); 760 ClientId client_id = MakeClientId(child_id, route_id);
742 761
743 ClientMap::iterator it = client_map_.find(client_id); 762 ClientMap::iterator it = client_map_.find(client_id);
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
811 return NULL; 830 return NULL;
812 } 831 }
813 return client_it->second; 832 return client_it->second;
814 } 833 }
815 834
816 void ResourceScheduler::DecrementActiveClientsLoading() { 835 void ResourceScheduler::DecrementActiveClientsLoading() {
817 DCHECK_NE(0u, active_clients_loading_); 836 DCHECK_NE(0u, active_clients_loading_);
818 --active_clients_loading_; 837 --active_clients_loading_;
819 DCHECK_EQ(active_clients_loading_, CountActiveClientsLoading()); 838 DCHECK_EQ(active_clients_loading_, CountActiveClientsLoading());
820 if (active_clients_loading_ == 0) { 839 if (active_clients_loading_ == 0) {
821 OnLoadingActiveClientsStateChanged(); 840 OnLoadingActiveClientsStateChangedForAllClients();
822 } 841 }
823 } 842 }
824 843
825 void ResourceScheduler::IncrementActiveClientsLoading() { 844 void ResourceScheduler::IncrementActiveClientsLoading() {
826 ++active_clients_loading_; 845 ++active_clients_loading_;
827 DCHECK_EQ(active_clients_loading_, CountActiveClientsLoading()); 846 DCHECK_EQ(active_clients_loading_, CountActiveClientsLoading());
828 if (active_clients_loading_ == 1) { 847 if (active_clients_loading_ == 1) {
829 OnLoadingActiveClientsStateChanged(); 848 OnLoadingActiveClientsStateChangedForAllClients();
830 } 849 }
831 } 850 }
832 851
833 void ResourceScheduler::OnLoadingActiveClientsStateChanged() { 852 void ResourceScheduler::OnLoadingActiveClientsStateChangedForAllClients() {
834 ClientMap::iterator client_it = client_map_.begin(); 853 ClientMap::iterator client_it = client_map_.begin();
835 while (client_it != client_map_.end()) { 854 while (client_it != client_map_.end()) {
836 Client* client = client_it->second; 855 Client* client = client_it->second;
837 client->UpdateThrottleState(); 856 client->UpdateThrottleState();
838 ++client_it; 857 ++client_it;
839 } 858 }
840 } 859 }
841 860
842 size_t ResourceScheduler::CountActiveClientsLoading() { 861 size_t ResourceScheduler::CountActiveClientsLoading() const {
843 size_t active_and_loading = 0; 862 size_t active_and_loading = 0;
844 ClientMap::iterator client_it = client_map_.begin(); 863 ClientMap::const_iterator client_it = client_map_.begin();
845 while (client_it != client_map_.end()) { 864 while (client_it != client_map_.end()) {
846 Client* client = client_it->second; 865 Client* client = client_it->second;
847 if (client->throttle_state() == ACTIVE_AND_LOADING) { 866 if (client->throttle_state() == ACTIVE_AND_LOADING) {
848 ++active_and_loading; 867 ++active_and_loading;
849 } 868 }
850 ++client_it; 869 ++client_it;
851 } 870 }
852 return active_and_loading; 871 return active_and_loading;
853 } 872 }
854 873
874 void ResourceScheduler::IncrementCoalescedClients() {
875 ++coalesced_clients_;
876 DCHECK_EQ(coalesced_clients_, CountCoalescedClients());
877 if (coalesced_clients_ == 1) {
878 coalescing_timer_->Start(
879 FROM_HERE,
880 base::TimeDelta::FromMilliseconds(kCoalescedTimerPeriod),
881 base::Bind(&ResourceScheduler::LoadRequestsForAllCoalescedClients,
882 base::Unretained(this)));
883 }
884 }
885
886 void ResourceScheduler::DecrementCoalescedClients() {
887 DCHECK_NE(0U, coalesced_clients_);
888 --coalesced_clients_;
889 DCHECK_EQ(coalesced_clients_, CountCoalescedClients());
890 if (coalesced_clients_ == 0) {
891 coalescing_timer_->Stop();
892 }
893 }
894
895 size_t ResourceScheduler::CountCoalescedClients() const {
896 size_t coalesced_clients = 0;
897 ClientMap::const_iterator client_it = client_map_.begin();
898 while (client_it != client_map_.end()) {
899 Client* client = client_it->second;
900 if (client->throttle_state() == COALESCED) {
901 ++coalesced_clients;
902 }
903 ++client_it;
904 }
905 return coalesced_clients_;
906 }
907
908 void ResourceScheduler::LoadRequestsForAllCoalescedClients() {
909 ClientMap::iterator client_it = client_map_.begin();
910 while (client_it != client_map_.end()) {
911 Client* client = client_it->second;
912 client->LoadRequestsForAllCoalescedClients();
913 ++client_it;
914 }
915 }
916
855 void ResourceScheduler::ReprioritizeRequest(ScheduledResourceRequest* request, 917 void ResourceScheduler::ReprioritizeRequest(ScheduledResourceRequest* request,
856 net::RequestPriority new_priority, 918 net::RequestPriority new_priority,
857 int new_intra_priority_value) { 919 int new_intra_priority_value) {
858 if (request->url_request()->load_flags() & net::LOAD_IGNORE_LIMITS) { 920 if (request->url_request()->load_flags() & net::LOAD_IGNORE_LIMITS) {
859 // We should not be re-prioritizing requests with the 921 // We should not be re-prioritizing requests with the
860 // IGNORE_LIMITS flag. 922 // IGNORE_LIMITS flag.
861 NOTREACHED(); 923 NOTREACHED();
862 return; 924 return;
863 } 925 }
864 RequestPriorityParams new_priority_params(new_priority, 926 RequestPriorityParams new_priority_params(new_priority,
(...skipping 18 matching lines...) Expand all
883 client->ReprioritizeRequest( 945 client->ReprioritizeRequest(
884 request, old_priority_params, new_priority_params); 946 request, old_priority_params, new_priority_params);
885 } 947 }
886 948
887 ResourceScheduler::ClientId ResourceScheduler::MakeClientId( 949 ResourceScheduler::ClientId ResourceScheduler::MakeClientId(
888 int child_id, int route_id) { 950 int child_id, int route_id) {
889 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id; 951 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id;
890 } 952 }
891 953
892 } // namespace content 954 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698