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

Side by Side Diff: components/scheduler/renderer/throttling_helper.cc

Issue 2118903002: scheduler: Move the Blink scheduler into Blink (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebased Created 4 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
(Empty)
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.
4
5 #include "components/scheduler/renderer/throttling_helper.h"
6
7 #include "base/logging.h"
8 #include "components/scheduler/base/real_time_domain.h"
9 #include "components/scheduler/child/scheduler_tqm_delegate.h"
10 #include "components/scheduler/renderer/auto_advancing_virtual_time_domain.h"
11 #include "components/scheduler/renderer/renderer_scheduler_impl.h"
12 #include "components/scheduler/renderer/throttled_time_domain.h"
13 #include "components/scheduler/renderer/web_frame_scheduler_impl.h"
14 #include "third_party/WebKit/public/platform/WebFrameScheduler.h"
15
16 namespace scheduler {
17
18 ThrottlingHelper::ThrottlingHelper(RendererSchedulerImpl* renderer_scheduler,
19 const char* tracing_category)
20 : task_runner_(renderer_scheduler->ControlTaskRunner()),
21 renderer_scheduler_(renderer_scheduler),
22 tick_clock_(renderer_scheduler->tick_clock()),
23 tracing_category_(tracing_category),
24 time_domain_(new ThrottledTimeDomain(this, tracing_category)),
25 virtual_time_(false),
26 weak_factory_(this) {
27 pump_throttled_tasks_closure_.Reset(base::Bind(
28 &ThrottlingHelper::PumpThrottledTasks, weak_factory_.GetWeakPtr()));
29 forward_immediate_work_closure_ =
30 base::Bind(&ThrottlingHelper::OnTimeDomainHasImmediateWork,
31 weak_factory_.GetWeakPtr());
32
33 renderer_scheduler_->RegisterTimeDomain(time_domain_.get());
34 }
35
36 ThrottlingHelper::~ThrottlingHelper() {
37 // It's possible for queues to be still throttled, so we need to tidy up
38 // before unregistering the time domain.
39 for (const TaskQueueMap::value_type& map_entry : throttled_queues_) {
40 TaskQueue* task_queue = map_entry.first;
41 task_queue->SetTimeDomain(renderer_scheduler_->real_time_domain());
42 task_queue->SetPumpPolicy(TaskQueue::PumpPolicy::AUTO);
43 }
44
45 renderer_scheduler_->UnregisterTimeDomain(time_domain_.get());
46 }
47
48 void ThrottlingHelper::SetQueueEnabled(TaskQueue* task_queue, bool enabled) {
49 TaskQueueMap::iterator find_it = throttled_queues_.find(task_queue);
50
51 if (find_it == throttled_queues_.end()) {
52 task_queue->SetQueueEnabled(enabled);
53 return;
54 }
55
56 find_it->second.enabled = enabled;
57
58 // We don't enable the queue here because it's throttled and there might be
59 // tasks in it's work queue that would execute immediatly rather than after
60 // PumpThrottledTasks runs.
61 if (!enabled)
62 task_queue->SetQueueEnabled(false);
63 }
64
65 void ThrottlingHelper::IncreaseThrottleRefCount(TaskQueue* task_queue) {
66 DCHECK_NE(task_queue, task_runner_.get());
67
68 if (virtual_time_)
69 return;
70
71 std::pair<TaskQueueMap::iterator, bool> insert_result =
72 throttled_queues_.insert(std::make_pair(
73 task_queue, Metadata(1, task_queue->IsQueueEnabled())));
74
75 if (insert_result.second) {
76 // The insert was succesful so we need to throttle the queue.
77 task_queue->SetTimeDomain(time_domain_.get());
78 task_queue->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL);
79 task_queue->SetQueueEnabled(false);
80
81 if (!task_queue->IsEmpty()) {
82 if (task_queue->HasPendingImmediateWork()) {
83 OnTimeDomainHasImmediateWork();
84 } else {
85 OnTimeDomainHasDelayedWork();
86 }
87 }
88 } else {
89 // An entry already existed in the map so we need to increment the refcount.
90 insert_result.first->second.throttling_ref_count++;
91 }
92 }
93
94 void ThrottlingHelper::DecreaseThrottleRefCount(TaskQueue* task_queue) {
95 if (virtual_time_)
96 return;
97
98 TaskQueueMap::iterator iter = throttled_queues_.find(task_queue);
99
100 if (iter != throttled_queues_.end() &&
101 --iter->second.throttling_ref_count == 0) {
102 bool enabled = iter->second.enabled;
103 // The refcount has become zero, we need to unthrottle the queue.
104 throttled_queues_.erase(iter);
105
106 task_queue->SetTimeDomain(renderer_scheduler_->real_time_domain());
107 task_queue->SetPumpPolicy(TaskQueue::PumpPolicy::AUTO);
108 task_queue->SetQueueEnabled(enabled);
109 }
110 }
111
112 void ThrottlingHelper::UnregisterTaskQueue(TaskQueue* task_queue) {
113 throttled_queues_.erase(task_queue);
114 }
115
116 void ThrottlingHelper::OnTimeDomainHasImmediateWork() {
117 // Forward to the main thread if called from another thread.
118 if (!task_runner_->RunsTasksOnCurrentThread()) {
119 task_runner_->PostTask(FROM_HERE, forward_immediate_work_closure_);
120 return;
121 }
122 TRACE_EVENT0(tracing_category_,
123 "ThrottlingHelper::OnTimeDomainHasImmediateWork");
124 base::TimeTicks now = tick_clock_->NowTicks();
125 MaybeSchedulePumpThrottledTasksLocked(FROM_HERE, now, now);
126 }
127
128 void ThrottlingHelper::OnTimeDomainHasDelayedWork() {
129 TRACE_EVENT0(tracing_category_,
130 "ThrottlingHelper::OnTimeDomainHasDelayedWork");
131 base::TimeTicks next_scheduled_delayed_task;
132 bool has_delayed_task =
133 time_domain_->NextScheduledRunTime(&next_scheduled_delayed_task);
134 DCHECK(has_delayed_task);
135 base::TimeTicks now = tick_clock_->NowTicks();
136 MaybeSchedulePumpThrottledTasksLocked(FROM_HERE, now,
137 next_scheduled_delayed_task);
138 }
139
140 void ThrottlingHelper::PumpThrottledTasks() {
141 TRACE_EVENT0(tracing_category_, "ThrottlingHelper::PumpThrottledTasks");
142 pending_pump_throttled_tasks_runtime_ = base::TimeTicks();
143
144 LazyNow lazy_low(tick_clock_);
145 for (const TaskQueueMap::value_type& map_entry : throttled_queues_) {
146 TaskQueue* task_queue = map_entry.first;
147 if (task_queue->IsEmpty())
148 continue;
149
150 task_queue->SetQueueEnabled(map_entry.second.enabled);
151 task_queue->PumpQueue(&lazy_low, false);
152 }
153 // Make sure NextScheduledRunTime gives us an up-to date result.
154 time_domain_->ClearExpiredWakeups();
155
156 base::TimeTicks next_scheduled_delayed_task;
157 // Maybe schedule a call to ThrottlingHelper::PumpThrottledTasks if there is
158 // a pending delayed task. NOTE posting a non-delayed task in the future will
159 // result in ThrottlingHelper::OnTimeDomainHasImmediateWork being called.
160 if (time_domain_->NextScheduledRunTime(&next_scheduled_delayed_task)) {
161 MaybeSchedulePumpThrottledTasksLocked(FROM_HERE, lazy_low.Now(),
162 next_scheduled_delayed_task);
163 }
164 }
165
166 /* static */
167 base::TimeTicks ThrottlingHelper::ThrottledRunTime(
168 base::TimeTicks unthrottled_runtime) {
169 const base::TimeDelta one_second = base::TimeDelta::FromSeconds(1);
170 return unthrottled_runtime + one_second -
171 ((unthrottled_runtime - base::TimeTicks()) % one_second);
172 }
173
174 void ThrottlingHelper::MaybeSchedulePumpThrottledTasksLocked(
175 const tracked_objects::Location& from_here,
176 base::TimeTicks now,
177 base::TimeTicks unthrottled_runtime) {
178 if (virtual_time_)
179 return;
180
181 base::TimeTicks throttled_runtime =
182 ThrottledRunTime(std::max(now, unthrottled_runtime));
183 // If there is a pending call to PumpThrottledTasks and it's sooner than
184 // |unthrottled_runtime| then return.
185 if (!pending_pump_throttled_tasks_runtime_.is_null() &&
186 throttled_runtime >= pending_pump_throttled_tasks_runtime_) {
187 return;
188 }
189
190 pending_pump_throttled_tasks_runtime_ = throttled_runtime;
191
192 pump_throttled_tasks_closure_.Cancel();
193
194 base::TimeDelta delay = pending_pump_throttled_tasks_runtime_ - now;
195 TRACE_EVENT1(tracing_category_,
196 "ThrottlingHelper::MaybeSchedulePumpThrottledTasksLocked",
197 "delay_till_next_pump_ms", delay.InMilliseconds());
198 task_runner_->PostDelayedTask(
199 from_here, pump_throttled_tasks_closure_.callback(), delay);
200 }
201
202 void ThrottlingHelper::EnableVirtualTime() {
203 virtual_time_ = true;
204
205 pump_throttled_tasks_closure_.Cancel();
206
207 while (!throttled_queues_.empty()) {
208 TaskQueue* task_queue = throttled_queues_.begin()->first;
209 bool enabled = throttled_queues_.begin()->second.enabled;
210
211 throttled_queues_.erase(throttled_queues_.begin());
212
213 task_queue->SetTimeDomain(renderer_scheduler_->GetVirtualTimeDomain());
214 task_queue->SetPumpPolicy(TaskQueue::PumpPolicy::AUTO);
215 task_queue->SetQueueEnabled(enabled);
216 }
217 }
218
219 } // namespace scheduler
OLDNEW
« no previous file with comments | « components/scheduler/renderer/throttling_helper.h ('k') | components/scheduler/renderer/throttling_helper_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698