| 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/task_queue_throttler.h" | 5 #include "platform/scheduler/renderer/task_queue_throttler.h" |
| 6 | 6 |
| 7 #include <cstdint> | 7 #include <cstdint> |
| 8 | 8 |
| 9 #include "base/format_macros.h" | 9 #include "base/format_macros.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 169 return find_it->second.throttling_ref_count > 0; | 169 return find_it->second.throttling_ref_count > 0; |
| 170 } | 170 } |
| 171 | 171 |
| 172 void TaskQueueThrottler::UnregisterTaskQueue(TaskQueue* task_queue) { | 172 void TaskQueueThrottler::UnregisterTaskQueue(TaskQueue* task_queue) { |
| 173 LazyNow lazy_now(tick_clock_); | 173 LazyNow lazy_now(tick_clock_); |
| 174 auto find_it = queue_details_.find(task_queue); | 174 auto find_it = queue_details_.find(task_queue); |
| 175 | 175 |
| 176 if (find_it == queue_details_.end()) | 176 if (find_it == queue_details_.end()) |
| 177 return; | 177 return; |
| 178 | 178 |
| 179 if (find_it->second.time_budget_pool) | 179 if (find_it->second.budget_pool) |
| 180 find_it->second.time_budget_pool->RemoveQueue(lazy_now.Now(), task_queue); | 180 find_it->second.budget_pool->RemoveQueue(lazy_now.Now(), task_queue); |
| 181 | 181 |
| 182 queue_details_.erase(find_it); | 182 queue_details_.erase(find_it); |
| 183 } | 183 } |
| 184 | 184 |
| 185 void TaskQueueThrottler::OnTimeDomainHasImmediateWork(TaskQueue* queue) { | 185 void TaskQueueThrottler::OnTimeDomainHasImmediateWork(TaskQueue* queue) { |
| 186 // Forward to the main thread if called from another thread | 186 // Forward to the main thread if called from another thread |
| 187 if (!task_runner_->RunsTasksOnCurrentThread()) { | 187 if (!task_runner_->RunsTasksOnCurrentThread()) { |
| 188 task_runner_->PostTask(FROM_HERE, | 188 task_runner_->PostTask(FROM_HERE, |
| 189 base::Bind(forward_immediate_work_callback_, queue)); | 189 base::Bind(forward_immediate_work_callback_, queue)); |
| 190 return; | 190 return; |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 308 from_here, pump_throttled_tasks_closure_.callback(), delay); | 308 from_here, pump_throttled_tasks_closure_.callback(), delay); |
| 309 } | 309 } |
| 310 | 310 |
| 311 CPUTimeBudgetPool* TaskQueueThrottler::CreateCPUTimeBudgetPool( | 311 CPUTimeBudgetPool* TaskQueueThrottler::CreateCPUTimeBudgetPool( |
| 312 const char* name, | 312 const char* name, |
| 313 base::Optional<base::TimeDelta> max_budget_level, | 313 base::Optional<base::TimeDelta> max_budget_level, |
| 314 base::Optional<base::TimeDelta> max_throttling_duration) { | 314 base::Optional<base::TimeDelta> max_throttling_duration) { |
| 315 CPUTimeBudgetPool* time_budget_pool = | 315 CPUTimeBudgetPool* time_budget_pool = |
| 316 new CPUTimeBudgetPool(name, this, tick_clock_->NowTicks(), | 316 new CPUTimeBudgetPool(name, this, tick_clock_->NowTicks(), |
| 317 max_budget_level, max_throttling_duration); | 317 max_budget_level, max_throttling_duration); |
| 318 time_budget_pools_[time_budget_pool] = base::WrapUnique(time_budget_pool); | 318 budget_pools_[time_budget_pool] = base::WrapUnique(time_budget_pool); |
| 319 return time_budget_pool; | 319 return time_budget_pool; |
| 320 } | 320 } |
| 321 | 321 |
| 322 void TaskQueueThrottler::OnTaskRunTimeReported(TaskQueue* task_queue, | 322 void TaskQueueThrottler::OnTaskRunTimeReported(TaskQueue* task_queue, |
| 323 base::TimeTicks start_time, | 323 base::TimeTicks start_time, |
| 324 base::TimeTicks end_time) { | 324 base::TimeTicks end_time) { |
| 325 if (!IsThrottled(task_queue)) | 325 if (!IsThrottled(task_queue)) |
| 326 return; | 326 return; |
| 327 | 327 |
| 328 CPUTimeBudgetPool* time_budget_pool = GetTimeBudgetPoolForQueue(task_queue); | 328 BudgetPool* budget_pool = GetBudgetPoolForQueue(task_queue); |
| 329 if (!time_budget_pool) | 329 if (!budget_pool) |
| 330 return; | 330 return; |
| 331 | 331 |
| 332 time_budget_pool->RecordTaskRunTime(start_time, end_time); | 332 budget_pool->RecordTaskRunTime(start_time, end_time); |
| 333 if (!time_budget_pool->HasEnoughBudgetToRun(end_time)) | 333 if (!budget_pool->HasEnoughBudgetToRun(end_time)) |
| 334 time_budget_pool->BlockThrottledQueues(end_time); | 334 budget_pool->BlockThrottledQueues(end_time); |
| 335 } |
| 336 |
| 337 void TaskQueueThrottler::BlockThrottledQueue(base::TimeTicks now, |
| 338 TaskQueue* queue) { |
| 339 if (!IsThrottled(queue)) |
| 340 return; |
| 341 |
| 342 queue->InsertFence(TaskQueue::InsertFencePosition::BEGINNING_OF_TIME); |
| 343 SchedulePumpQueue(FROM_HERE, now, queue); |
| 335 } | 344 } |
| 336 | 345 |
| 337 void TaskQueueThrottler::AsValueInto(base::trace_event::TracedValue* state, | 346 void TaskQueueThrottler::AsValueInto(base::trace_event::TracedValue* state, |
| 338 base::TimeTicks now) const { | 347 base::TimeTicks now) const { |
| 339 if (pending_pump_throttled_tasks_runtime_) { | 348 if (pending_pump_throttled_tasks_runtime_) { |
| 340 state->SetDouble( | 349 state->SetDouble( |
| 341 "next_throttled_tasks_pump_in_seconds", | 350 "next_throttled_tasks_pump_in_seconds", |
| 342 (pending_pump_throttled_tasks_runtime_.value() - now).InSecondsF()); | 351 (pending_pump_throttled_tasks_runtime_.value() - now).InSecondsF()); |
| 343 } | 352 } |
| 344 | 353 |
| 345 state->SetBoolean("allow_throttling", allow_throttling_); | 354 state->SetBoolean("allow_throttling", allow_throttling_); |
| 346 | 355 |
| 347 state->BeginDictionary("time_budget_pools"); | 356 state->BeginDictionary("time_budget_pools"); |
| 348 for (const auto& map_entry : time_budget_pools_) { | 357 for (const auto& map_entry : budget_pools_) { |
| 349 BudgetPool* pool = map_entry.first; | 358 BudgetPool* pool = map_entry.first; |
| 350 pool->AsValueInto(state, now); | 359 pool->AsValueInto(state, now); |
| 351 } | 360 } |
| 352 state->EndDictionary(); | 361 state->EndDictionary(); |
| 353 | 362 |
| 354 state->BeginDictionary("queue_details"); | 363 state->BeginDictionary("queue_details"); |
| 355 for (const auto& map_entry : queue_details_) { | 364 for (const auto& map_entry : queue_details_) { |
| 356 state->BeginDictionaryWithCopiedName(PointerToId(map_entry.first)); | 365 state->BeginDictionaryWithCopiedName(PointerToId(map_entry.first)); |
| 357 | 366 |
| 358 state->SetInteger("throttling_ref_count", | 367 state->SetInteger("throttling_ref_count", |
| 359 map_entry.second.throttling_ref_count); | 368 map_entry.second.throttling_ref_count); |
| 360 | 369 |
| 361 state->EndDictionary(); | 370 state->EndDictionary(); |
| 362 } | 371 } |
| 363 state->EndDictionary(); | 372 state->EndDictionary(); |
| 364 } | 373 } |
| 365 | 374 |
| 366 CPUTimeBudgetPool* TaskQueueThrottler::GetTimeBudgetPoolForQueue( | 375 void TaskQueueThrottler::AddQueueToBudgetPool(TaskQueue* queue, |
| 376 BudgetPool* budget_pool) { |
| 377 std::pair<TaskQueueMap::iterator, bool> insert_result = |
| 378 queue_details_.insert(std::make_pair(queue, Metadata())); |
| 379 |
| 380 Metadata& metadata = insert_result.first->second; |
| 381 |
| 382 DCHECK(!metadata.budget_pool); |
| 383 metadata.budget_pool = budget_pool; |
| 384 } |
| 385 |
| 386 void TaskQueueThrottler::RemoveQueueFromBudgetPool(TaskQueue* queue, |
| 387 BudgetPool* budget_pool) { |
| 388 auto find_it = queue_details_.find(queue); |
| 389 DCHECK(find_it != queue_details_.end() && |
| 390 find_it->second.budget_pool == budget_pool); |
| 391 |
| 392 find_it->second.budget_pool = nullptr; |
| 393 |
| 394 MaybeDeleteQueueMetadata(find_it); |
| 395 } |
| 396 |
| 397 void TaskQueueThrottler::UnregisterBudgetPool(BudgetPool* budget_pool) { |
| 398 budget_pools_.erase(budget_pool); |
| 399 } |
| 400 |
| 401 void TaskQueueThrottler::SchedulePumpQueue( |
| 402 const tracked_objects::Location& from_here, |
| 403 base::TimeTicks now, |
| 367 TaskQueue* queue) { | 404 TaskQueue* queue) { |
| 405 if (!IsThrottled(queue)) |
| 406 return; |
| 407 |
| 408 LazyNow lazy_now(now); |
| 409 base::Optional<base::TimeTicks> next_desired_run_time = |
| 410 NextTaskRunTime(&lazy_now, queue); |
| 411 if (!next_desired_run_time) |
| 412 return; |
| 413 |
| 414 base::Optional<base::TimeTicks> next_run_time = |
| 415 Max(next_desired_run_time, GetNextAllowedRunTime(now, queue)); |
| 416 |
| 417 MaybeSchedulePumpThrottledTasks(from_here, now, next_run_time.value()); |
| 418 } |
| 419 |
| 420 BudgetPool* TaskQueueThrottler::GetBudgetPoolForQueue(TaskQueue* queue) { |
| 368 auto find_it = queue_details_.find(queue); | 421 auto find_it = queue_details_.find(queue); |
| 369 if (find_it == queue_details_.end()) | 422 if (find_it == queue_details_.end()) |
| 370 return nullptr; | 423 return nullptr; |
| 371 return find_it->second.time_budget_pool; | 424 return find_it->second.budget_pool; |
| 372 } | |
| 373 | |
| 374 void TaskQueueThrottler::MaybeSchedulePumpQueue( | |
| 375 const tracked_objects::Location& from_here, | |
| 376 base::TimeTicks now, | |
| 377 TaskQueue* queue, | |
| 378 base::Optional<base::TimeTicks> next_possible_run_time) { | |
| 379 LazyNow lazy_now(now); | |
| 380 base::Optional<base::TimeTicks> next_run_time = | |
| 381 Max(NextTaskRunTime(&lazy_now, queue), next_possible_run_time); | |
| 382 | |
| 383 if (next_run_time) { | |
| 384 MaybeSchedulePumpThrottledTasks(from_here, now, next_run_time.value()); | |
| 385 } | |
| 386 } | 425 } |
| 387 | 426 |
| 388 base::TimeTicks TaskQueueThrottler::GetNextAllowedRunTime(base::TimeTicks now, | 427 base::TimeTicks TaskQueueThrottler::GetNextAllowedRunTime(base::TimeTicks now, |
| 389 TaskQueue* queue) { | 428 TaskQueue* queue) { |
| 390 CPUTimeBudgetPool* time_budget_pool = GetTimeBudgetPoolForQueue(queue); | 429 BudgetPool* budget_pool = GetBudgetPoolForQueue(queue); |
| 391 if (!time_budget_pool) | 430 if (!budget_pool) |
| 392 return now; | 431 return now; |
| 393 return std::max(now, time_budget_pool->GetNextAllowedRunTime()); | 432 return std::max(now, budget_pool->GetNextAllowedRunTime()); |
| 394 } | 433 } |
| 395 | 434 |
| 396 void TaskQueueThrottler::MaybeDeleteQueueMetadata(TaskQueueMap::iterator it) { | 435 void TaskQueueThrottler::MaybeDeleteQueueMetadata(TaskQueueMap::iterator it) { |
| 397 if (it->second.throttling_ref_count == 0 && !it->second.time_budget_pool) | 436 if (it->second.throttling_ref_count == 0 && !it->second.budget_pool) |
| 398 queue_details_.erase(it); | 437 queue_details_.erase(it); |
| 399 } | 438 } |
| 400 | 439 |
| 401 void TaskQueueThrottler::DisableThrottling() { | 440 void TaskQueueThrottler::DisableThrottling() { |
| 402 if (!allow_throttling_) | 441 if (!allow_throttling_) |
| 403 return; | 442 return; |
| 404 | 443 |
| 405 allow_throttling_ = false; | 444 allow_throttling_ = false; |
| 406 | 445 |
| 407 for (const auto& map_entry : queue_details_) { | 446 for (const auto& map_entry : queue_details_) { |
| (...skipping 24 matching lines...) Expand all Loading... |
| 432 for (const auto& map_entry : queue_details_) { | 471 for (const auto& map_entry : queue_details_) { |
| 433 if (map_entry.second.throttling_ref_count == 0) | 472 if (map_entry.second.throttling_ref_count == 0) |
| 434 continue; | 473 continue; |
| 435 | 474 |
| 436 TaskQueue* queue = map_entry.first; | 475 TaskQueue* queue = map_entry.first; |
| 437 | 476 |
| 438 // Throttling is enabled and task queue should be blocked immediately | 477 // Throttling is enabled and task queue should be blocked immediately |
| 439 // to enforce task alignment. | 478 // to enforce task alignment. |
| 440 queue->InsertFence(TaskQueue::InsertFencePosition::BEGINNING_OF_TIME); | 479 queue->InsertFence(TaskQueue::InsertFencePosition::BEGINNING_OF_TIME); |
| 441 queue->SetTimeDomain(time_domain_.get()); | 480 queue->SetTimeDomain(time_domain_.get()); |
| 442 MaybeSchedulePumpQueue(FROM_HERE, lazy_now.Now(), queue, | 481 SchedulePumpQueue(FROM_HERE, lazy_now.Now(), queue); |
| 443 GetNextAllowedRunTime(lazy_now.Now(), queue)); | |
| 444 } | 482 } |
| 445 | 483 |
| 446 TRACE_EVENT0(tracing_category_, "TaskQueueThrottler_EnableThrottling"); | 484 TRACE_EVENT0(tracing_category_, "TaskQueueThrottler_EnableThrottling"); |
| 447 } | 485 } |
| 448 | 486 |
| 449 } // namespace scheduler | 487 } // namespace scheduler |
| 450 } // namespace blink | 488 } // namespace blink |
| OLD | NEW |