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

Unified Diff: content/renderer/resource_dispatch_throttler.cc

Issue 847883002: Reland "Throttle resource message requests during user interaction" (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase Created 5 years, 11 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 side-by-side diff with in-line comments
Download patch
Index: content/renderer/resource_dispatch_throttler.cc
diff --git a/content/renderer/resource_dispatch_throttler.cc b/content/renderer/resource_dispatch_throttler.cc
new file mode 100644
index 0000000000000000000000000000000000000000..4ba1291caa3f14de02e3fba253f2851a80d72924
--- /dev/null
+++ b/content/renderer/resource_dispatch_throttler.cc
@@ -0,0 +1,239 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/resource_dispatch_throttler.h"
+
+#include "base/auto_reset.h"
+#include "base/debug/trace_event.h"
+#include "content/common/resource_messages.h"
+#include "content/renderer/scheduler/renderer_scheduler.h"
+#include "ipc/ipc_message_macros.h"
+
+namespace content {
+namespace {
+
+int GetRequestId(const IPC::Message& msg) {
+ int request_id = -1;
+ switch (msg.type()) {
+ case ResourceHostMsg_RequestResource::ID: {
+ PickleIterator iter(msg);
+ int routing_id = -1;
+ if (!iter.ReadInt(&routing_id) || !iter.ReadInt(&request_id))
+ NOTREACHED() << "Invalid id for resource request message.";
+ } break;
+
+ case ResourceHostMsg_DidChangePriority::ID:
+ case ResourceHostMsg_ReleaseDownloadedFile::ID:
+ case ResourceHostMsg_CancelRequest::ID:
+ if (!PickleIterator(msg).ReadInt(&request_id))
+ NOTREACHED() << "Invalid id for resource message.";
+ break;
+
+ default:
+ NOTREACHED() << "Invalid message for resource throttling.";
+ break;
+ }
+ return request_id;
+}
+
+bool UpdateRequestPriority(const IPC::Message& priority_msg,
+ IPC::Message* request_msg) {
+ ResourceHostMsg_DidChangePriority::Param priority_params;
+ if (!ResourceHostMsg_DidChangePriority::Read(&priority_msg, &priority_params))
+ return false;
+
+ ResourceHostMsg_RequestResource::Param request_params;
+ if (!ResourceHostMsg_RequestResource::Read(request_msg, &request_params))
+ return false;
+
+ int routing_id = get<0>(request_params);
+ int request_id = get<1>(request_params);
+ DCHECK_EQ(request_id, get<0>(priority_params));
+
+ ResourceHostMsg_Request& updated_request = get<2>(request_params);
+ updated_request.priority = get<1>(priority_params);
+ *request_msg =
+ ResourceHostMsg_RequestResource(routing_id, request_id, updated_request);
+ return true;
+}
+
+bool UpdateRequestToReleaseDownloadedFile(IPC::Message* request_msg) {
+ ResourceHostMsg_RequestResource::Param request_params;
+ if (!ResourceHostMsg_RequestResource::Read(request_msg, &request_params))
+ return false;
+
+ int routing_id = get<0>(request_params);
+ int request_id = get<1>(request_params);
+ ResourceHostMsg_Request& updated_request = get<2>(request_params);
+ // No need to update the request message if no file download was specified.
+ if (!updated_request.download_to_file)
+ return true;
+
+ updated_request.download_to_file = false;
+ *request_msg =
+ ResourceHostMsg_RequestResource(routing_id, request_id, updated_request);
+ return true;
+}
+
+} // namespace
+
+ResourceDispatchThrottler::ResourceDispatchThrottler(
+ IPC::Sender* proxied_sender,
+ RendererScheduler* scheduler,
+ base::TimeDelta flush_period,
+ uint32 max_requests_per_flush)
+ : proxied_sender_(proxied_sender),
+ scheduler_(scheduler),
+ flush_period_(flush_period),
+ max_requests_per_flush_(max_requests_per_flush),
+ flush_timer_(
+ FROM_HERE,
+ flush_period_,
+ base::Bind(&ResourceDispatchThrottler::Flush, base::Unretained(this)),
+ false /* is_repeating */),
+ sent_requests_since_last_flush_(0),
+ is_forwarding_request_(false) {
+ DCHECK(proxied_sender);
+ DCHECK(scheduler);
+ DCHECK(flush_period_ != base::TimeDelta());
+ DCHECK(max_requests_per_flush_);
+ flush_timer_.SetTaskRunner(scheduler->DefaultTaskRunner());
+}
+
+ResourceDispatchThrottler::~ResourceDispatchThrottler() {
+ for (auto& request : throttled_requests_)
+ ForwardRequest(request.second);
+ throttled_requests_.clear();
+}
+
+bool ResourceDispatchThrottler::Send(IPC::Message* msg) {
+ thread_checker_.CalledOnValidThread();
+ switch (msg->type()) {
+ case ResourceHostMsg_RequestResource::ID:
+ return OnRequestResource(msg);
+
+ case ResourceHostMsg_DidChangePriority::ID:
+ return OnDidChangePriority(msg);
+
+ case ResourceHostMsg_ReleaseDownloadedFile::ID:
+ return OnReleaseDownloadedFile(msg);
+
+ case ResourceHostMsg_CancelRequest::ID:
+ return OnCancelRequest(msg);
+
+ default:
+ return proxied_sender_->Send(msg);
+ }
+}
+
+base::TimeTicks ResourceDispatchThrottler::Now() const {
+ return base::TimeTicks::Now();
+}
+
+void ResourceDispatchThrottler::ScheduleFlush() {
+ DCHECK(!flush_timer_.IsRunning());
+ flush_timer_.Reset();
+}
+
+void ResourceDispatchThrottler::Flush() {
+ TRACE_EVENT1("loader", "ResourceDispatchThrottler::Flush",
+ "total_throttled_requests", throttled_requests_.size());
+ sent_requests_since_last_flush_ = 0;
+
+ // If high-priority work is no longer anticipated, dispatch can be safely
+ // accelerated. Avoid completely flushing in such case in the event that
+ // a large number of requests have been throttled.
+ uint32 max_requests = scheduler_->ShouldAnticipateHighPriorityWork()
+ ? max_requests_per_flush_
+ : max_requests_per_flush_ * 2;
+
+ while (!throttled_requests_.empty() &&
+ sent_requests_since_last_flush_ < max_requests) {
+ auto request_it = throttled_requests_.begin();
+ scoped_ptr<IPC::Message> forwarded_msg(request_it->second);
+ throttled_requests_.erase(request_it);
+ ForwardRequest(forwarded_msg.release());
+ }
+
+ if (!throttled_requests_.empty())
+ ScheduleFlush();
+}
+
+bool ResourceDispatchThrottler::ForwardRequest(IPC::Message* msg) {
+ DCHECK(!is_forwarding_request_);
+ base::AutoReset<bool> is_forwarding_request_resetter(&is_forwarding_request_,
+ true);
+ last_sent_request_time_ = Now();
+ ++sent_requests_since_last_flush_;
+ return proxied_sender_->Send(msg);
+}
+
+bool ResourceDispatchThrottler::OnRequestResource(IPC::Message* msg) {
+ DCHECK(!is_forwarding_request_);
+ const int request_id = GetRequestId(*msg);
+
+ // Shift responsibility for handling an invalid request ID downstream.
+ if (request_id == -1)
+ return ForwardRequest(msg);
+
+ if (!throttled_requests_.empty()) {
+ // Valid request ids must be monotonically increasing.
+ DCHECK_LT(throttled_requests_.rbegin()->first, request_id);
+ throttled_requests_.insert(std::make_pair(request_id, msg));
+ TRACE_EVENT_INSTANT0("loader", "ResourceDispatchThrottler::ThrottleRequest",
+ TRACE_EVENT_SCOPE_THREAD);
+ return true;
+ }
+
+ if (!scheduler_->ShouldAnticipateHighPriorityWork())
+ return ForwardRequest(msg);
+
+ if (Now() > (last_sent_request_time_ + flush_period_)) {
+ // If sufficient time has passed since the previous send, we can effectively
+ // mark the pipeline as flushed.
+ sent_requests_since_last_flush_ = 0;
+ return ForwardRequest(msg);
+ }
+
+ if (sent_requests_since_last_flush_ < max_requests_per_flush_)
+ return ForwardRequest(msg);
+
+ TRACE_EVENT_INSTANT0("loader", "ResourceDispatchThrottler::ThrottleRequest",
+ TRACE_EVENT_SCOPE_THREAD);
+ throttled_requests_.insert(std::make_pair(request_id, msg));
+ ScheduleFlush();
+ return true;
+}
+
+bool ResourceDispatchThrottler::OnDidChangePriority(IPC::Message* msg) {
+ scoped_ptr<IPC::Message> scoped_msg(msg);
+ auto request_it = throttled_requests_.find(GetRequestId(*msg));
+ if (request_it == throttled_requests_.end())
+ return proxied_sender_->Send(scoped_msg.release());
+
+ return UpdateRequestPriority(*scoped_msg, request_it->second);
+}
+
+bool ResourceDispatchThrottler::OnReleaseDownloadedFile(IPC::Message* msg) {
+ scoped_ptr<IPC::Message> scoped_msg(msg);
+ auto request_it = throttled_requests_.find(GetRequestId(*msg));
+ if (request_it == throttled_requests_.end())
+ return proxied_sender_->Send(scoped_msg.release());
+
+ // TODO(jdduke): Should this simply cancel the outstanding request?
+ return UpdateRequestToReleaseDownloadedFile(request_it->second);
+}
+
+bool ResourceDispatchThrottler::OnCancelRequest(IPC::Message* msg) {
+ scoped_ptr<IPC::Message> scoped_msg(msg);
+ auto request_it = throttled_requests_.find(GetRequestId(*msg));
+ if (request_it == throttled_requests_.end())
+ return proxied_sender_->Send(scoped_msg.release());
+
+ scoped_ptr<IPC::Message> cancelled_msg(request_it->second);
+ throttled_requests_.erase(request_it);
+ return true;
+}
+
+} // namespace content

Powered by Google App Engine
This is Rietveld 408576698