Add ICU message format support
[chromium-blink-merge.git] / content / renderer / scheduler / resource_dispatch_throttler.cc
blobd2f7916507651fa18cd3e05795a91cb4c8cde255
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/renderer/scheduler/resource_dispatch_throttler.h"
7 #include "base/auto_reset.h"
8 #include "base/trace_event/trace_event.h"
9 #include "components/scheduler/renderer/renderer_scheduler.h"
10 #include "content/common/resource_messages.h"
11 #include "ipc/ipc_message_macros.h"
13 namespace content {
14 namespace {
16 bool IsResourceRequest(const IPC::Message& msg) {
17 return msg.type() == ResourceHostMsg_RequestResource::ID;
20 } // namespace
22 ResourceDispatchThrottler::ResourceDispatchThrottler(
23 IPC::Sender* proxied_sender,
24 scheduler::RendererScheduler* scheduler,
25 base::TimeDelta flush_period,
26 uint32 max_requests_per_flush)
27 : proxied_sender_(proxied_sender),
28 scheduler_(scheduler),
29 flush_period_(flush_period),
30 max_requests_per_flush_(max_requests_per_flush),
31 flush_timer_(
32 FROM_HERE,
33 flush_period_,
34 base::Bind(&ResourceDispatchThrottler::Flush, base::Unretained(this)),
35 false /* is_repeating */),
36 sent_requests_since_last_flush_(0) {
37 DCHECK(proxied_sender);
38 DCHECK(scheduler);
39 DCHECK_NE(flush_period_, base::TimeDelta());
40 DCHECK(max_requests_per_flush_);
41 flush_timer_.SetTaskRunner(scheduler->LoadingTaskRunner());
44 ResourceDispatchThrottler::~ResourceDispatchThrottler() {
45 FlushAll();
48 bool ResourceDispatchThrottler::Send(IPC::Message* msg) {
49 DCHECK(thread_checker_.CalledOnValidThread());
50 if (msg->is_sync()) {
51 // Flush any pending requests, preserving dispatch order between async and
52 // sync requests.
53 FlushAll();
54 return ForwardMessage(msg);
57 // Always defer message forwarding if there are pending messages, ensuring
58 // message dispatch ordering consistency.
59 if (!throttled_messages_.empty()) {
60 TRACE_EVENT_INSTANT0("loader", "ResourceDispatchThrottler::ThrottleMessage",
61 TRACE_EVENT_SCOPE_THREAD);
62 throttled_messages_.push_back(msg);
63 return true;
66 if (!IsResourceRequest(*msg))
67 return ForwardMessage(msg);
69 if (!scheduler_->IsHighPriorityWorkAnticipated())
70 return ForwardMessage(msg);
72 if (Now() > (last_sent_request_time_ + flush_period_)) {
73 // If sufficient time has passed since the previous send, we can effectively
74 // mark the pipeline as flushed.
75 sent_requests_since_last_flush_ = 0;
76 return ForwardMessage(msg);
79 if (sent_requests_since_last_flush_ < max_requests_per_flush_)
80 return ForwardMessage(msg);
82 TRACE_EVENT_INSTANT0("loader", "ResourceDispatchThrottler::ThrottleRequest",
83 TRACE_EVENT_SCOPE_THREAD);
84 throttled_messages_.push_back(msg);
85 ScheduleFlush();
86 return true;
89 base::TimeTicks ResourceDispatchThrottler::Now() const {
90 return base::TimeTicks::Now();
93 void ResourceDispatchThrottler::ScheduleFlush() {
94 DCHECK(!flush_timer_.IsRunning());
95 flush_timer_.Reset();
98 void ResourceDispatchThrottler::Flush() {
99 DCHECK(thread_checker_.CalledOnValidThread());
100 TRACE_EVENT1("loader", "ResourceDispatchThrottler::Flush",
101 "total_throttled_messages", throttled_messages_.size());
102 sent_requests_since_last_flush_ = 0;
104 // If high-priority work is no longer anticipated, dispatch can be safely
105 // accelerated. Avoid completely flushing in such case in the event that
106 // a large number of requests have been throttled.
107 uint32 max_requests = scheduler_->IsHighPriorityWorkAnticipated()
108 ? max_requests_per_flush_
109 : max_requests_per_flush_ * 2;
111 while (!throttled_messages_.empty() &&
112 (sent_requests_since_last_flush_ < max_requests ||
113 !IsResourceRequest(*throttled_messages_.front()))) {
114 IPC::Message* msg = throttled_messages_.front();
115 throttled_messages_.pop_front();
116 ForwardMessage(msg);
119 if (!throttled_messages_.empty())
120 ScheduleFlush();
123 void ResourceDispatchThrottler::FlushAll() {
124 if (throttled_messages_.empty())
125 return;
127 TRACE_EVENT1("loader", "ResourceDispatchThrottler::FlushAll",
128 "total_throttled_messages", throttled_messages_.size());
129 std::deque<IPC::Message*> throttled_messages;
130 throttled_messages.swap(throttled_messages_);
131 for (auto& message : throttled_messages)
132 ForwardMessage(message);
133 // There shouldn't be re-entrancy issues when forwarding an IPC, but validate
134 // as a safeguard.
135 DCHECK(throttled_messages_.empty());
138 bool ResourceDispatchThrottler::ForwardMessage(IPC::Message* msg) {
139 if (IsResourceRequest(*msg)) {
140 last_sent_request_time_ = Now();
141 ++sent_requests_since_last_flush_;
143 return proxied_sender_->Send(msg);
146 } // namespace content