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

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: More tests and nits. 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
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 197 matching lines...) Expand 10 before | Expand all | Expand 10 after
232 explicit Client(ResourceScheduler* scheduler) 233 explicit Client(ResourceScheduler* scheduler)
233 : is_audible_(false), 234 : is_audible_(false),
234 is_visible_(false), 235 is_visible_(false),
235 is_loaded_(false), 236 is_loaded_(false),
236 has_body_(false), 237 has_body_(false),
237 using_spdy_proxy_(false), 238 using_spdy_proxy_(false),
238 total_delayable_count_(0), 239 total_delayable_count_(0),
239 throttle_state_(ResourceScheduler::THROTTLED) { 240 throttle_state_(ResourceScheduler::THROTTLED) {
240 scheduler_ = scheduler; 241 scheduler_ = scheduler;
241 } 242 }
242 ~Client() {} 243
244 ~Client() {
245 // Update to default state and pause to ensure the scheduler has a
246 // correct count of important types of clients.
mmenke 2014/07/29 15:43:26 nit: I think "important" is a bit weird here. Ma
aiolos (Not reviewing) 2014/07/29 17:58:51 Done.
247 is_visible_ = false;
248 is_audible_ = false;
249 UpdateThrottleState(true /* should_pause */);
250 }
243 251
244 void ScheduleRequest( 252 void ScheduleRequest(
245 net::URLRequest* url_request, 253 net::URLRequest* url_request,
246 ScheduledResourceRequest* request) { 254 ScheduledResourceRequest* request) {
247 if (ShouldStartRequest(request) == START_REQUEST) { 255 if (ShouldStartRequest(request) == START_REQUEST) {
248 StartRequest(request); 256 StartRequest(request);
249 } else { 257 } else {
250 pending_requests_.Insert(request); 258 pending_requests_.Insert(request);
251 } 259 }
252 } 260 }
(...skipping 23 matching lines...) Expand all
276 284
277 bool is_active() const { return is_visible_ || is_audible_; } 285 bool is_active() const { return is_visible_ || is_audible_; }
278 286
279 bool is_loaded() const { return is_loaded_; } 287 bool is_loaded() const { return is_loaded_; }
280 288
281 void OnAudibilityChanged(bool is_audible) { 289 void OnAudibilityChanged(bool is_audible) {
282 if (is_audible == is_audible_) { 290 if (is_audible == is_audible_) {
283 return; 291 return;
284 } 292 }
285 is_audible_ = is_audible; 293 is_audible_ = is_audible;
286 UpdateThrottleState(); 294 UpdateThrottleState(false /* should_pause */);
287 } 295 }
288 296
289 void OnVisibilityChanged(bool is_visible) { 297 void OnVisibilityChanged(bool is_visible) {
290 if (is_visible == is_visible_) { 298 if (is_visible == is_visible_) {
291 return; 299 return;
292 } 300 }
293 is_visible_ = is_visible; 301 is_visible_ = is_visible;
294 UpdateThrottleState(); 302 UpdateThrottleState(false /* should_pause */);
295 } 303 }
296 304
297 void OnLoadingStateChanged(bool is_loaded) { 305 void OnLoadingStateChanged(bool is_loaded) {
298 if (is_loaded == is_loaded_) { 306 if (is_loaded == is_loaded_) {
299 return; 307 return;
300 } 308 }
301 is_loaded_ = is_loaded; 309 is_loaded_ = is_loaded;
302 UpdateThrottleState(); 310 UpdateThrottleState(false /* should_pause */);
303 } 311 }
304 312
305 void UpdateThrottleState() { 313 void UpdateThrottleState(bool should_pause) {
306 ClientThrottleState old_throttle_state = throttle_state_; 314 ClientThrottleState old_throttle_state = throttle_state_;
307 if (is_active() && !is_loaded_) { 315 if (should_pause) {
316 SetThrottleState(PAUSED);
317 } else if (is_active() && !is_loaded_) {
308 SetThrottleState(ACTIVE_AND_LOADING); 318 SetThrottleState(ACTIVE_AND_LOADING);
309 } else if (is_active()) { 319 } else if (is_active()) {
310 SetThrottleState(UNTHROTTLED); 320 SetThrottleState(UNTHROTTLED);
311 } else if (!scheduler_->active_clients_loaded()) { 321 } else if (!scheduler_->active_clients_loaded()) {
312 SetThrottleState(THROTTLED); 322 SetThrottleState(THROTTLED);
313 } else if (is_loaded_ && scheduler_->should_coalesce()) { 323 } else if (is_loaded_ && scheduler_->should_coalesce()) {
314 SetThrottleState(COALESCED); 324 SetThrottleState(COALESCED);
315 } else if (!is_active()) { 325 } else if (!is_active()) {
316 SetThrottleState(UNTHROTTLED); 326 SetThrottleState(UNTHROTTLED);
317 } 327 }
328
318 if (throttle_state_ == old_throttle_state) { 329 if (throttle_state_ == old_throttle_state) {
319 return; 330 return;
320 } 331 }
321 if (throttle_state_ == ACTIVE_AND_LOADING) { 332 if (throttle_state_ == ACTIVE_AND_LOADING) {
322 scheduler_->IncrementActiveClientsLoading(); 333 scheduler_->IncrementActiveClientsLoading();
323 } else if (old_throttle_state == ACTIVE_AND_LOADING) { 334 } else if (old_throttle_state == ACTIVE_AND_LOADING) {
324 scheduler_->DecrementActiveClientsLoading(); 335 scheduler_->DecrementActiveClientsLoading();
325 } 336 }
337 if (throttle_state_ == COALESCED) {
338 scheduler_->IncrementCoalescedClients();
339 } else if (old_throttle_state == COALESCED) {
340 scheduler_->DecrementCoalescedClients();
341 }
326 } 342 }
327 343
328 void OnNavigate() { 344 void OnNavigate() {
329 has_body_ = false; 345 has_body_ = false;
330 is_loaded_ = false; 346 is_loaded_ = false;
331 } 347 }
332 348
333 void OnWillInsertBody() { 349 void OnWillInsertBody() {
334 has_body_ = true; 350 has_body_ = true;
335 LoadAnyStartablePendingRequests(); 351 LoadAnyStartablePendingRequests();
(...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after
627 bool has_body_; 643 bool has_body_;
628 bool using_spdy_proxy_; 644 bool using_spdy_proxy_;
629 RequestQueue pending_requests_; 645 RequestQueue pending_requests_;
630 RequestSet in_flight_requests_; 646 RequestSet in_flight_requests_;
631 ResourceScheduler* scheduler_; 647 ResourceScheduler* scheduler_;
632 // The number of delayable in-flight requests. 648 // The number of delayable in-flight requests.
633 size_t total_delayable_count_; 649 size_t total_delayable_count_;
634 ResourceScheduler::ClientThrottleState throttle_state_; 650 ResourceScheduler::ClientThrottleState throttle_state_;
635 }; 651 };
636 652
637 ResourceScheduler::ResourceScheduler(): should_coalesce_(false), 653 ResourceScheduler::ResourceScheduler()
638 should_throttle_(false), 654 : should_coalesce_(false),
639 active_clients_loading_(0) { 655 should_throttle_(false),
656 active_clients_loading_(0),
657 coalesced_clients_(0),
658 coalescing_timer_(new base::Timer(true /* retain_user_task */,
659 true /* is_repeating */)) {
640 } 660 }
641 661
642 ResourceScheduler::~ResourceScheduler() { 662 ResourceScheduler::~ResourceScheduler() {
643 DCHECK(unowned_requests_.empty()); 663 DCHECK(unowned_requests_.empty());
644 DCHECK(client_map_.empty()); 664 DCHECK(client_map_.empty());
645 } 665 }
646 666
647 void ResourceScheduler::SetThrottleOptionsForTesting(bool should_throttle, 667 void ResourceScheduler::SetThrottleOptionsForTesting(bool should_throttle,
648 bool should_coalesce) { 668 bool should_coalesce) {
649 should_coalesce_ = should_coalesce; 669 should_coalesce_ = should_coalesce;
650 should_throttle_ = should_throttle; 670 should_throttle_ = should_throttle;
651 OnLoadingActiveClientsStateChanged(); 671 OnLoadingActiveClientsStateChangedForAllClients();
652 } 672 }
653 673
654 ResourceScheduler::ClientThrottleState 674 ResourceScheduler::ClientThrottleState
655 ResourceScheduler::GetClientStateForTesting(int child_id, int route_id) { 675 ResourceScheduler::GetClientStateForTesting(int child_id, int route_id) {
656 Client* client = GetClient(child_id, route_id); 676 Client* client = GetClient(child_id, route_id);
657 DCHECK(client); 677 DCHECK(client);
658 return client->throttle_state(); 678 return client->throttle_state();
659 } 679 }
660 680
661 scoped_ptr<ResourceThrottle> ResourceScheduler::ScheduleRequest( 681 scoped_ptr<ResourceThrottle> ResourceScheduler::ScheduleRequest(
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
703 void ResourceScheduler::OnClientCreated(int child_id, int route_id) { 723 void ResourceScheduler::OnClientCreated(int child_id, int route_id) {
704 DCHECK(CalledOnValidThread()); 724 DCHECK(CalledOnValidThread());
705 ClientId client_id = MakeClientId(child_id, route_id); 725 ClientId client_id = MakeClientId(child_id, route_id);
706 DCHECK(!ContainsKey(client_map_, client_id)); 726 DCHECK(!ContainsKey(client_map_, client_id));
707 727
708 Client* client = new Client(this); 728 Client* client = new Client(this);
709 client_map_[client_id] = client; 729 client_map_[client_id] = client;
710 730
711 // TODO(aiolos): set Client visibility/audibility when signals are added 731 // TODO(aiolos): set Client visibility/audibility when signals are added
712 // this will UNTHROTTLE Clients as needed 732 // this will UNTHROTTLE Clients as needed
713 client->UpdateThrottleState(); 733 client->UpdateThrottleState(false /* should_paused */);
714 } 734 }
715 735
716 void ResourceScheduler::OnClientDeleted(int child_id, int route_id) { 736 void ResourceScheduler::OnClientDeleted(int child_id, int route_id) {
717 DCHECK(CalledOnValidThread()); 737 DCHECK(CalledOnValidThread());
718 ClientId client_id = MakeClientId(child_id, route_id); 738 ClientId client_id = MakeClientId(child_id, route_id);
719 DCHECK(ContainsKey(client_map_, client_id)); 739 DCHECK(ContainsKey(client_map_, client_id));
720 ClientMap::iterator it = client_map_.find(client_id); 740 ClientMap::iterator it = client_map_.find(client_id);
721 if (it == client_map_.end()) 741 if (it == client_map_.end())
722 return; 742 return;
723 743
724 Client* client = it->second; 744 Client* client = it->second;
725 client->OnLoadingStateChanged(true);
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 }
734 753
735 delete client; 754 delete client;
(...skipping 75 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(false /* should_pause */);
mmenke 2014/07/29 15:43:26 This unpauses all clients. While not yet a bug, i
aiolos (Not reviewing) 2014/07/29 17:58:51 Done.
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());
mmenke 2014/07/29 15:43:26 DCHECK(should_coalesce_), maybe? Could also put t
aiolos (Not reviewing) 2014/07/29 17:58:51 Done.
877 if (coalesced_clients_ == 1) {
878 coalescing_timer_->Start(
879 FROM_HERE,
880 base::TimeDelta::FromMilliseconds(kCoalescedTimerPeriod),
881 base::Bind(&ResourceScheduler::LoadCoalescedRequests,
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::LoadCoalescedRequests() {
909 ClientMap::iterator client_it = client_map_.begin();
910 while (client_it != client_map_.end()) {
911 Client* client = client_it->second;
912 client->LoadCoalescedRequests();
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