Chromium Code Reviews| Index: content/renderer/scheduler/renderer_scheduler_selector.cc |
| diff --git a/content/renderer/scheduler/renderer_scheduler_selector.cc b/content/renderer/scheduler/renderer_scheduler_selector.cc |
| index 4741b705c7f6f6d1114ec68ebfcec4738d236ba0..02c8144cd15fa75e2a7d6d626afe0fa26e1e1fe5 100644 |
| --- a/content/renderer/scheduler/renderer_scheduler_selector.cc |
| +++ b/content/renderer/scheduler/renderer_scheduler_selector.cc |
| @@ -4,21 +4,38 @@ |
| #include "content/renderer/scheduler/renderer_scheduler_selector.h" |
| +#include "base/debug/trace_event_argument.h" |
| #include "base/logging.h" |
| #include "base/pending_task.h" |
| +#include "base/strings/string_number_conversions.h" |
| +#include "content/renderer/scheduler/task_queue_manager.h" |
| namespace content { |
| +RendererSchedulerSelector::Queue::Queue() : work_queue(nullptr), name(nullptr) { |
| +} |
| + |
| RendererSchedulerSelector::RendererSchedulerSelector() : starvation_count_(0) { |
| + TRACE_EVENT_OBJECT_CREATED_WITH_ID( |
| + TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), |
| + "RendererSchedulerSelector", |
| + this); |
| } |
| RendererSchedulerSelector::~RendererSchedulerSelector() { |
| + TRACE_EVENT_OBJECT_DELETED_WITH_ID( |
| + TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), |
| + "RendererSchedulerSelector", |
| + this); |
| } |
| void RendererSchedulerSelector::RegisterWorkQueues( |
| const std::vector<const base::TaskQueue*>& work_queues) { |
| main_thread_checker_.CalledOnValidThread(); |
| - work_queues_ = work_queues; |
| + queues_.clear(); |
| + queues_.resize(work_queues.size()); |
| + for (size_t i = 0; i < work_queues.size(); i++) |
| + queues_[i].work_queue = work_queues[i]; |
|
rmcilroy
2014/10/27 17:51:28
Maybe set a default "unknown" name to avoid segfau
Sami
2014/10/28 12:57:47
I'm only tracing the counter value if the queue ha
|
| for (QueuePriority priority = kFirstQueuePriority; |
| priority < kQueuePriorityCount; |
| priority = NextPriority(priority)) { |
| @@ -33,7 +50,7 @@ void RendererSchedulerSelector::RegisterWorkQueues( |
| void RendererSchedulerSelector::SetQueuePriority(size_t queue_index, |
| QueuePriority priority) { |
| main_thread_checker_.CalledOnValidThread(); |
| - DCHECK_LT(queue_index, work_queues_.size()); |
| + DCHECK_LT(queue_index, queues_.size()); |
| DCHECK_LT(priority, kQueuePriorityCount); |
| DisableQueue(queue_index); |
| queue_priorities_[priority].insert(queue_index); |
| @@ -46,7 +63,7 @@ void RendererSchedulerSelector::EnableQueue(size_t queue_index, |
| void RendererSchedulerSelector::DisableQueue(size_t queue_index) { |
| main_thread_checker_.CalledOnValidThread(); |
| - DCHECK_LT(queue_index, work_queues_.size()); |
| + DCHECK_LT(queue_index, queues_.size()); |
| for (QueuePriority priority = kFirstQueuePriority; |
| priority < kQueuePriorityCount; |
| priority = NextPriority(priority)) { |
| @@ -54,6 +71,13 @@ void RendererSchedulerSelector::DisableQueue(size_t queue_index) { |
| } |
| } |
| +void RendererSchedulerSelector::SetQueueName(size_t queue_index, |
| + const char* name) { |
| + main_thread_checker_.CalledOnValidThread(); |
| + DCHECK_LT(queue_index, queues_.size()); |
| + queues_[queue_index].name = name; |
| +} |
| + |
| bool RendererSchedulerSelector::IsOlder(const base::TaskQueue* queueA, |
| const base::TaskQueue* queueB) { |
| // Note: the comparison is correct due to the fact that the PendingTask |
| @@ -74,11 +98,11 @@ bool RendererSchedulerSelector::ChooseOldestWithPriority( |
| bool found_non_empty_queue = false; |
| size_t chosen_queue = 0; |
| for (int queue_index : queue_priorities_[priority]) { |
| - if (work_queues_[queue_index]->empty()) { |
| + if (queues_[queue_index].work_queue->empty()) { |
| continue; |
| } |
| - if (!found_non_empty_queue || |
| - IsOlder(work_queues_[queue_index], work_queues_[chosen_queue])) { |
| + if (!found_non_empty_queue || IsOlder(queues_[queue_index].work_queue, |
| + queues_[chosen_queue].work_queue)) { |
| found_non_empty_queue = true; |
| chosen_queue = queue_index; |
| } |
| @@ -93,30 +117,97 @@ bool RendererSchedulerSelector::ChooseOldestWithPriority( |
| bool RendererSchedulerSelector::SelectWorkQueueToService( |
| size_t* out_queue_index) { |
| main_thread_checker_.CalledOnValidThread(); |
| - DCHECK(work_queues_.size()); |
| + DCHECK(queues_.size()); |
| + |
| // Always service the control queue if it has any work. |
| if (ChooseOldestWithPriority(kControlPriority, out_queue_index)) { |
| + DidSelectQueue(*out_queue_index, kControlPriority); |
| return true; |
| } |
| // Select from the normal priority queue if we are starving it. |
| if (starvation_count_ >= kMaxStarvationTasks && |
| ChooseOldestWithPriority(kNormalPriority, out_queue_index)) { |
| - starvation_count_ = 0; |
| + DidSelectQueue(*out_queue_index, kNormalPriority); |
| return true; |
| } |
| // Otherwise choose in priority order. |
| for (QueuePriority priority = kHighPriority; priority < kQueuePriorityCount; |
| priority = NextPriority(priority)) { |
| if (ChooseOldestWithPriority(priority, out_queue_index)) { |
| - if (priority == kHighPriority) { |
| - starvation_count_++; |
| - } else { |
| - starvation_count_ = 0; |
| - } |
| + DidSelectQueue(*out_queue_index, priority); |
| return true; |
| } |
| } |
| return false; |
| } |
| +void RendererSchedulerSelector::DidSelectQueue(size_t selected_queue, |
| + QueuePriority priority) { |
| + TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( |
| + TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), |
| + "RendererSchedulerSelector", |
| + this, |
| + AsValueWithSelectedQueue(selected_queue)); |
| + for (size_t i = 0; i < queues_.size(); i++) { |
| + if (queues_[i].name) |
| + TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), |
| + queues_[i].name, |
| + queues_[i].work_queue->size()); |
| + } |
|
rmcilroy
2014/10/27 17:51:28
Could we encapsulate this tracing code in a functi
picksi1
2014/10/28 11:01:40
Does this all boil away in release builds? I worry
Sami
2014/10/28 12:57:47
Tracing is always compiled in -- having separate b
Sami
2014/10/28 12:57:47
I've now moved this to TQM and it's much cleaner t
|
| + |
| + if (priority == kHighPriority) { |
| + starvation_count_++; |
| + } else if (priority >= kNormalPriority) { |
|
rmcilroy
2014/10/27 17:51:28
This is a bit confusing since ">= normal" sounds l
picksi1
2014/10/28 11:01:40
Or should this be a case statement (following the
Sami
2014/10/28 12:57:47
I suppose a switch case would be more future proof
Sami
2014/10/28 12:57:47
Agreed, done.
|
| + starvation_count_ = 0; |
| + } |
| +} |
| + |
| +scoped_refptr<base::debug::ConvertableToTraceFormat> |
| +RendererSchedulerSelector::AsValueWithSelectedQueue( |
| + size_t selected_queue) const { |
| + main_thread_checker_.CalledOnValidThread(); |
| + scoped_refptr<base::debug::TracedValue> state = |
| + new base::debug::TracedValue(); |
| + state->BeginArray("work_queues"); |
| + for (const auto& queue : queues_) |
| + TaskQueueManager::QueueAsValueInto(*queue.work_queue, state.get()); |
|
rmcilroy
2014/10/27 17:51:28
I'm not sure we should be serializing the taskQueu
Sami
2014/10/28 12:57:47
Yeah, I think I agree with you. Doing it this way
|
| + state->EndArray(); |
| + state->SetInteger("selected_queue", selected_queue); |
| + AsValueInto(state.get()); |
| + return state; |
| +} |
| + |
| +// static |
| +const char* RendererSchedulerSelector::PriorityToString( |
| + QueuePriority priority) { |
| + switch (priority) { |
| + case kControlPriority: |
| + return "control"; |
| + case kHighPriority: |
| + return "high"; |
| + case kNormalPriority: |
| + return "normal"; |
| + case kBestEffortPriority: |
| + return "best_effort"; |
| + default: |
| + NOTREACHED(); |
| + return nullptr; |
| + } |
| +} |
| + |
| +void RendererSchedulerSelector::AsValueInto( |
| + base::debug::TracedValue* state) const { |
| + main_thread_checker_.CalledOnValidThread(); |
| + state->BeginDictionary("priorities"); |
| + for (QueuePriority priority = kHighPriority; priority < kQueuePriorityCount; |
|
rmcilroy
2014/10/27 17:51:28
Should we not expose the control priority here?
Sami
2014/10/28 12:57:47
Ack, bad copy & paste. Thanks.
|
| + priority = NextPriority(priority)) { |
| + state->BeginArray(PriorityToString(priority)); |
| + for (size_t queue_index : queue_priorities_[priority]) |
| + state->AppendInteger(queue_index); |
| + state->EndArray(); |
| + } |
| + state->EndDictionary(); |
| + state->SetInteger("starvation_count", starvation_count_); |
| +} |
| + |
| } // namespace content |