Index: content/renderer/scheduler/throttled_message_sender.cc |
diff --git a/content/renderer/scheduler/throttled_message_sender.cc b/content/renderer/scheduler/throttled_message_sender.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..242d4105b1616949cfe72de8326f5f8c8456464a |
--- /dev/null |
+++ b/content/renderer/scheduler/throttled_message_sender.cc |
@@ -0,0 +1,116 @@ |
+// 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/scheduler/throttled_message_sender.h" |
+ |
+#include "base/auto_reset.h" |
+#include "content/renderer/scheduler/renderer_scheduler.h" |
+#include "ipc/ipc_message.h" |
+ |
+namespace content { |
+namespace { |
+ |
+const int kReasonableFlushesPerSecond = 60; |
picksi1
2015/01/13 11:24:44
Is this 60 related to the 60*4 in kMaxResourceMess
jdduke (slow)
2015/01/13 16:18:11
It's not really related, but I'll add a comment.
|
+ |
+} // namespace |
+ |
+ThrottledMessageSender::ThrottledMessageSender(IPC::Sender* proxied_sender, |
+ RendererScheduler* scheduler, |
+ int max_sent_messages_per_second) |
+ : proxied_sender_(proxied_sender), |
+ scheduler_(scheduler), |
+ max_sent_messages_per_flush_( |
+ std::max(1, |
+ max_sent_messages_per_second / kReasonableFlushesPerSecond)), |
+ flush_period_(base::TimeDelta::FromSecondsD( |
+ 1.f / |
+ std::min(max_sent_messages_per_second, kReasonableFlushesPerSecond))), |
+ sent_messages_since_last_flush_(0), |
+ flush_timer_(FROM_HERE, |
Sami
2015/01/13 14:47:35
I wonder if we should build some kind of use-idle-
rmcilroy
2015/01/13 15:24:37
I like this idea (if not the name... ;). How abou
jdduke (slow)
2015/01/13 16:18:11
All solid options, I'm open to whatever you all th
|
+ flush_period_, |
+ base::Bind(&ThrottledMessageSender::FlushThrottled, |
+ base::Unretained(this)), |
+ false /* is_repeating */), |
+ is_sending_via_proxied_(false) { |
+ DCHECK(proxied_sender); |
+ DCHECK(scheduler); |
+ DCHECK_GT(max_sent_messages_per_second, 0); |
+ flush_timer_.SetTaskRunner(scheduler->DefaultTaskRunner()); |
+} |
+ |
+ThrottledMessageSender::~ThrottledMessageSender() { |
+ FlushAll(); |
+ DCHECK(throttled_messages_.empty()); |
+} |
+ |
+bool ThrottledMessageSender::Send(IPC::Message* msg) { |
+ DCHECK(!is_sending_via_proxied_); |
+ thread_checker_.CalledOnValidThread(); |
+ |
+ if (msg->is_sync()) { |
+ FlushAll(); |
+ return SendViaProxiedSender(msg); |
+ } |
+ |
+ if (!throttled_messages_.empty()) { |
+ throttled_messages_.push_back(msg); |
picksi1
2015/01/13 11:24:44
cunning!
|
+ return true; |
+ } |
+ |
+ if (!scheduler_->ShouldYieldForHighPriorityWork()) |
alex clarke (OOO till 29th)
2015/01/13 10:38:02
I think you'd get better results if the scheduler
Sami
2015/01/13 14:47:35
What advantage were you thinking of? This feels li
rmcilroy
2015/01/13 15:24:37
I agree with Sami here - I think this shouldn't be
alex clarke (OOO till 29th)
2015/01/13 15:46:55
As far as I understand it, the intent here is to t
jdduke (slow)
2015/01/13 16:18:11
I agree with Alex here, and was actually going to
|
+ return SendViaProxiedSender(msg); |
+ |
+ if (Now() > (last_sent_message_time_ + flush_period_)) { |
+ // If sufficient time has passed since the previous send, we can effectively |
+ // mark the pipeline as flushed. |
+ sent_messages_since_last_flush_ = 0; |
+ return SendViaProxiedSender(msg); |
+ } |
+ |
+ if (sent_messages_since_last_flush_ < max_sent_messages_per_flush_) |
+ return SendViaProxiedSender(msg); |
+ |
+ throttled_messages_.push_back(msg); |
+ DCHECK(!flush_timer_.IsRunning()); |
+ flush_timer_.Reset(); |
+ return true; |
+} |
+ |
+base::TimeTicks ThrottledMessageSender::Now() const { |
+ return base::TimeTicks::Now(); |
+} |
+ |
+void ThrottledMessageSender::FlushAll() { |
+ sent_messages_since_last_flush_ = 0; |
picksi1
2015/01/13 11:24:44
Can you confirm that there are no threading issues
jdduke (slow)
2015/01/13 16:18:11
Yeah, I've got the |DCHECK(!is_sending_via_proxied
|
+ flush_timer_.Stop(); |
+ |
+ for (auto& msg : throttled_messages_) |
+ SendViaProxiedSender(msg); |
+ throttled_messages_.clear(); |
+} |
+ |
+void ThrottledMessageSender::FlushThrottled() { |
+ sent_messages_since_last_flush_ = 0; |
+ |
+ while (!throttled_messages_.empty() && |
picksi1
2015/01/13 11:24:44
Suggestion for discussion: Rather than checking fo
jdduke (slow)
2015/01/13 16:18:11
That's a solid option, though it would prevent the
|
+ sent_messages_since_last_flush_ < max_sent_messages_per_flush_) { |
+ IPC::Message* msg = throttled_messages_.front(); |
+ throttled_messages_.pop_front(); |
+ SendViaProxiedSender(msg); |
Sami
2015/01/13 14:47:35
Should we yield here too (after sending at least o
jdduke (slow)
2015/01/13 16:18:11
Hmm, the |Send| itself should be fairly cheap (max
|
+ } |
+ |
+ if (!throttled_messages_.empty()) |
+ flush_timer_.Reset(); |
+} |
+ |
+bool ThrottledMessageSender::SendViaProxiedSender(IPC::Message* msg) { |
+ DCHECK(!is_sending_via_proxied_); |
+ base::AutoReset<bool> is_sending_via_proxied_resetter( |
+ &is_sending_via_proxied_, true); |
+ last_sent_message_time_ = Now(); |
+ ++sent_messages_since_last_flush_; |
+ return proxied_sender_->Send(msg); |
+} |
+ |
+} // namespace content |