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

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: Nits and reviewer suggestions. 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 191 matching lines...) Expand 10 before | Expand all | Expand 10 after
226 pointers_[request] = queue_.insert(request); 227 pointers_[request] = queue_.insert(request);
227 } 228 }
228 229
229 // Each client represents a tab. 230 // Each client represents a tab.
230 class ResourceScheduler::Client { 231 class ResourceScheduler::Client {
231 public: 232 public:
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),
237 is_paused_(false),
236 has_body_(false), 238 has_body_(false),
237 using_spdy_proxy_(false), 239 using_spdy_proxy_(false),
238 total_delayable_count_(0), 240 total_delayable_count_(0),
239 throttle_state_(ResourceScheduler::THROTTLED) { 241 throttle_state_(ResourceScheduler::THROTTLED) {
240 scheduler_ = scheduler; 242 scheduler_ = scheduler;
241 } 243 }
242 ~Client() {} 244
245 ~Client() {
246 // Update to default state and pause to ensure the scheduler has a
247 // correct count of important types of clients.
mmenke 2014/07/29 18:07:22 nit: You didn't change the wording (If you prefer
aiolos (Not reviewing) 2014/07/29 18:58:25 Thanks for catching that. It is now changed.
248 is_visible_ = false;
249 is_audible_ = false;
250 is_paused_ = true;
251 UpdateThrottleState();
252 }
243 253
244 void ScheduleRequest( 254 void ScheduleRequest(
245 net::URLRequest* url_request, 255 net::URLRequest* url_request,
246 ScheduledResourceRequest* request) { 256 ScheduledResourceRequest* request) {
247 if (ShouldStartRequest(request) == START_REQUEST) { 257 if (ShouldStartRequest(request) == START_REQUEST) {
248 StartRequest(request); 258 StartRequest(request);
249 } else { 259 } else {
250 pending_requests_.Insert(request); 260 pending_requests_.Insert(request);
251 } 261 }
252 } 262 }
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
295 } 305 }
296 306
297 void OnLoadingStateChanged(bool is_loaded) { 307 void OnLoadingStateChanged(bool is_loaded) {
298 if (is_loaded == is_loaded_) { 308 if (is_loaded == is_loaded_) {
299 return; 309 return;
300 } 310 }
301 is_loaded_ = is_loaded; 311 is_loaded_ = is_loaded;
302 UpdateThrottleState(); 312 UpdateThrottleState();
303 } 313 }
304 314
315 void SetPaused() {
316 is_paused_ = true;
317 UpdateThrottleState();
318 }
319
305 void UpdateThrottleState() { 320 void UpdateThrottleState() {
306 ClientThrottleState old_throttle_state = throttle_state_; 321 ClientThrottleState old_throttle_state = throttle_state_;
307 if (is_active() && !is_loaded_) { 322 if (is_active() && !is_loaded_) {
308 SetThrottleState(ACTIVE_AND_LOADING); 323 SetThrottleState(ACTIVE_AND_LOADING);
309 } else if (is_active()) { 324 } else if (is_active()) {
310 SetThrottleState(UNTHROTTLED); 325 SetThrottleState(UNTHROTTLED);
326 } else if (is_paused_) {
327 SetThrottleState(PAUSED);
311 } else if (!scheduler_->active_clients_loaded()) { 328 } else if (!scheduler_->active_clients_loaded()) {
312 SetThrottleState(THROTTLED); 329 SetThrottleState(THROTTLED);
313 } else if (is_loaded_ && scheduler_->should_coalesce()) { 330 } else if (is_loaded_ && scheduler_->should_coalesce()) {
314 SetThrottleState(COALESCED); 331 SetThrottleState(COALESCED);
315 } else if (!is_active()) { 332 } else if (!is_active()) {
316 SetThrottleState(UNTHROTTLED); 333 SetThrottleState(UNTHROTTLED);
317 } 334 }
335
318 if (throttle_state_ == old_throttle_state) { 336 if (throttle_state_ == old_throttle_state) {
319 return; 337 return;
320 } 338 }
321 if (throttle_state_ == ACTIVE_AND_LOADING) { 339 if (throttle_state_ == ACTIVE_AND_LOADING) {
322 scheduler_->IncrementActiveClientsLoading(); 340 scheduler_->IncrementActiveClientsLoading();
323 } else if (old_throttle_state == ACTIVE_AND_LOADING) { 341 } else if (old_throttle_state == ACTIVE_AND_LOADING) {
324 scheduler_->DecrementActiveClientsLoading(); 342 scheduler_->DecrementActiveClientsLoading();
325 } 343 }
344 if (throttle_state_ == COALESCED) {
345 scheduler_->IncrementCoalescedClients();
346 } else if (old_throttle_state == COALESCED) {
347 scheduler_->DecrementCoalescedClients();
348 }
326 } 349 }
327 350
328 void OnNavigate() { 351 void OnNavigate() {
329 has_body_ = false; 352 has_body_ = false;
330 is_loaded_ = false; 353 is_loaded_ = false;
331 } 354 }
332 355
333 void OnWillInsertBody() { 356 void OnWillInsertBody() {
334 has_body_ = true; 357 has_body_ = true;
335 LoadAnyStartablePendingRequests(); 358 LoadAnyStartablePendingRequests();
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
378 // Non-observable client, an observable client starts loading. 401 // Non-observable client, an observable client starts loading.
379 // COALESCED -> THROTTLED 402 // COALESCED -> THROTTLED
380 // A COALESCED client will transition into UNTHROTTLED when the network is 403 // A COALESCED client will transition into UNTHROTTLED when the network is
381 // woken up by a heartbeat and then transition back into COALESCED. 404 // woken up by a heartbeat and then transition back into COALESCED.
382 void SetThrottleState(ResourceScheduler::ClientThrottleState throttle_state) { 405 void SetThrottleState(ResourceScheduler::ClientThrottleState throttle_state) {
383 if (throttle_state == throttle_state_) { 406 if (throttle_state == throttle_state_) {
384 return; 407 return;
385 } 408 }
386 throttle_state_ = throttle_state; 409 throttle_state_ = throttle_state;
387 LoadAnyStartablePendingRequests(); 410 LoadAnyStartablePendingRequests();
411 if (throttle_state_ != PAUSED) {
mmenke 2014/07/29 18:07:22 This should probably go before LoadAnyStartablePen
aiolos (Not reviewing) 2014/07/29 18:58:25 Done.
412 is_paused_ = false;
413 }
388 // TODO(aiolos): Stop any started but not inflght requests when 414 // TODO(aiolos): Stop any started but not inflght requests when
389 // switching to stricter throttle state? 415 // switching to stricter throttle state?
390 } 416 }
391 417
392 ResourceScheduler::ClientThrottleState throttle_state() const { 418 ResourceScheduler::ClientThrottleState throttle_state() const {
393 return throttle_state_; 419 return throttle_state_;
394 } 420 }
395 421
396 void LoadCoalescedRequests() { 422 void LoadCoalescedRequests() {
397 if (throttle_state_ != COALESCED) { 423 if (throttle_state_ != COALESCED) {
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after
617 } else { 643 } else {
618 DCHECK(query_result == DO_NOT_START_REQUEST_AND_STOP_SEARCHING); 644 DCHECK(query_result == DO_NOT_START_REQUEST_AND_STOP_SEARCHING);
619 break; 645 break;
620 } 646 }
621 } 647 }
622 } 648 }
623 649
624 bool is_audible_; 650 bool is_audible_;
625 bool is_visible_; 651 bool is_visible_;
626 bool is_loaded_; 652 bool is_loaded_;
653 bool is_paused_;
627 bool has_body_; 654 bool has_body_;
628 bool using_spdy_proxy_; 655 bool using_spdy_proxy_;
629 RequestQueue pending_requests_; 656 RequestQueue pending_requests_;
630 RequestSet in_flight_requests_; 657 RequestSet in_flight_requests_;
631 ResourceScheduler* scheduler_; 658 ResourceScheduler* scheduler_;
632 // The number of delayable in-flight requests. 659 // The number of delayable in-flight requests.
633 size_t total_delayable_count_; 660 size_t total_delayable_count_;
634 ResourceScheduler::ClientThrottleState throttle_state_; 661 ResourceScheduler::ClientThrottleState throttle_state_;
635 }; 662 };
636 663
637 ResourceScheduler::ResourceScheduler(): should_coalesce_(false), 664 ResourceScheduler::ResourceScheduler()
638 should_throttle_(false), 665 : should_coalesce_(false),
639 active_clients_loading_(0) { 666 should_throttle_(false),
667 active_clients_loading_(0),
668 coalesced_clients_(0),
669 coalescing_timer_(new base::Timer(true /* retain_user_task */,
670 true /* is_repeating */)) {
640 } 671 }
641 672
642 ResourceScheduler::~ResourceScheduler() { 673 ResourceScheduler::~ResourceScheduler() {
643 DCHECK(unowned_requests_.empty()); 674 DCHECK(unowned_requests_.empty());
644 DCHECK(client_map_.empty()); 675 DCHECK(client_map_.empty());
645 } 676 }
646 677
647 void ResourceScheduler::SetThrottleOptionsForTesting(bool should_throttle, 678 void ResourceScheduler::SetThrottleOptionsForTesting(bool should_throttle,
648 bool should_coalesce) { 679 bool should_coalesce) {
649 should_coalesce_ = should_coalesce; 680 should_coalesce_ = should_coalesce;
650 should_throttle_ = should_throttle; 681 should_throttle_ = should_throttle;
651 OnLoadingActiveClientsStateChanged(); 682 OnLoadingActiveClientsStateChangedForAllClients();
652 } 683 }
653 684
654 ResourceScheduler::ClientThrottleState 685 ResourceScheduler::ClientThrottleState
655 ResourceScheduler::GetClientStateForTesting(int child_id, int route_id) { 686 ResourceScheduler::GetClientStateForTesting(int child_id, int route_id) {
656 Client* client = GetClient(child_id, route_id); 687 Client* client = GetClient(child_id, route_id);
657 DCHECK(client); 688 DCHECK(client);
658 return client->throttle_state(); 689 return client->throttle_state();
659 } 690 }
660 691
661 scoped_ptr<ResourceThrottle> ResourceScheduler::ScheduleRequest( 692 scoped_ptr<ResourceThrottle> ResourceScheduler::ScheduleRequest(
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
715 746
716 void ResourceScheduler::OnClientDeleted(int child_id, int route_id) { 747 void ResourceScheduler::OnClientDeleted(int child_id, int route_id) {
717 DCHECK(CalledOnValidThread()); 748 DCHECK(CalledOnValidThread());
718 ClientId client_id = MakeClientId(child_id, route_id); 749 ClientId client_id = MakeClientId(child_id, route_id);
719 DCHECK(ContainsKey(client_map_, client_id)); 750 DCHECK(ContainsKey(client_map_, client_id));
720 ClientMap::iterator it = client_map_.find(client_id); 751 ClientMap::iterator it = client_map_.find(client_id);
721 if (it == client_map_.end()) 752 if (it == client_map_.end())
722 return; 753 return;
723 754
724 Client* client = it->second; 755 Client* client = it->second;
725 client->OnLoadingStateChanged(true);
726 // FYI, ResourceDispatcherHost cancels all of the requests after this function 756 // 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 757 // is called. It should end up canceling all of the requests except for a
728 // cross-renderer navigation. 758 // cross-renderer navigation.
729 RequestSet client_unowned_requests = client->RemoveAllRequests(); 759 RequestSet client_unowned_requests = client->RemoveAllRequests();
730 for (RequestSet::iterator it = client_unowned_requests.begin(); 760 for (RequestSet::iterator it = client_unowned_requests.begin();
731 it != client_unowned_requests.end(); ++it) { 761 it != client_unowned_requests.end(); ++it) {
732 unowned_requests_.insert(*it); 762 unowned_requests_.insert(*it);
733 } 763 }
734 764
735 delete client; 765 delete client;
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
811 return NULL; 841 return NULL;
812 } 842 }
813 return client_it->second; 843 return client_it->second;
814 } 844 }
815 845
816 void ResourceScheduler::DecrementActiveClientsLoading() { 846 void ResourceScheduler::DecrementActiveClientsLoading() {
817 DCHECK_NE(0u, active_clients_loading_); 847 DCHECK_NE(0u, active_clients_loading_);
818 --active_clients_loading_; 848 --active_clients_loading_;
819 DCHECK_EQ(active_clients_loading_, CountActiveClientsLoading()); 849 DCHECK_EQ(active_clients_loading_, CountActiveClientsLoading());
820 if (active_clients_loading_ == 0) { 850 if (active_clients_loading_ == 0) {
821 OnLoadingActiveClientsStateChanged(); 851 OnLoadingActiveClientsStateChangedForAllClients();
822 } 852 }
823 } 853 }
824 854
825 void ResourceScheduler::IncrementActiveClientsLoading() { 855 void ResourceScheduler::IncrementActiveClientsLoading() {
826 ++active_clients_loading_; 856 ++active_clients_loading_;
827 DCHECK_EQ(active_clients_loading_, CountActiveClientsLoading()); 857 DCHECK_EQ(active_clients_loading_, CountActiveClientsLoading());
828 if (active_clients_loading_ == 1) { 858 if (active_clients_loading_ == 1) {
829 OnLoadingActiveClientsStateChanged(); 859 OnLoadingActiveClientsStateChangedForAllClients();
830 } 860 }
831 } 861 }
832 862
833 void ResourceScheduler::OnLoadingActiveClientsStateChanged() { 863 void ResourceScheduler::OnLoadingActiveClientsStateChangedForAllClients() {
834 ClientMap::iterator client_it = client_map_.begin(); 864 ClientMap::iterator client_it = client_map_.begin();
835 while (client_it != client_map_.end()) { 865 while (client_it != client_map_.end()) {
836 Client* client = client_it->second; 866 Client* client = client_it->second;
837 client->UpdateThrottleState(); 867 client->UpdateThrottleState();
838 ++client_it; 868 ++client_it;
839 } 869 }
840 } 870 }
841 871
842 size_t ResourceScheduler::CountActiveClientsLoading() { 872 size_t ResourceScheduler::CountActiveClientsLoading() const {
843 size_t active_and_loading = 0; 873 size_t active_and_loading = 0;
844 ClientMap::iterator client_it = client_map_.begin(); 874 ClientMap::const_iterator client_it = client_map_.begin();
845 while (client_it != client_map_.end()) { 875 while (client_it != client_map_.end()) {
846 Client* client = client_it->second; 876 Client* client = client_it->second;
847 if (client->throttle_state() == ACTIVE_AND_LOADING) { 877 if (client->throttle_state() == ACTIVE_AND_LOADING) {
848 ++active_and_loading; 878 ++active_and_loading;
849 } 879 }
850 ++client_it; 880 ++client_it;
851 } 881 }
852 return active_and_loading; 882 return active_and_loading;
853 } 883 }
854 884
885 void ResourceScheduler::IncrementCoalescedClients() {
886 ++coalesced_clients_;
887 DCHECK(should_coalesce_);
888 DCHECK_EQ(coalesced_clients_, CountCoalescedClients());
889 if (coalesced_clients_ == 1) {
890 coalescing_timer_->Start(
891 FROM_HERE,
892 base::TimeDelta::FromMilliseconds(kCoalescedTimerPeriod),
893 base::Bind(&ResourceScheduler::LoadCoalescedRequests,
894 base::Unretained(this)));
895 }
896 }
897
898 void ResourceScheduler::DecrementCoalescedClients() {
899 DCHECK(should_coalesce_);
900 DCHECK_NE(0U, coalesced_clients_);
901 --coalesced_clients_;
902 DCHECK_EQ(coalesced_clients_, CountCoalescedClients());
903 if (coalesced_clients_ == 0) {
904 coalescing_timer_->Stop();
905 }
906 }
907
908 size_t ResourceScheduler::CountCoalescedClients() const {
909 DCHECK(should_coalesce_);
910 size_t coalesced_clients = 0;
911 ClientMap::const_iterator client_it = client_map_.begin();
912 while (client_it != client_map_.end()) {
913 Client* client = client_it->second;
914 if (client->throttle_state() == COALESCED) {
915 ++coalesced_clients;
916 }
917 ++client_it;
918 }
919 return coalesced_clients_;
920 }
921
922 void ResourceScheduler::LoadCoalescedRequests() {
923 DCHECK(should_coalesce_);
924 ClientMap::iterator client_it = client_map_.begin();
925 while (client_it != client_map_.end()) {
926 Client* client = client_it->second;
927 client->LoadCoalescedRequests();
928 ++client_it;
929 }
930 }
931
855 void ResourceScheduler::ReprioritizeRequest(ScheduledResourceRequest* request, 932 void ResourceScheduler::ReprioritizeRequest(ScheduledResourceRequest* request,
856 net::RequestPriority new_priority, 933 net::RequestPriority new_priority,
857 int new_intra_priority_value) { 934 int new_intra_priority_value) {
858 if (request->url_request()->load_flags() & net::LOAD_IGNORE_LIMITS) { 935 if (request->url_request()->load_flags() & net::LOAD_IGNORE_LIMITS) {
859 // We should not be re-prioritizing requests with the 936 // We should not be re-prioritizing requests with the
860 // IGNORE_LIMITS flag. 937 // IGNORE_LIMITS flag.
861 NOTREACHED(); 938 NOTREACHED();
862 return; 939 return;
863 } 940 }
864 RequestPriorityParams new_priority_params(new_priority, 941 RequestPriorityParams new_priority_params(new_priority,
(...skipping 18 matching lines...) Expand all
883 client->ReprioritizeRequest( 960 client->ReprioritizeRequest(
884 request, old_priority_params, new_priority_params); 961 request, old_priority_params, new_priority_params);
885 } 962 }
886 963
887 ResourceScheduler::ClientId ResourceScheduler::MakeClientId( 964 ResourceScheduler::ClientId ResourceScheduler::MakeClientId(
888 int child_id, int route_id) { 965 int child_id, int route_id) {
889 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id; 966 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id;
890 } 967 }
891 968
892 } // namespace content 969 } // 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