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

Side by Side Diff: third_party/WebKit/Source/platform/scheduler/renderer/task_queue_throttler.cc

Issue 2258133002: [scheduler] Implement time-based cpu throttling. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Changed similarity Created 4 years, 3 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
1 // Copyright 2015 The Chromium Authors. All rights reserved. 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 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 #include "platform/scheduler/renderer/throttling_helper.h" 5 #include "platform/scheduler/renderer/task_queue_throttler.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "base/memory/ptr_util.h"
9 #include "base/optional.h"
8 #include "platform/scheduler/base/real_time_domain.h" 10 #include "platform/scheduler/base/real_time_domain.h"
9 #include "platform/scheduler/child/scheduler_tqm_delegate.h" 11 #include "platform/scheduler/child/scheduler_tqm_delegate.h"
10 #include "platform/scheduler/renderer/auto_advancing_virtual_time_domain.h" 12 #include "platform/scheduler/renderer/auto_advancing_virtual_time_domain.h"
11 #include "platform/scheduler/renderer/renderer_scheduler_impl.h" 13 #include "platform/scheduler/renderer/renderer_scheduler_impl.h"
12 #include "platform/scheduler/renderer/throttled_time_domain.h" 14 #include "platform/scheduler/renderer/throttled_time_domain.h"
13 #include "platform/scheduler/renderer/web_frame_scheduler_impl.h" 15 #include "platform/scheduler/renderer/web_frame_scheduler_impl.h"
14 #include "public/platform/WebFrameScheduler.h" 16 #include "public/platform/WebFrameScheduler.h"
15 17
16 namespace blink { 18 namespace blink {
17 namespace scheduler { 19 namespace scheduler {
18 20
19 ThrottlingHelper::ThrottlingHelper(RendererSchedulerImpl* renderer_scheduler, 21 namespace {
20 const char* tracing_category) 22 const base::TimeDelta kMaxTimeBudget = base::TimeDelta::FromSeconds(1);
Sami 2016/09/07 15:20:43 No static global non-pod constructors please.
altimin 2016/09/09 15:43:58 Done.
23 }
24
25 TaskQueueThrottler::TimeBudgetPool::TimeBudgetPool(
26 TaskQueueThrottler* task_queue_throttler,
27 base::TimeTicks now)
28 : task_queue_throttler_(task_queue_throttler),
29 last_checkpoint_(now),
30 cpu_percentage_(1) {}
31
32 TaskQueueThrottler::TimeBudgetPool::~TimeBudgetPool() {}
33
34 void TaskQueueThrottler::TimeBudgetPool::SetTimeBudget(double cpu_percentage) {
35 cpu_percentage_ = cpu_percentage;
36 current_budget_level_ = base::TimeDelta();
37 }
38
39 void TaskQueueThrottler::TimeBudgetPool::AddQueue(TaskQueue* queue) {
40 DCHECK(task_queue_throttler_->time_budget_pool_for_queue_.find(queue) ==
41 task_queue_throttler_->time_budget_pool_for_queue_.end());
42 task_queue_throttler_->time_budget_pool_for_queue_[queue] = this;
Sami 2016/09/07 15:20:43 Do we need to disable the queue if the budget has
altimin 2016/09/09 15:43:58 Done.
43 }
44
45 void TaskQueueThrottler::TimeBudgetPool::RemoveQueue(TaskQueue* queue) {
46 DCHECK_EQ(task_queue_throttler_->time_budget_pool_for_queue_[queue], this);
47 task_queue_throttler_->time_budget_pool_for_queue_.erase(queue);
Sami 2016/09/07 15:20:43 Do we need to re-enable the queue?
altimin 2016/09/09 15:43:58 Done.
48 }
49
50 void TaskQueueThrottler::TimeBudgetPool::Close() {
51 task_queue_throttler_->time_budget_pools_.erase(this);
52 }
53
54 bool TaskQueueThrottler::TimeBudgetPool::IsAllowedToRun(base::TimeTicks now) {
55 if (now > last_checkpoint_) {
56 current_budget_level_ = std::min(
57 current_budget_level_ + cpu_percentage_ * (now - last_checkpoint_),
58 kMaxTimeBudget);
59 last_checkpoint_ = now;
60 }
61
62 return current_budget_level_.InMicroseconds() >= 0;
63 }
64
65 base::TimeTicks TaskQueueThrottler::TimeBudgetPool::NextAllowedRunTime() {
66 if (current_budget_level_.InMicroseconds() >= 0) {
67 return last_checkpoint_;
68 } else {
69 // Subtract because current_budget is negative.
70 return last_checkpoint_ - current_budget_level_ / cpu_percentage_;
71 }
72 }
73
74 void TaskQueueThrottler::TimeBudgetPool::RecordTaskRunTime(
75 base::TimeDelta task_run_time) {
76 current_budget_level_ -= task_run_time;
77 }
78
79 TaskQueueThrottler::TaskQueueThrottler(
80 RendererSchedulerImpl* renderer_scheduler,
81 const char* tracing_category)
21 : task_runner_(renderer_scheduler->ControlTaskRunner()), 82 : task_runner_(renderer_scheduler->ControlTaskRunner()),
22 renderer_scheduler_(renderer_scheduler), 83 renderer_scheduler_(renderer_scheduler),
23 tick_clock_(renderer_scheduler->tick_clock()), 84 tick_clock_(renderer_scheduler->tick_clock()),
24 tracing_category_(tracing_category), 85 tracing_category_(tracing_category),
25 time_domain_(new ThrottledTimeDomain(this, tracing_category)), 86 time_domain_(new ThrottledTimeDomain(this, tracing_category)),
26 virtual_time_(false), 87 virtual_time_(false),
27 weak_factory_(this) { 88 weak_factory_(this) {
28 pump_throttled_tasks_closure_.Reset(base::Bind( 89 pump_throttled_tasks_closure_.Reset(base::Bind(
29 &ThrottlingHelper::PumpThrottledTasks, weak_factory_.GetWeakPtr())); 90 &TaskQueueThrottler::PumpThrottledTasks, weak_factory_.GetWeakPtr()));
30 forward_immediate_work_closure_ = 91 forward_immediate_work_closure_ =
31 base::Bind(&ThrottlingHelper::OnTimeDomainHasImmediateWork, 92 base::Bind(&TaskQueueThrottler::OnTimeDomainHasImmediateWork,
32 weak_factory_.GetWeakPtr()); 93 weak_factory_.GetWeakPtr());
33 94
34 renderer_scheduler_->RegisterTimeDomain(time_domain_.get()); 95 renderer_scheduler_->RegisterTimeDomain(time_domain_.get());
35 } 96 }
36 97
37 ThrottlingHelper::~ThrottlingHelper() { 98 TaskQueueThrottler::~TaskQueueThrottler() {
38 // It's possible for queues to be still throttled, so we need to tidy up 99 // It's possible for queues to be still throttled, so we need to tidy up
39 // before unregistering the time domain. 100 // before unregistering the time domain.
40 for (const TaskQueueMap::value_type& map_entry : throttled_queues_) { 101 for (const TaskQueueMap::value_type& map_entry : throttled_queues_) {
41 TaskQueue* task_queue = map_entry.first; 102 TaskQueue* task_queue = map_entry.first;
42 task_queue->SetTimeDomain(renderer_scheduler_->real_time_domain()); 103 task_queue->SetTimeDomain(renderer_scheduler_->real_time_domain());
43 task_queue->RemoveFence(); 104 task_queue->RemoveFence();
44 } 105 }
45 106
46 renderer_scheduler_->UnregisterTimeDomain(time_domain_.get()); 107 renderer_scheduler_->UnregisterTimeDomain(time_domain_.get());
47 } 108 }
48 109
49 void ThrottlingHelper::SetQueueEnabled(TaskQueue* task_queue, bool enabled) { 110 void TaskQueueThrottler::SetQueueEnabled(TaskQueue* task_queue, bool enabled) {
50 TaskQueueMap::iterator find_it = throttled_queues_.find(task_queue); 111 TaskQueueMap::iterator find_it = throttled_queues_.find(task_queue);
51 112
52 if (find_it == throttled_queues_.end()) { 113 if (find_it == throttled_queues_.end()) {
53 task_queue->SetQueueEnabled(enabled); 114 task_queue->SetQueueEnabled(enabled);
54 return; 115 return;
55 } 116 }
56 117
57 find_it->second.enabled = enabled; 118 find_it->second.enabled = enabled;
58 119
59 // We don't enable the queue here because it's throttled and there might be 120 // We don't enable the queue here because it's throttled and there might be
60 // tasks in it's work queue that would execute immediatly rather than after 121 // tasks in it's work queue that would execute immediatly rather than after
61 // PumpThrottledTasks runs. 122 // PumpThrottledTasks runs.
62 if (!enabled) 123 if (!enabled)
63 task_queue->SetQueueEnabled(false); 124 task_queue->SetQueueEnabled(false);
64 } 125 }
65 126
66 void ThrottlingHelper::IncreaseThrottleRefCount(TaskQueue* task_queue) { 127 void TaskQueueThrottler::IncreaseThrottleRefCount(TaskQueue* task_queue) {
67 DCHECK_NE(task_queue, task_runner_.get()); 128 DCHECK_NE(task_queue, task_runner_.get());
68 129
69 if (virtual_time_) 130 if (virtual_time_)
70 return; 131 return;
71 132
72 std::pair<TaskQueueMap::iterator, bool> insert_result = 133 std::pair<TaskQueueMap::iterator, bool> insert_result =
73 throttled_queues_.insert(std::make_pair( 134 throttled_queues_.insert(std::make_pair(
74 task_queue, Metadata(1, task_queue->IsQueueEnabled()))); 135 task_queue, Metadata(1, task_queue->IsQueueEnabled())));
75 136
76 if (insert_result.second) { 137 if (insert_result.second) {
77 // The insert was succesful so we need to throttle the queue. 138 // The insert was successful so we need to throttle the queue.
78 task_queue->SetTimeDomain(time_domain_.get()); 139 task_queue->SetTimeDomain(time_domain_.get());
79 task_queue->RemoveFence(); 140 task_queue->RemoveFence();
80 task_queue->SetQueueEnabled(false); 141 task_queue->SetQueueEnabled(false);
81 142
82 if (!task_queue->IsEmpty()) { 143 if (!task_queue->IsEmpty()) {
83 if (task_queue->HasPendingImmediateWork()) { 144 if (task_queue->HasPendingImmediateWork()) {
84 OnTimeDomainHasImmediateWork(); 145 OnTimeDomainHasImmediateWork();
85 } else { 146 } else {
86 OnTimeDomainHasDelayedWork(); 147 OnTimeDomainHasDelayedWork();
87 } 148 }
88 } 149 }
89 } else { 150 } else {
90 // An entry already existed in the map so we need to increment the refcount. 151 // An entry already existed in the map so we need to increment the refcount.
91 insert_result.first->second.throttling_ref_count++; 152 insert_result.first->second.throttling_ref_count++;
92 } 153 }
93 } 154 }
94 155
95 void ThrottlingHelper::DecreaseThrottleRefCount(TaskQueue* task_queue) { 156 void TaskQueueThrottler::DecreaseThrottleRefCount(TaskQueue* task_queue) {
96 if (virtual_time_) 157 if (virtual_time_)
97 return; 158 return;
98 159
99 TaskQueueMap::iterator iter = throttled_queues_.find(task_queue); 160 TaskQueueMap::iterator iter = throttled_queues_.find(task_queue);
100 161
101 if (iter != throttled_queues_.end() && 162 if (iter != throttled_queues_.end() &&
102 --iter->second.throttling_ref_count == 0) { 163 --iter->second.throttling_ref_count == 0) {
103 bool enabled = iter->second.enabled; 164 bool enabled = iter->second.enabled;
104 // The refcount has become zero, we need to unthrottle the queue. 165 // The refcount has become zero, we need to unthrottle the queue.
105 throttled_queues_.erase(iter); 166 throttled_queues_.erase(iter);
106 167
107 task_queue->SetTimeDomain(renderer_scheduler_->real_time_domain()); 168 task_queue->SetTimeDomain(renderer_scheduler_->real_time_domain());
108 task_queue->RemoveFence(); 169 task_queue->RemoveFence();
109 task_queue->SetQueueEnabled(enabled); 170 task_queue->SetQueueEnabled(enabled);
110 } 171 }
111 } 172 }
112 173
113 bool ThrottlingHelper::IsThrottled(TaskQueue* task_queue) const { 174 bool TaskQueueThrottler::IsThrottled(TaskQueue* task_queue) const {
114 return throttled_queues_.find(task_queue) != throttled_queues_.end(); 175 return throttled_queues_.find(task_queue) != throttled_queues_.end();
115 } 176 }
116 177
117 void ThrottlingHelper::UnregisterTaskQueue(TaskQueue* task_queue) { 178 void TaskQueueThrottler::UnregisterTaskQueue(TaskQueue* task_queue) {
118 throttled_queues_.erase(task_queue); 179 throttled_queues_.erase(task_queue);
119 } 180 }
120 181
121 void ThrottlingHelper::OnTimeDomainHasImmediateWork() { 182 void TaskQueueThrottler::OnTimeDomainHasImmediateWork() {
122 // Forward to the main thread if called from another thread. 183 // Forward to the main thread if called from another thread.
123 if (!task_runner_->RunsTasksOnCurrentThread()) { 184 if (!task_runner_->RunsTasksOnCurrentThread()) {
124 task_runner_->PostTask(FROM_HERE, forward_immediate_work_closure_); 185 task_runner_->PostTask(FROM_HERE, forward_immediate_work_closure_);
125 return; 186 return;
126 } 187 }
127 TRACE_EVENT0(tracing_category_, 188 TRACE_EVENT0(tracing_category_,
128 "ThrottlingHelper::OnTimeDomainHasImmediateWork"); 189 "TaskQueueThrottler::OnTimeDomainHasImmediateWork");
129 base::TimeTicks now = tick_clock_->NowTicks(); 190 base::TimeTicks now = tick_clock_->NowTicks();
130 MaybeSchedulePumpThrottledTasksLocked(FROM_HERE, now, now); 191 MaybeSchedulePumpThrottledTasks(FROM_HERE, now, now);
131 } 192 }
132 193
133 void ThrottlingHelper::OnTimeDomainHasDelayedWork() { 194 void TaskQueueThrottler::OnTimeDomainHasDelayedWork() {
134 TRACE_EVENT0(tracing_category_, 195 TRACE_EVENT0(tracing_category_,
135 "ThrottlingHelper::OnTimeDomainHasDelayedWork"); 196 "TaskQueueThrottler::OnTimeDomainHasDelayedWork");
136 base::TimeTicks next_scheduled_delayed_task; 197 base::TimeTicks next_scheduled_delayed_task;
137 bool has_delayed_task = 198 bool has_delayed_task =
138 time_domain_->NextScheduledRunTime(&next_scheduled_delayed_task); 199 time_domain_->NextScheduledRunTime(&next_scheduled_delayed_task);
139 DCHECK(has_delayed_task); 200 DCHECK(has_delayed_task);
140 base::TimeTicks now = tick_clock_->NowTicks(); 201 base::TimeTicks now = tick_clock_->NowTicks();
141 MaybeSchedulePumpThrottledTasksLocked(FROM_HERE, now, 202 MaybeSchedulePumpThrottledTasks(FROM_HERE, now, next_scheduled_delayed_task);
142 next_scheduled_delayed_task);
143 } 203 }
144 204
145 void ThrottlingHelper::PumpThrottledTasks() { 205 namespace {
146 TRACE_EVENT0(tracing_category_, "ThrottlingHelper::PumpThrottledTasks");
147 pending_pump_throttled_tasks_runtime_ = base::TimeTicks();
148 206
149 LazyNow lazy_low(tick_clock_); 207 template <class T>
208 T Min(const base::Optional<T>& optional, const T& value) {
209 if (!optional) {
210 return value;
211 }
212 return std::min(optional.value(), value);
213 }
214
215 } // namespace
216
217 void TaskQueueThrottler::PumpThrottledTasks() {
218 TRACE_EVENT0(tracing_category_, "TaskQueueThrottler::PumpThrottledTasks");
219 pending_pump_throttled_tasks_runtime_.reset();
220
221 LazyNow lazy_now(tick_clock_);
222 base::Optional<base::TimeTicks> next_scheduled_delayed_task;
223
150 for (const TaskQueueMap::value_type& map_entry : throttled_queues_) { 224 for (const TaskQueueMap::value_type& map_entry : throttled_queues_) {
151 TaskQueue* task_queue = map_entry.first; 225 TaskQueue* task_queue = map_entry.first;
152 if (!map_entry.second.enabled || task_queue->IsEmpty()) 226 if (!map_entry.second.enabled || task_queue->IsEmpty())
153 continue; 227 continue;
154 228
229 TimeBudgetPool* time_budget_pool = time_budget_pool_for_queue_[task_queue];
230 if (time_budget_pool && !time_budget_pool->IsAllowedToRun(lazy_now.Now())) {
231 base::TimeTicks next_run_time =
232 std::max(time_budget_pool->NextAllowedRunTime(), lazy_now.Now());
233
234 next_scheduled_delayed_task =
235 Min(next_scheduled_delayed_task, next_run_time);
236 continue;
Sami 2016/09/07 15:20:43 Should we add a trace event here so we can see whe
altimin 2016/09/09 15:43:57 Done.
237 }
238
155 task_queue->SetQueueEnabled(true); 239 task_queue->SetQueueEnabled(true);
156 task_queue->InsertFence(); 240 task_queue->InsertFence();
241
242 base::TimeTicks wakeup;
Sami 2016/09/07 15:20:43 nit: wake_up
altimin 2016/09/09 15:43:58 Done.
243 if (task_queue->NextScheduledWakeUp(&wakeup)) {
244 next_scheduled_delayed_task = Min(next_scheduled_delayed_task, wakeup);
245 }
157 } 246 }
158 // Make sure NextScheduledRunTime gives us an up-to date result.
159 time_domain_->ClearExpiredWakeups();
Sami 2016/09/07 15:20:43 Do we need to remove this?
altimin 2016/09/09 15:43:57 Yes, now we don't rely on TimeDomain::NextSchedule
160 247
161 base::TimeTicks next_scheduled_delayed_task; 248 if (next_scheduled_delayed_task) {
162 // Maybe schedule a call to ThrottlingHelper::PumpThrottledTasks if there is 249 MaybeSchedulePumpThrottledTasks(FROM_HERE, lazy_now.Now(),
Sami 2016/09/07 15:20:43 Is this comment still valid?
altimin 2016/09/09 15:43:58 Done.
163 // a pending delayed task. NOTE posting a non-delayed task in the future will 250 *next_scheduled_delayed_task);
164 // result in ThrottlingHelper::OnTimeDomainHasImmediateWork being called.
165 if (time_domain_->NextScheduledRunTime(&next_scheduled_delayed_task)) {
166 MaybeSchedulePumpThrottledTasksLocked(FROM_HERE, lazy_low.Now(),
167 next_scheduled_delayed_task);
168 } 251 }
169 } 252 }
170 253
171 /* static */ 254 /* static */
172 base::TimeTicks ThrottlingHelper::ThrottledRunTime( 255 base::TimeTicks TaskQueueThrottler::AlignedThrottledRunTime(
173 base::TimeTicks unthrottled_runtime) { 256 base::TimeTicks unthrottled_runtime) {
174 const base::TimeDelta one_second = base::TimeDelta::FromSeconds(1); 257 const base::TimeDelta one_second = base::TimeDelta::FromSeconds(1);
175 return unthrottled_runtime + one_second - 258 return unthrottled_runtime + one_second -
176 ((unthrottled_runtime - base::TimeTicks()) % one_second); 259 ((unthrottled_runtime - base::TimeTicks()) % one_second);
177 } 260 }
178 261
179 void ThrottlingHelper::MaybeSchedulePumpThrottledTasksLocked( 262 void TaskQueueThrottler::MaybeSchedulePumpThrottledTasks(
180 const tracked_objects::Location& from_here, 263 const tracked_objects::Location& from_here,
181 base::TimeTicks now, 264 base::TimeTicks now,
182 base::TimeTicks unthrottled_runtime) { 265 base::TimeTicks runtime) {
183 if (virtual_time_) 266 if (virtual_time_)
184 return; 267 return;
185 268
186 base::TimeTicks throttled_runtime = 269 runtime = std::max(now, AlignedThrottledRunTime(runtime));
187 ThrottledRunTime(std::max(now, unthrottled_runtime)); 270
188 // If there is a pending call to PumpThrottledTasks and it's sooner than 271 // If there is a pending call to PumpThrottledTasks and it's sooner than
189 // |unthrottled_runtime| then return. 272 // |runtime| then return.
190 if (!pending_pump_throttled_tasks_runtime_.is_null() && 273 if (pending_pump_throttled_tasks_runtime_ &&
191 throttled_runtime >= pending_pump_throttled_tasks_runtime_) { 274 runtime >= pending_pump_throttled_tasks_runtime_.value()) {
192 return; 275 return;
193 } 276 }
194 277
195 pending_pump_throttled_tasks_runtime_ = throttled_runtime; 278 pending_pump_throttled_tasks_runtime_ = runtime;
196 279
197 pump_throttled_tasks_closure_.Cancel(); 280 pump_throttled_tasks_closure_.Cancel();
198 281
199 base::TimeDelta delay = pending_pump_throttled_tasks_runtime_ - now; 282 base::TimeDelta delay = pending_pump_throttled_tasks_runtime_.value() - now;
200 TRACE_EVENT1(tracing_category_, 283 TRACE_EVENT1(tracing_category_,
201 "ThrottlingHelper::MaybeSchedulePumpThrottledTasksLocked", 284 "TaskQueueThrottler::MaybeSchedulePumpThrottledTasks",
202 "delay_till_next_pump_ms", delay.InMilliseconds()); 285 "delay_till_next_pump_ms", delay.InMilliseconds());
203 task_runner_->PostDelayedTask( 286 task_runner_->PostDelayedTask(
204 from_here, pump_throttled_tasks_closure_.callback(), delay); 287 from_here, pump_throttled_tasks_closure_.callback(), delay);
205 } 288 }
206 289
207 void ThrottlingHelper::EnableVirtualTime() { 290 void TaskQueueThrottler::EnableVirtualTime() {
208 virtual_time_ = true; 291 virtual_time_ = true;
209 292
210 pump_throttled_tasks_closure_.Cancel(); 293 pump_throttled_tasks_closure_.Cancel();
211 294
212 while (!throttled_queues_.empty()) { 295 while (!throttled_queues_.empty()) {
213 TaskQueue* task_queue = throttled_queues_.begin()->first; 296 TaskQueue* task_queue = throttled_queues_.begin()->first;
214 bool enabled = throttled_queues_.begin()->second.enabled; 297 bool enabled = throttled_queues_.begin()->second.enabled;
215 298
216 throttled_queues_.erase(throttled_queues_.begin()); 299 throttled_queues_.erase(throttled_queues_.begin());
217 300
218 task_queue->SetTimeDomain(renderer_scheduler_->GetVirtualTimeDomain()); 301 task_queue->SetTimeDomain(renderer_scheduler_->GetVirtualTimeDomain());
219 task_queue->RemoveFence(); 302 task_queue->RemoveFence();
220 task_queue->SetQueueEnabled(enabled); 303 task_queue->SetQueueEnabled(enabled);
221 } 304 }
222 } 305 }
223 306
307 TaskQueueThrottler::TimeBudgetPool* TaskQueueThrottler::CreateTimeBudgetPool() {
308 TimeBudgetPool* time_budget_pool =
309 new TimeBudgetPool(this, tick_clock_->NowTicks());
310 time_budget_pools_[time_budget_pool] = base::WrapUnique(time_budget_pool);
311 return time_budget_pool;
312 }
313
314 void TaskQueueThrottler::OnTaskRunTimeReported(TaskQueue* task_queue,
315 base::TimeTicks start_time,
316 base::TimeTicks end_time) {
317 auto find_it = throttled_queues_.find(task_queue);
318 if (find_it == throttled_queues_.end()) {
319 return;
320 }
321
322 TimeBudgetPool* time_budget_pool = time_budget_pool_for_queue_[task_queue];
323 if (time_budget_pool) {
Sami 2016/09/07 15:20:43 Can this ever be null?
altimin 2016/09/09 15:43:58 Done.
324 time_budget_pool->RecordTaskRunTime(end_time - start_time);
325 if (!time_budget_pool->IsAllowedToRun(end_time)) {
326 // This task was too expensive and all following tasks are throttled
327 // until explicitly allowed.
328 task_queue->SetQueueEnabled(false);
329
330 base::TimeTicks now = tick_clock_->NowTicks();
Sami 2016/09/07 15:20:43 Could we just use end_time for this? If not, move
altimin 2016/09/09 15:43:58 Done.
331
332 if (task_queue->HasPendingImmediateWork()) {
333 MaybeSchedulePumpThrottledTasks(
334 FROM_HERE, now,
335 std::max(now, time_budget_pool->NextAllowedRunTime()));
336 }
337 }
338 }
339 }
340
224 } // namespace scheduler 341 } // namespace scheduler
225 } // namespace blink 342 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698