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

Side by Side Diff: content/renderer/scheduler/renderer_scheduler_selector.cc

Issue 681793003: scheduler: Add support for tracing scheduler state (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 1 month 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 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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 "content/renderer/scheduler/renderer_scheduler_selector.h" 5 #include "content/renderer/scheduler/renderer_scheduler_selector.h"
6 6
7 #include "base/debug/trace_event_argument.h"
7 #include "base/logging.h" 8 #include "base/logging.h"
8 #include "base/pending_task.h" 9 #include "base/pending_task.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "content/renderer/scheduler/task_queue_manager.h"
9 12
10 namespace content { 13 namespace content {
11 14
15 RendererSchedulerSelector::Queue::Queue() : work_queue(nullptr), name(nullptr) {
16 }
17
12 RendererSchedulerSelector::RendererSchedulerSelector() : starvation_count_(0) { 18 RendererSchedulerSelector::RendererSchedulerSelector() : starvation_count_(0) {
19 TRACE_EVENT_OBJECT_CREATED_WITH_ID(
20 TRACE_DISABLED_BY_DEFAULT("blink.scheduler"),
21 "RendererSchedulerSelector",
22 this);
13 } 23 }
14 24
15 RendererSchedulerSelector::~RendererSchedulerSelector() { 25 RendererSchedulerSelector::~RendererSchedulerSelector() {
26 TRACE_EVENT_OBJECT_DELETED_WITH_ID(
27 TRACE_DISABLED_BY_DEFAULT("blink.scheduler"),
28 "RendererSchedulerSelector",
29 this);
16 } 30 }
17 31
18 void RendererSchedulerSelector::RegisterWorkQueues( 32 void RendererSchedulerSelector::RegisterWorkQueues(
19 const std::vector<const base::TaskQueue*>& work_queues) { 33 const std::vector<const base::TaskQueue*>& work_queues) {
20 main_thread_checker_.CalledOnValidThread(); 34 main_thread_checker_.CalledOnValidThread();
21 work_queues_ = work_queues; 35 queues_.clear();
36 queues_.resize(work_queues.size());
37 for (size_t i = 0; i < work_queues.size(); i++)
38 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
22 for (QueuePriority priority = kFirstQueuePriority; 39 for (QueuePriority priority = kFirstQueuePriority;
23 priority < kQueuePriorityCount; 40 priority < kQueuePriorityCount;
24 priority = NextPriority(priority)) { 41 priority = NextPriority(priority)) {
25 queue_priorities_[priority].clear(); 42 queue_priorities_[priority].clear();
26 } 43 }
27 // By default, all work queues are set to normal priority. 44 // By default, all work queues are set to normal priority.
28 for (size_t i = 0; i < work_queues.size(); i++) { 45 for (size_t i = 0; i < work_queues.size(); i++) {
29 queue_priorities_[kNormalPriority].insert(i); 46 queue_priorities_[kNormalPriority].insert(i);
30 } 47 }
31 } 48 }
32 49
33 void RendererSchedulerSelector::SetQueuePriority(size_t queue_index, 50 void RendererSchedulerSelector::SetQueuePriority(size_t queue_index,
34 QueuePriority priority) { 51 QueuePriority priority) {
35 main_thread_checker_.CalledOnValidThread(); 52 main_thread_checker_.CalledOnValidThread();
36 DCHECK_LT(queue_index, work_queues_.size()); 53 DCHECK_LT(queue_index, queues_.size());
37 DCHECK_LT(priority, kQueuePriorityCount); 54 DCHECK_LT(priority, kQueuePriorityCount);
38 DisableQueue(queue_index); 55 DisableQueue(queue_index);
39 queue_priorities_[priority].insert(queue_index); 56 queue_priorities_[priority].insert(queue_index);
40 } 57 }
41 58
42 void RendererSchedulerSelector::EnableQueue(size_t queue_index, 59 void RendererSchedulerSelector::EnableQueue(size_t queue_index,
43 QueuePriority priority) { 60 QueuePriority priority) {
44 SetQueuePriority(queue_index, priority); 61 SetQueuePriority(queue_index, priority);
45 } 62 }
46 63
47 void RendererSchedulerSelector::DisableQueue(size_t queue_index) { 64 void RendererSchedulerSelector::DisableQueue(size_t queue_index) {
48 main_thread_checker_.CalledOnValidThread(); 65 main_thread_checker_.CalledOnValidThread();
49 DCHECK_LT(queue_index, work_queues_.size()); 66 DCHECK_LT(queue_index, queues_.size());
50 for (QueuePriority priority = kFirstQueuePriority; 67 for (QueuePriority priority = kFirstQueuePriority;
51 priority < kQueuePriorityCount; 68 priority < kQueuePriorityCount;
52 priority = NextPriority(priority)) { 69 priority = NextPriority(priority)) {
53 queue_priorities_[priority].erase(queue_index); 70 queue_priorities_[priority].erase(queue_index);
54 } 71 }
55 } 72 }
56 73
74 void RendererSchedulerSelector::SetQueueName(size_t queue_index,
75 const char* name) {
76 main_thread_checker_.CalledOnValidThread();
77 DCHECK_LT(queue_index, queues_.size());
78 queues_[queue_index].name = name;
79 }
80
57 bool RendererSchedulerSelector::IsOlder(const base::TaskQueue* queueA, 81 bool RendererSchedulerSelector::IsOlder(const base::TaskQueue* queueA,
58 const base::TaskQueue* queueB) { 82 const base::TaskQueue* queueB) {
59 // Note: the comparison is correct due to the fact that the PendingTask 83 // Note: the comparison is correct due to the fact that the PendingTask
60 // operator inverts its comparison operation in order to work well in a heap 84 // operator inverts its comparison operation in order to work well in a heap
61 // based priority queue. 85 // based priority queue.
62 return queueB->front() < queueA->front(); 86 return queueB->front() < queueA->front();
63 } 87 }
64 88
65 RendererSchedulerSelector::QueuePriority 89 RendererSchedulerSelector::QueuePriority
66 RendererSchedulerSelector::NextPriority(QueuePriority priority) { 90 RendererSchedulerSelector::NextPriority(QueuePriority priority) {
67 DCHECK(priority < kQueuePriorityCount); 91 DCHECK(priority < kQueuePriorityCount);
68 return static_cast<QueuePriority>(static_cast<int>(priority) + 1); 92 return static_cast<QueuePriority>(static_cast<int>(priority) + 1);
69 } 93 }
70 94
71 bool RendererSchedulerSelector::ChooseOldestWithPriority( 95 bool RendererSchedulerSelector::ChooseOldestWithPriority(
72 QueuePriority priority, 96 QueuePriority priority,
73 size_t* out_queue_index) const { 97 size_t* out_queue_index) const {
74 bool found_non_empty_queue = false; 98 bool found_non_empty_queue = false;
75 size_t chosen_queue = 0; 99 size_t chosen_queue = 0;
76 for (int queue_index : queue_priorities_[priority]) { 100 for (int queue_index : queue_priorities_[priority]) {
77 if (work_queues_[queue_index]->empty()) { 101 if (queues_[queue_index].work_queue->empty()) {
78 continue; 102 continue;
79 } 103 }
80 if (!found_non_empty_queue || 104 if (!found_non_empty_queue || IsOlder(queues_[queue_index].work_queue,
81 IsOlder(work_queues_[queue_index], work_queues_[chosen_queue])) { 105 queues_[chosen_queue].work_queue)) {
82 found_non_empty_queue = true; 106 found_non_empty_queue = true;
83 chosen_queue = queue_index; 107 chosen_queue = queue_index;
84 } 108 }
85 } 109 }
86 110
87 if (found_non_empty_queue) { 111 if (found_non_empty_queue) {
88 *out_queue_index = chosen_queue; 112 *out_queue_index = chosen_queue;
89 } 113 }
90 return found_non_empty_queue; 114 return found_non_empty_queue;
91 } 115 }
92 116
93 bool RendererSchedulerSelector::SelectWorkQueueToService( 117 bool RendererSchedulerSelector::SelectWorkQueueToService(
94 size_t* out_queue_index) { 118 size_t* out_queue_index) {
95 main_thread_checker_.CalledOnValidThread(); 119 main_thread_checker_.CalledOnValidThread();
96 DCHECK(work_queues_.size()); 120 DCHECK(queues_.size());
121
97 // Always service the control queue if it has any work. 122 // Always service the control queue if it has any work.
98 if (ChooseOldestWithPriority(kControlPriority, out_queue_index)) { 123 if (ChooseOldestWithPriority(kControlPriority, out_queue_index)) {
124 DidSelectQueue(*out_queue_index, kControlPriority);
99 return true; 125 return true;
100 } 126 }
101 // Select from the normal priority queue if we are starving it. 127 // Select from the normal priority queue if we are starving it.
102 if (starvation_count_ >= kMaxStarvationTasks && 128 if (starvation_count_ >= kMaxStarvationTasks &&
103 ChooseOldestWithPriority(kNormalPriority, out_queue_index)) { 129 ChooseOldestWithPriority(kNormalPriority, out_queue_index)) {
104 starvation_count_ = 0; 130 DidSelectQueue(*out_queue_index, kNormalPriority);
105 return true; 131 return true;
106 } 132 }
107 // Otherwise choose in priority order. 133 // Otherwise choose in priority order.
108 for (QueuePriority priority = kHighPriority; priority < kQueuePriorityCount; 134 for (QueuePriority priority = kHighPriority; priority < kQueuePriorityCount;
109 priority = NextPriority(priority)) { 135 priority = NextPriority(priority)) {
110 if (ChooseOldestWithPriority(priority, out_queue_index)) { 136 if (ChooseOldestWithPriority(priority, out_queue_index)) {
111 if (priority == kHighPriority) { 137 DidSelectQueue(*out_queue_index, priority);
112 starvation_count_++;
113 } else {
114 starvation_count_ = 0;
115 }
116 return true; 138 return true;
117 } 139 }
118 } 140 }
119 return false; 141 return false;
120 } 142 }
121 143
144 void RendererSchedulerSelector::DidSelectQueue(size_t selected_queue,
145 QueuePriority priority) {
146 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
147 TRACE_DISABLED_BY_DEFAULT("blink.scheduler"),
148 "RendererSchedulerSelector",
149 this,
150 AsValueWithSelectedQueue(selected_queue));
151 for (size_t i = 0; i < queues_.size(); i++) {
152 if (queues_[i].name)
153 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"),
154 queues_[i].name,
155 queues_[i].work_queue->size());
156 }
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
157
158 if (priority == kHighPriority) {
159 starvation_count_++;
160 } 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.
161 starvation_count_ = 0;
162 }
163 }
164
165 scoped_refptr<base::debug::ConvertableToTraceFormat>
166 RendererSchedulerSelector::AsValueWithSelectedQueue(
167 size_t selected_queue) const {
168 main_thread_checker_.CalledOnValidThread();
169 scoped_refptr<base::debug::TracedValue> state =
170 new base::debug::TracedValue();
171 state->BeginArray("work_queues");
172 for (const auto& queue : queues_)
173 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
174 state->EndArray();
175 state->SetInteger("selected_queue", selected_queue);
176 AsValueInto(state.get());
177 return state;
178 }
179
180 // static
181 const char* RendererSchedulerSelector::PriorityToString(
182 QueuePriority priority) {
183 switch (priority) {
184 case kControlPriority:
185 return "control";
186 case kHighPriority:
187 return "high";
188 case kNormalPriority:
189 return "normal";
190 case kBestEffortPriority:
191 return "best_effort";
192 default:
193 NOTREACHED();
194 return nullptr;
195 }
196 }
197
198 void RendererSchedulerSelector::AsValueInto(
199 base::debug::TracedValue* state) const {
200 main_thread_checker_.CalledOnValidThread();
201 state->BeginDictionary("priorities");
202 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.
203 priority = NextPriority(priority)) {
204 state->BeginArray(PriorityToString(priority));
205 for (size_t queue_index : queue_priorities_[priority])
206 state->AppendInteger(queue_index);
207 state->EndArray();
208 }
209 state->EndDictionary();
210 state->SetInteger("starvation_count", starvation_count_);
211 }
212
122 } // namespace content 213 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698