Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 |
| OLD | NEW |