Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 // See http://dev.chromium.org/developers/design-documents/multi-process-resourc e-loading | 5 // See http://dev.chromium.org/developers/design-documents/multi-process-resourc e-loading |
| 6 | 6 |
| 7 #include "content/browser/loader/resource_dispatcher_host_impl.h" | 7 #include "content/browser/loader/resource_dispatcher_host_impl.h" |
| 8 | 8 |
| 9 #include <stddef.h> | 9 #include <stddef.h> |
| 10 | 10 |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 161 | 161 |
| 162 namespace content { | 162 namespace content { |
| 163 | 163 |
| 164 namespace { | 164 namespace { |
| 165 | 165 |
| 166 static ResourceDispatcherHostImpl* g_resource_dispatcher_host; | 166 static ResourceDispatcherHostImpl* g_resource_dispatcher_host; |
| 167 | 167 |
| 168 // The interval for calls to ResourceDispatcherHostImpl::UpdateLoadStates | 168 // The interval for calls to ResourceDispatcherHostImpl::UpdateLoadStates |
| 169 const int kUpdateLoadStatesIntervalMsec = 250; | 169 const int kUpdateLoadStatesIntervalMsec = 250; |
| 170 | 170 |
| 171 // The interval for calls to RecordOutstandingRequestsStats. | |
| 172 const int kRecordOutstandingRequestsStatsIntervalMsec = 60000; | |
| 173 | |
| 171 // Maximum byte "cost" of all the outstanding requests for a renderer. | 174 // Maximum byte "cost" of all the outstanding requests for a renderer. |
| 172 // See declaration of |max_outstanding_requests_cost_per_process_| for details. | 175 // See declaration of |max_outstanding_requests_cost_per_process_| for details. |
| 173 // This bound is 25MB, which allows for around 6000 outstanding requests. | 176 // This bound is 25MB, which allows for around 6000 outstanding requests. |
| 174 const int kMaxOutstandingRequestsCostPerProcess = 26214400; | 177 const int kMaxOutstandingRequestsCostPerProcess = 26214400; |
| 175 | 178 |
| 176 // The number of milliseconds after noting a user gesture that we will | 179 // The number of milliseconds after noting a user gesture that we will |
| 177 // tag newly-created URLRequest objects with the | 180 // tag newly-created URLRequest objects with the |
| 178 // net::LOAD_MAYBE_USER_GESTURE load flag. This is a fairly arbitrary | 181 // net::LOAD_MAYBE_USER_GESTURE load flag. This is a fairly arbitrary |
| 179 // guess at how long to expect direct impact from a user gesture, but | 182 // guess at how long to expect direct impact from a user gesture, but |
| 180 // this should be OK as the load flag is a best-effort thing only, | 183 // this should be OK as the load flag is a best-effort thing only, |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 332 : request_id_(-1), | 335 : request_id_(-1), |
| 333 is_shutdown_(false), | 336 is_shutdown_(false), |
| 334 num_in_flight_requests_(0), | 337 num_in_flight_requests_(0), |
| 335 max_num_in_flight_requests_(base::SharedMemory::GetHandleLimit()), | 338 max_num_in_flight_requests_(base::SharedMemory::GetHandleLimit()), |
| 336 max_num_in_flight_requests_per_process_(static_cast<int>( | 339 max_num_in_flight_requests_per_process_(static_cast<int>( |
| 337 max_num_in_flight_requests_ * kMaxRequestsPerProcessRatio)), | 340 max_num_in_flight_requests_ * kMaxRequestsPerProcessRatio)), |
| 338 max_outstanding_requests_cost_per_process_( | 341 max_outstanding_requests_cost_per_process_( |
| 339 kMaxOutstandingRequestsCostPerProcess), | 342 kMaxOutstandingRequestsCostPerProcess), |
| 340 largest_outstanding_request_count_seen_(0), | 343 largest_outstanding_request_count_seen_(0), |
| 341 largest_outstanding_request_per_process_count_seen_(0), | 344 largest_outstanding_request_per_process_count_seen_(0), |
| 345 peak_outstanding_request_count_(0), | |
| 346 peak_outstanding_request_count_multitab_(0), | |
| 342 delegate_(nullptr), | 347 delegate_(nullptr), |
| 343 loader_delegate_(nullptr), | 348 loader_delegate_(nullptr), |
| 344 allow_cross_origin_auth_prompt_(false), | 349 allow_cross_origin_auth_prompt_(false), |
| 345 create_download_handler_intercept_(download_handler_intercept), | 350 create_download_handler_intercept_(download_handler_intercept), |
| 346 main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()), | 351 main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
| 347 io_thread_task_runner_(io_thread_runner), | 352 io_thread_task_runner_(io_thread_runner), |
| 348 experimental_web_features_enabled_( | 353 experimental_web_features_enabled_( |
| 349 base::CommandLine::ForCurrentProcess()->HasSwitch( | 354 base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 350 switches::kEnableExperimentalWebPlatformFeatures)) { | 355 switches::kEnableExperimentalWebPlatformFeatures)) { |
| 351 DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); | 356 DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); |
| 352 DCHECK(!g_resource_dispatcher_host); | 357 DCHECK(!g_resource_dispatcher_host); |
| 353 g_resource_dispatcher_host = this; | 358 g_resource_dispatcher_host = this; |
| 354 | 359 |
| 355 ANNOTATE_BENIGN_RACE( | 360 ANNOTATE_BENIGN_RACE( |
| 356 &last_user_gesture_time_, | 361 &last_user_gesture_time_, |
| 357 "We don't care about the precise value, see http://crbug.com/92889"); | 362 "We don't care about the precise value, see http://crbug.com/92889"); |
| 358 | 363 |
| 359 io_thread_task_runner_->PostTask( | 364 io_thread_task_runner_->PostTask( |
| 360 FROM_HERE, | 365 FROM_HERE, |
| 361 base::Bind(&ResourceDispatcherHostImpl::OnInit, base::Unretained(this))); | 366 base::Bind(&ResourceDispatcherHostImpl::OnInit, base::Unretained(this))); |
| 362 | 367 |
| 363 update_load_states_timer_.reset(new base::RepeatingTimer()); | 368 update_load_states_timer_.reset(new base::RepeatingTimer()); |
| 369 record_outstanding_requests_stats_timer_.reset(new base::RepeatingTimer()); | |
| 364 } | 370 } |
| 365 | 371 |
| 366 // The default ctor is only used by unittests. It is reasonable to assume that | 372 // The default ctor is only used by unittests. It is reasonable to assume that |
| 367 // the main thread and the IO thread are the same for unittests. | 373 // the main thread and the IO thread are the same for unittests. |
| 368 ResourceDispatcherHostImpl::ResourceDispatcherHostImpl() | 374 ResourceDispatcherHostImpl::ResourceDispatcherHostImpl() |
| 369 : ResourceDispatcherHostImpl(CreateDownloadHandlerIntercept(), | 375 : ResourceDispatcherHostImpl(CreateDownloadHandlerIntercept(), |
| 370 base::ThreadTaskRunnerHandle::Get()) {} | 376 base::ThreadTaskRunnerHandle::Get()) {} |
| 371 | 377 |
| 372 ResourceDispatcherHostImpl::~ResourceDispatcherHostImpl() { | 378 ResourceDispatcherHostImpl::~ResourceDispatcherHostImpl() { |
| 373 DCHECK(outstanding_requests_stats_map_.empty()); | 379 DCHECK(outstanding_requests_stats_map_.empty()); |
| (...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 582 | 588 |
| 583 const net::URLRequestJobFactory* job_factory = | 589 const net::URLRequestJobFactory* job_factory = |
| 584 info->GetContext()->GetRequestContext()->job_factory(); | 590 info->GetContext()->GetRequestContext()->job_factory(); |
| 585 if (!url.is_valid() || job_factory->IsHandledProtocol(url.scheme())) | 591 if (!url.is_valid() || job_factory->IsHandledProtocol(url.scheme())) |
| 586 return false; | 592 return false; |
| 587 | 593 |
| 588 return delegate_->HandleExternalProtocol(url, info); | 594 return delegate_->HandleExternalProtocol(url, info); |
| 589 } | 595 } |
| 590 | 596 |
| 591 void ResourceDispatcherHostImpl::DidStartRequest(ResourceLoader* loader) { | 597 void ResourceDispatcherHostImpl::DidStartRequest(ResourceLoader* loader) { |
| 592 // Make sure we have the load state monitor running. | 598 // Make sure we have the load state monitors running. |
| 593 if (!update_load_states_timer_->IsRunning() && | 599 if (!update_load_states_timer_->IsRunning() && |
| 594 scheduler_->HasLoadingClients()) { | 600 scheduler_->HasLoadingClients()) { |
| 595 update_load_states_timer_->Start( | 601 update_load_states_timer_->Start( |
| 596 FROM_HERE, TimeDelta::FromMilliseconds(kUpdateLoadStatesIntervalMsec), | 602 FROM_HERE, TimeDelta::FromMilliseconds(kUpdateLoadStatesIntervalMsec), |
| 597 this, &ResourceDispatcherHostImpl::UpdateLoadInfo); | 603 this, &ResourceDispatcherHostImpl::UpdateLoadInfo); |
| 598 } | 604 } |
| 605 if (!record_outstanding_requests_stats_timer_->IsRunning()) { | |
| 606 record_outstanding_requests_stats_timer_->Start( | |
| 607 FROM_HERE, | |
| 608 TimeDelta::FromMilliseconds( | |
| 609 kRecordOutstandingRequestsStatsIntervalMsec), | |
| 610 this, &ResourceDispatcherHostImpl::RecordOutstandingRequestsStats); | |
| 611 } | |
| 599 } | 612 } |
| 600 | 613 |
| 601 void ResourceDispatcherHostImpl::DidReceiveRedirect( | 614 void ResourceDispatcherHostImpl::DidReceiveRedirect( |
| 602 ResourceLoader* loader, | 615 ResourceLoader* loader, |
| 603 const GURL& new_url, | 616 const GURL& new_url, |
| 604 ResourceResponse* response) { | 617 ResourceResponse* response) { |
| 605 ResourceRequestInfoImpl* info = loader->GetRequestInfo(); | 618 ResourceRequestInfoImpl* info = loader->GetRequestInfo(); |
| 606 if (delegate_) { | 619 if (delegate_) { |
| 607 delegate_->OnRequestRedirected( | 620 delegate_->OnRequestRedirected( |
| 608 new_url, loader->request(), info->GetContext(), response); | 621 new_url, loader->request(), info->GetContext(), response); |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 777 void ResourceDispatcherHostImpl::OnInit() { | 790 void ResourceDispatcherHostImpl::OnInit() { |
| 778 scheduler_.reset(new ResourceScheduler); | 791 scheduler_.reset(new ResourceScheduler); |
| 779 } | 792 } |
| 780 | 793 |
| 781 void ResourceDispatcherHostImpl::OnShutdown() { | 794 void ResourceDispatcherHostImpl::OnShutdown() { |
| 782 DCHECK(io_thread_task_runner_->BelongsToCurrentThread()); | 795 DCHECK(io_thread_task_runner_->BelongsToCurrentThread()); |
| 783 | 796 |
| 784 is_shutdown_ = true; | 797 is_shutdown_ = true; |
| 785 pending_loaders_.clear(); | 798 pending_loaders_.clear(); |
| 786 | 799 |
| 787 // Make sure we shutdown the timer now, otherwise by the time our destructor | 800 // Make sure we shutdown the timers now, otherwise by the time our destructor |
| 788 // runs if the timer is still running the Task is deleted twice (once by | 801 // runs if the timer is still running the Task is deleted twice (once by |
| 789 // the MessageLoop and the second time by RepeatingTimer). | 802 // the MessageLoop and the second time by RepeatingTimer). |
| 790 update_load_states_timer_.reset(); | 803 update_load_states_timer_.reset(); |
| 804 record_outstanding_requests_stats_timer_.reset(); | |
| 791 | 805 |
| 792 // Clear blocked requests if any left. | 806 // Clear blocked requests if any left. |
| 793 // Note that we have to do this in 2 passes as we cannot call | 807 // Note that we have to do this in 2 passes as we cannot call |
| 794 // CancelBlockedRequestsForRoute while iterating over | 808 // CancelBlockedRequestsForRoute while iterating over |
| 795 // blocked_loaders_map_, as it modifies it. | 809 // blocked_loaders_map_, as it modifies it. |
| 796 std::set<GlobalFrameRoutingId> ids; | 810 std::set<GlobalFrameRoutingId> ids; |
| 797 for (const auto& blocked_loaders : blocked_loaders_map_) { | 811 for (const auto& blocked_loaders : blocked_loaders_map_) { |
| 798 std::pair<std::set<GlobalFrameRoutingId>::iterator, bool> result = | 812 std::pair<std::set<GlobalFrameRoutingId>::iterator, bool> result = |
| 799 ids.insert(blocked_loaders.first); | 813 ids.insert(blocked_loaders.first); |
| 800 // We should not have duplicates. | 814 // We should not have duplicates. |
| (...skipping 1161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1962 } | 1976 } |
| 1963 | 1977 |
| 1964 if (stats.num_requests > | 1978 if (stats.num_requests > |
| 1965 largest_outstanding_request_per_process_count_seen_) { | 1979 largest_outstanding_request_per_process_count_seen_) { |
| 1966 largest_outstanding_request_per_process_count_seen_ = stats.num_requests; | 1980 largest_outstanding_request_per_process_count_seen_ = stats.num_requests; |
| 1967 UMA_HISTOGRAM_COUNTS_1M( | 1981 UMA_HISTOGRAM_COUNTS_1M( |
| 1968 "Net.ResourceDispatcherHost.OutstandingRequests.PerProcess", | 1982 "Net.ResourceDispatcherHost.OutstandingRequests.PerProcess", |
| 1969 largest_outstanding_request_per_process_count_seen_); | 1983 largest_outstanding_request_per_process_count_seen_); |
| 1970 } | 1984 } |
| 1971 | 1985 |
| 1986 if (num_in_flight_requests_ > peak_outstanding_request_count_) { | |
| 1987 peak_outstanding_request_count_ = num_in_flight_requests_; | |
| 1988 } | |
| 1989 | |
| 1990 if (HasRequestsFromMultipleActiveProcesses() && | |
| 1991 num_in_flight_requests_ > peak_outstanding_request_count_multitab_) { | |
| 1992 peak_outstanding_request_count_multitab_ = num_in_flight_requests_; | |
| 1993 } | |
| 1994 | |
| 1972 return stats; | 1995 return stats; |
| 1973 } | 1996 } |
| 1974 | 1997 |
| 1975 bool ResourceDispatcherHostImpl::HasSufficientResourcesForRequest( | 1998 bool ResourceDispatcherHostImpl::HasSufficientResourcesForRequest( |
| 1976 net::URLRequest* request) { | 1999 net::URLRequest* request) { |
| 1977 ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest(request); | 2000 ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest(request); |
| 1978 OustandingRequestsStats stats = IncrementOutstandingRequestsCount(1, info); | 2001 OustandingRequestsStats stats = IncrementOutstandingRequestsCount(1, info); |
| 1979 | 2002 |
| 1980 if (stats.num_requests > max_num_in_flight_requests_per_process_) | 2003 if (stats.num_requests > max_num_in_flight_requests_per_process_) |
| 1981 return false; | 2004 return false; |
| (...skipping 508 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2490 // We need to be able to compare all requests to find the most important one | 2513 // We need to be able to compare all requests to find the most important one |
| 2491 // per tab. Since some requests may be navigation requests and we don't have | 2514 // per tab. Since some requests may be navigation requests and we don't have |
| 2492 // their render frame routing IDs yet (which is what we have for subresource | 2515 // their render frame routing IDs yet (which is what we have for subresource |
| 2493 // requests), we must go to the UI thread and compare the requests using their | 2516 // requests), we must go to the UI thread and compare the requests using their |
| 2494 // WebContents. | 2517 // WebContents. |
| 2495 main_thread_task_runner_->PostTask( | 2518 main_thread_task_runner_->PostTask( |
| 2496 FROM_HERE, | 2519 FROM_HERE, |
| 2497 base::Bind(UpdateLoadStateOnUI, loader_delegate_, base::Passed(&infos))); | 2520 base::Bind(UpdateLoadStateOnUI, loader_delegate_, base::Passed(&infos))); |
| 2498 } | 2521 } |
| 2499 | 2522 |
| 2523 void ResourceDispatcherHostImpl::RecordOutstandingRequestsStats() { | |
| 2524 if (peak_outstanding_request_count_ != 0) { | |
| 2525 UMA_HISTOGRAM_COUNTS_1M( | |
| 2526 "Net.ResourceDispatcherHost.PeakOutstandingRequests", | |
| 2527 peak_outstanding_request_count_); | |
| 2528 peak_outstanding_request_count_ = num_in_flight_requests_; | |
|
kinuko
2017/06/21 04:00:10
Intuitively I feel this should be reset to 0 becau
Kunihiko Sakamoto
2017/06/21 05:25:32
My intuition is that if there are n outstanding re
kinuko
2017/06/21 07:06:48
Hm, ok I think that makes sense.
| |
| 2529 } | |
| 2530 | |
| 2531 if (peak_outstanding_request_count_multitab_ != 0) { | |
| 2532 UMA_HISTOGRAM_COUNTS_1M( | |
| 2533 "Net.ResourceDispatcherHost.PeakOutstandingRequests.MultiTabLoading", | |
|
kinuko
2017/06/21 04:00:10
The map we rely on groups requests per-process rat
Kunihiko Sakamoto
2017/06/21 05:25:32
Yeah, you're right. Renamed the suffix to 'Multipl
kinuko
2017/06/21 07:06:48
We could use routing_id to gather per-tab stats, h
| |
| 2534 peak_outstanding_request_count_multitab_); | |
| 2535 peak_outstanding_request_count_multitab_ = | |
| 2536 HasRequestsFromMultipleActiveProcesses() ? num_in_flight_requests_ : 0; | |
| 2537 } | |
| 2538 } | |
| 2539 | |
| 2500 void ResourceDispatcherHostImpl::BlockRequestsForRoute( | 2540 void ResourceDispatcherHostImpl::BlockRequestsForRoute( |
| 2501 const GlobalFrameRoutingId& global_routing_id) { | 2541 const GlobalFrameRoutingId& global_routing_id) { |
| 2502 DCHECK(io_thread_task_runner_->BelongsToCurrentThread()); | 2542 DCHECK(io_thread_task_runner_->BelongsToCurrentThread()); |
| 2503 DCHECK(blocked_loaders_map_.find(global_routing_id) == | 2543 DCHECK(blocked_loaders_map_.find(global_routing_id) == |
| 2504 blocked_loaders_map_.end()) | 2544 blocked_loaders_map_.end()) |
| 2505 << "BlockRequestsForRoute called multiple time for the same RFH"; | 2545 << "BlockRequestsForRoute called multiple time for the same RFH"; |
| 2506 blocked_loaders_map_[global_routing_id] = | 2546 blocked_loaders_map_[global_routing_id] = |
| 2507 base::MakeUnique<BlockedLoadersList>(); | 2547 base::MakeUnique<BlockedLoadersList>(); |
| 2508 } | 2548 } |
| 2509 | 2549 |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2699 is_content_initiated, true, is_new_request, | 2739 is_content_initiated, true, is_new_request, |
| 2700 &throttles); | 2740 &throttles); |
| 2701 if (!throttles.empty()) { | 2741 if (!throttles.empty()) { |
| 2702 handler.reset(new ThrottlingResourceHandler(std::move(handler), request, | 2742 handler.reset(new ThrottlingResourceHandler(std::move(handler), request, |
| 2703 std::move(throttles))); | 2743 std::move(throttles))); |
| 2704 } | 2744 } |
| 2705 } | 2745 } |
| 2706 return handler; | 2746 return handler; |
| 2707 } | 2747 } |
| 2708 | 2748 |
| 2749 bool ResourceDispatcherHostImpl::HasRequestsFromMultipleActiveProcesses() { | |
| 2750 if (outstanding_requests_stats_map_.size() < 2) | |
| 2751 return false; | |
| 2752 | |
| 2753 int active_processes = 0; | |
| 2754 for (auto iter = outstanding_requests_stats_map_.begin(); | |
| 2755 iter != outstanding_requests_stats_map_.end(); ++iter) { | |
| 2756 if (iter->second.num_requests > 2) { | |
| 2757 active_processes++; | |
| 2758 if (active_processes >= 2) | |
| 2759 return true; | |
| 2760 } | |
| 2761 } | |
| 2762 return false; | |
| 2763 } | |
| 2764 | |
| 2709 } // namespace content | 2765 } // namespace content |
| OLD | NEW |