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

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

Issue 1008693004: Handle delayed tasks more natively in the scheduler (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix bug with AutomaticSelectorForTest and multiple queues Created 5 years, 9 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 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/task_queue_manager.h" 5 #include "content/renderer/scheduler/task_queue_manager.h"
6 6
7 #include <queue> 7 #include <queue>
8 #include <set>
8 9
9 #include "base/bind.h" 10 #include "base/bind.h"
10 #include "base/trace_event/trace_event.h" 11 #include "base/trace_event/trace_event.h"
11 #include "base/trace_event/trace_event_argument.h" 12 #include "base/trace_event/trace_event_argument.h"
12 #include "cc/test/test_now_source.h" 13 #include "cc/test/test_now_source.h"
13 #include "content/renderer/scheduler/nestable_single_thread_task_runner.h" 14 #include "content/renderer/scheduler/nestable_single_thread_task_runner.h"
14 #include "content/renderer/scheduler/task_queue_selector.h" 15 #include "content/renderer/scheduler/task_queue_selector.h"
15 16
16 namespace { 17 namespace {
17 const int64_t kMaxTimeTicks = std::numeric_limits<int64>::max(); 18 const int64_t kMaxTimeTicks = std::numeric_limits<int64>::max();
18 } 19 }
19 20
20 namespace content { 21 namespace content {
21 namespace internal { 22 namespace internal {
22 23
24 // Now() is somewhat expensive so it makes sense not to call Now() unless we
25 // really need to.
26 class LazyNow {
27 public:
28 explicit LazyNow(base::TimeTicks now)
29 : task_queue_manager_(nullptr), now_(now) {
30 DCHECK(!now.is_null());
31 }
32
33 explicit LazyNow(TaskQueueManager* task_queue_manager)
34 : task_queue_manager_(task_queue_manager) {}
35
36 base::TimeTicks Now() {
37 if (now_.is_null())
38 now_ = task_queue_manager_->Now();
39 return now_;
40 }
41
42 private:
43 TaskQueueManager* task_queue_manager_; // NOT OWNED
44 base::TimeTicks now_;
45 };
46
23 class TaskQueue : public base::SingleThreadTaskRunner { 47 class TaskQueue : public base::SingleThreadTaskRunner {
24 public: 48 public:
25 TaskQueue(TaskQueueManager* task_queue_manager); 49 TaskQueue(TaskQueueManager* task_queue_manager);
26 50
27 // base::SingleThreadTaskRunner implementation. 51 // base::SingleThreadTaskRunner implementation.
28 bool RunsTasksOnCurrentThread() const override; 52 bool RunsTasksOnCurrentThread() const override;
29 bool PostDelayedTask(const tracked_objects::Location& from_here, 53 bool PostDelayedTask(const tracked_objects::Location& from_here,
30 const base::Closure& task, 54 const base::Closure& task,
31 base::TimeDelta delay) override { 55 base::TimeDelta delay) override {
32 return PostDelayedTaskImpl(from_here, task, delay, TaskType::NORMAL); 56 return PostDelayedTaskImpl(from_here, task, delay, TaskType::NORMAL);
33 } 57 }
34 58
35 bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here, 59 bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
36 const base::Closure& task, 60 const base::Closure& task,
37 base::TimeDelta delay) override { 61 base::TimeDelta delay) override {
38 return PostDelayedTaskImpl(from_here, task, delay, TaskType::NON_NESTABLE); 62 return PostDelayedTaskImpl(from_here, task, delay, TaskType::NON_NESTABLE);
39 } 63 }
40 64
41 bool IsQueueEmpty() const; 65 bool IsQueueEmpty() const;
42 66
43 void SetPumpPolicy(TaskQueueManager::PumpPolicy pump_policy); 67 void SetPumpPolicy(TaskQueueManager::PumpPolicy pump_policy);
44 void PumpQueue(); 68 void PumpQueue();
45 69
46 bool NextPendingDelayedTaskRunTime( 70 bool NextPendingDelayedTaskRunTime(
47 base::TimeTicks* next_pending_delayed_task); 71 base::TimeTicks* next_pending_delayed_task);
48 72
49 bool UpdateWorkQueue(base::TimeTicks* next_pending_delayed_task, 73 bool UpdateWorkQueue(LazyNow* lazy_now,
50 const base::PendingTask* previous_task); 74 const base::PendingTask* previous_task);
51 base::PendingTask TakeTaskFromWorkQueue(); 75 base::PendingTask TakeTaskFromWorkQueue();
52 76
53 void WillDeleteTaskQueueManager(); 77 void WillDeleteTaskQueueManager();
54 78
55 base::TaskQueue& work_queue() { return work_queue_; } 79 base::TaskQueue& work_queue() { return work_queue_; }
56 80
57 void set_name(const char* name) { name_ = name; } 81 void set_name(const char* name) { name_ = name; }
58 82
59 void AsValueInto(base::trace_event::TracedValue* state) const; 83 void AsValueInto(base::trace_event::TracedValue* state) const;
60 84
61 private: 85 private:
62 enum class TaskType { 86 enum class TaskType {
63 NORMAL, 87 NORMAL,
64 NON_NESTABLE, 88 NON_NESTABLE,
65 }; 89 };
66 90
67 ~TaskQueue() override; 91 ~TaskQueue() override;
68 92
69 bool PostDelayedTaskImpl(const tracked_objects::Location& from_here, 93 bool PostDelayedTaskImpl(const tracked_objects::Location& from_here,
70 const base::Closure& task, 94 const base::Closure& task,
71 base::TimeDelta delay, 95 base::TimeDelta delay,
72 TaskType task_type); 96 TaskType task_type);
73 97
74 // Adds a task at the end of the incoming task queue and schedules a call to 98 // Delayed task posted to the underlying run loop, which locks |lock_| and
75 // TaskQueueManager::DoWork() if the incoming queue was empty and automatic 99 // calls MoveReadyDelayedTasksToIncomingQueueLocked to process dealyed tasks
76 // pumping is enabled. Can be called on an arbitrary thread. 100 // that need to be run now.
77 void EnqueueTask(const base::PendingTask& pending_task); 101 void MoveReadyDelayedTasksToIncomingQueue();
102
103 // Enqueues any delayed tasks which should be run now on the incoming_queue_
104 // and calls ScheduleDelayedWorkLocked to ensure future tasks are scheduled.
105 // Must be called with |lock_| locked.
106 void MoveReadyDelayedTasksToIncomingQueueLocked(LazyNow* lazy_now);
107
108 // Posts MoveReadyDelayedTasksToIncomingQueue if there isn't already a task
109 // posted on the underlying runloop for the next task's scheduled run time.
110 void ScheduleDelayedWorkLocked(LazyNow* lazy_now);
78 111
79 void PumpQueueLocked(); 112 void PumpQueueLocked();
80 bool TaskIsOlderThanQueuedTasks(const base::PendingTask* task); 113 bool TaskIsOlderThanQueuedTasks(const base::PendingTask* task);
81 bool ShouldAutoPumpQueueLocked(const base::PendingTask* previous_task); 114 bool ShouldAutoPumpQueueLocked(const base::PendingTask* previous_task);
82 void EnqueueTaskLocked(const base::PendingTask& pending_task); 115 void EnqueueTaskLocked(const base::PendingTask& pending_task);
83 bool NextPendingDelayedTaskRunTimeLocked(
84 base::TimeTicks* next_pending_delayed_task);
85 116
86 void TraceQueueSize(bool is_locked) const; 117 void TraceQueueSize(bool is_locked) const;
87 static const char* PumpPolicyToString( 118 static const char* PumpPolicyToString(
88 TaskQueueManager::PumpPolicy pump_policy); 119 TaskQueueManager::PumpPolicy pump_policy);
89 static void QueueAsValueInto(const base::TaskQueue& queue, 120 static void QueueAsValueInto(const base::TaskQueue& queue,
90 base::trace_event::TracedValue* state); 121 base::trace_event::TracedValue* state);
122 static void QueueAsValueInto(const base::DelayedTaskQueue& queue,
123 base::trace_event::TracedValue* state);
91 static void TaskAsValueInto(const base::PendingTask& task, 124 static void TaskAsValueInto(const base::PendingTask& task,
92 base::trace_event::TracedValue* state); 125 base::trace_event::TracedValue* state);
93 126
94 // This lock protects all members except the work queue. 127 // This lock protects all members except the work queue and the
128 // main_thread_checker_.
95 mutable base::Lock lock_; 129 mutable base::Lock lock_;
96 base::PlatformThreadId thread_id_; 130 base::PlatformThreadId thread_id_;
97 TaskQueueManager* task_queue_manager_; 131 TaskQueueManager* task_queue_manager_;
98 base::TaskQueue incoming_queue_; 132 base::TaskQueue incoming_queue_;
99 TaskQueueManager::PumpPolicy pump_policy_; 133 TaskQueueManager::PumpPolicy pump_policy_;
100 const char* name_; 134 const char* name_;
101 std::priority_queue<base::TimeTicks, 135 base::DelayedTaskQueue delayed_task_queue_;
102 std::vector<base::TimeTicks>, 136 std::set<base::TimeTicks> in_flight_kick_delayed_tasks_;
103 std::greater<base::TimeTicks>> delayed_task_run_times_;
104 137
138 base::ThreadChecker main_thread_checker_;
105 base::TaskQueue work_queue_; 139 base::TaskQueue work_queue_;
106 140
107 DISALLOW_COPY_AND_ASSIGN(TaskQueue); 141 DISALLOW_COPY_AND_ASSIGN(TaskQueue);
108 }; 142 };
109 143
110 TaskQueue::TaskQueue(TaskQueueManager* task_queue_manager) 144 TaskQueue::TaskQueue(TaskQueueManager* task_queue_manager)
111 : thread_id_(base::PlatformThread::CurrentId()), 145 : thread_id_(base::PlatformThread::CurrentId()),
112 task_queue_manager_(task_queue_manager), 146 task_queue_manager_(task_queue_manager),
113 pump_policy_(TaskQueueManager::PumpPolicy::AUTO), 147 pump_policy_(TaskQueueManager::PumpPolicy::AUTO),
114 name_(nullptr) { 148 name_(nullptr) {
115 } 149 }
116 150
117 TaskQueue::~TaskQueue() { 151 TaskQueue::~TaskQueue() {
118 } 152 }
119 153
120 void TaskQueue::WillDeleteTaskQueueManager() { 154 void TaskQueue::WillDeleteTaskQueueManager() {
121 base::AutoLock lock(lock_); 155 base::AutoLock lock(lock_);
122 task_queue_manager_ = nullptr; 156 task_queue_manager_ = nullptr;
157 // TODO(scheduler-dev): Should we also clear the other queues here too?
158 delayed_task_queue_ = base::DelayedTaskQueue();
123 } 159 }
124 160
125 bool TaskQueue::RunsTasksOnCurrentThread() const { 161 bool TaskQueue::RunsTasksOnCurrentThread() const {
126 base::AutoLock lock(lock_); 162 base::AutoLock lock(lock_);
127 return base::PlatformThread::CurrentId() == thread_id_; 163 return base::PlatformThread::CurrentId() == thread_id_;
128 } 164 }
129 165
130 bool TaskQueue::PostDelayedTaskImpl(const tracked_objects::Location& from_here, 166 bool TaskQueue::PostDelayedTaskImpl(const tracked_objects::Location& from_here,
131 const base::Closure& task, 167 const base::Closure& task,
132 base::TimeDelta delay, 168 base::TimeDelta delay,
133 TaskType task_type) { 169 TaskType task_type) {
134 base::AutoLock lock(lock_); 170 base::AutoLock lock(lock_);
135 if (!task_queue_manager_) 171 if (!task_queue_manager_)
136 return false; 172 return false;
137 173
138 base::PendingTask pending_task(from_here, task, base::TimeTicks(), 174 base::PendingTask pending_task(from_here, task, base::TimeTicks(),
139 task_type != TaskType::NON_NESTABLE); 175 task_type != TaskType::NON_NESTABLE);
140 task_queue_manager_->DidQueueTask(&pending_task); 176 task_queue_manager_->DidQueueTask(&pending_task);
141 177
142 if (delay > base::TimeDelta()) { 178 if (delay > base::TimeDelta()) {
143 pending_task.delayed_run_time = task_queue_manager_->Now() + delay; 179 base::TimeTicks now = task_queue_manager_->Now();
144 delayed_task_run_times_.push(pending_task.delayed_run_time); 180 pending_task.delayed_run_time = now + delay;
145 return task_queue_manager_->PostDelayedTask( 181 delayed_task_queue_.push(pending_task);
146 FROM_HERE, Bind(&TaskQueue::EnqueueTask, this, pending_task), delay); 182 TraceQueueSize(true);
183 // If we changed the topmost task, then it is time to reschedule.
184 if (delayed_task_queue_.top().task.Equals(pending_task.task)) {
185 LazyNow lazy_now(now);
186 ScheduleDelayedWorkLocked(&lazy_now);
187 }
188 return true;
147 } 189 }
148 EnqueueTaskLocked(pending_task); 190 EnqueueTaskLocked(pending_task);
149 return true; 191 return true;
150 } 192 }
151 193
194 void TaskQueue::MoveReadyDelayedTasksToIncomingQueue() {
195 DCHECK(main_thread_checker_.CalledOnValidThread());
196 base::AutoLock lock(lock_);
197 if (!task_queue_manager_)
198 return;
199
200 LazyNow lazy_now(task_queue_manager_);
201 MoveReadyDelayedTasksToIncomingQueueLocked(&lazy_now);
202 }
203
204 void TaskQueue::MoveReadyDelayedTasksToIncomingQueueLocked(LazyNow* lazy_now) {
205 lock_.AssertAcquired();
206 // Enqueue all delayed tasks that should be running now.
207 while (!delayed_task_queue_.empty() &&
208 delayed_task_queue_.top().delayed_run_time <= lazy_now->Now()) {
209 in_flight_kick_delayed_tasks_.erase(
210 delayed_task_queue_.top().delayed_run_time);
211 EnqueueTaskLocked(delayed_task_queue_.top());
212 delayed_task_queue_.pop();
213 }
214 TraceQueueSize(true);
215 ScheduleDelayedWorkLocked(lazy_now);
216 }
217
218 void TaskQueue::ScheduleDelayedWorkLocked(LazyNow* lazy_now) {
219 lock_.AssertAcquired();
220 // Any remaining tasks are in the future, so queue a task to kick them.
221 if (!delayed_task_queue_.empty()) {
222 base::TimeTicks next_run_time = delayed_task_queue_.top().delayed_run_time;
223 DCHECK_GT(next_run_time, lazy_now->Now());
224 // Make sure we don't have more than one
225 // MoveReadyDelayedTasksToIncomingQueue posted for a particular scheduled
226 // run time (note it's fine to have multiple ones in flight for distinct
227 // run times).
228 if (in_flight_kick_delayed_tasks_.find(next_run_time) ==
229 in_flight_kick_delayed_tasks_.end()) {
230 in_flight_kick_delayed_tasks_.insert(next_run_time);
231 base::TimeDelta delay = next_run_time - lazy_now->Now();
232 task_queue_manager_->PostDelayedTask(
233 FROM_HERE,
234 Bind(&TaskQueue::MoveReadyDelayedTasksToIncomingQueue, this), delay);
235 }
236 }
237 }
238
152 bool TaskQueue::IsQueueEmpty() const { 239 bool TaskQueue::IsQueueEmpty() const {
153 if (!work_queue_.empty()) 240 if (!work_queue_.empty())
154 return false; 241 return false;
155 242
156 { 243 {
157 base::AutoLock lock(lock_); 244 base::AutoLock lock(lock_);
158 return incoming_queue_.empty(); 245 return incoming_queue_.empty();
159 } 246 }
160 } 247 }
161 248
(...skipping 28 matching lines...) Expand all
190 TaskIsOlderThanQueuedTasks(previous_task)) 277 TaskIsOlderThanQueuedTasks(previous_task))
191 return false; 278 return false;
192 if (incoming_queue_.empty()) 279 if (incoming_queue_.empty())
193 return false; 280 return false;
194 return true; 281 return true;
195 } 282 }
196 283
197 bool TaskQueue::NextPendingDelayedTaskRunTime( 284 bool TaskQueue::NextPendingDelayedTaskRunTime(
198 base::TimeTicks* next_pending_delayed_task) { 285 base::TimeTicks* next_pending_delayed_task) {
199 base::AutoLock lock(lock_); 286 base::AutoLock lock(lock_);
200 return NextPendingDelayedTaskRunTimeLocked(next_pending_delayed_task); 287 if (delayed_task_queue_.empty())
288 return false;
289 *next_pending_delayed_task = delayed_task_queue_.top().delayed_run_time;
290 return true;
201 } 291 }
202 292
203 bool TaskQueue::NextPendingDelayedTaskRunTimeLocked( 293 bool TaskQueue::UpdateWorkQueue(LazyNow* lazy_now,
204 base::TimeTicks* next_pending_delayed_task) { 294 const base::PendingTask* previous_task) {
205 lock_.AssertAcquired();
206 if (!delayed_task_run_times_.empty()) {
207 *next_pending_delayed_task =
208 std::min(*next_pending_delayed_task, delayed_task_run_times_.top());
209 return true;
210 }
211 return false;
212 }
213
214 bool TaskQueue::UpdateWorkQueue(
215 base::TimeTicks* next_pending_delayed_task,
216 const base::PendingTask* previous_task) {
217 if (!work_queue_.empty()) 295 if (!work_queue_.empty())
218 return true; 296 return true;
219 297
220 { 298 {
221 base::AutoLock lock(lock_); 299 base::AutoLock lock(lock_);
222 NextPendingDelayedTaskRunTimeLocked(next_pending_delayed_task); 300 MoveReadyDelayedTasksToIncomingQueueLocked(lazy_now);
223 if (!ShouldAutoPumpQueueLocked(previous_task)) 301 if (!ShouldAutoPumpQueueLocked(previous_task))
224 return false; 302 return false;
303 MoveReadyDelayedTasksToIncomingQueueLocked(lazy_now);
225 work_queue_.Swap(&incoming_queue_); 304 work_queue_.Swap(&incoming_queue_);
226 TraceQueueSize(true); 305 TraceQueueSize(true);
227 return true; 306 return true;
228 } 307 }
229 } 308 }
230 309
231 base::PendingTask TaskQueue::TakeTaskFromWorkQueue() { 310 base::PendingTask TaskQueue::TakeTaskFromWorkQueue() {
232 base::PendingTask pending_task = work_queue_.front(); 311 base::PendingTask pending_task = work_queue_.front();
233 work_queue_.pop(); 312 work_queue_.pop();
234 TraceQueueSize(false); 313 TraceQueueSize(false);
235 return pending_task; 314 return pending_task;
236 } 315 }
237 316
238 void TaskQueue::TraceQueueSize(bool is_locked) const { 317 void TaskQueue::TraceQueueSize(bool is_locked) const {
239 bool is_tracing; 318 bool is_tracing;
240 TRACE_EVENT_CATEGORY_GROUP_ENABLED( 319 TRACE_EVENT_CATEGORY_GROUP_ENABLED(
241 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), &is_tracing); 320 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), &is_tracing);
242 if (!is_tracing || !name_) 321 if (!is_tracing || !name_)
243 return; 322 return;
244 if (!is_locked) 323 if (!is_locked)
245 lock_.Acquire(); 324 lock_.Acquire();
246 else 325 else
247 lock_.AssertAcquired(); 326 lock_.AssertAcquired();
248 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), name_, 327 TRACE_COUNTER1(
249 incoming_queue_.size() + work_queue_.size()); 328 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), name_,
329 incoming_queue_.size() + work_queue_.size() + delayed_task_queue_.size());
250 if (!is_locked) 330 if (!is_locked)
251 lock_.Release(); 331 lock_.Release();
252 } 332 }
253 333
254 void TaskQueue::EnqueueTask(const base::PendingTask& pending_task) {
255 base::AutoLock lock(lock_);
256 EnqueueTaskLocked(pending_task);
257 }
258
259 void TaskQueue::EnqueueTaskLocked(const base::PendingTask& pending_task) { 334 void TaskQueue::EnqueueTaskLocked(const base::PendingTask& pending_task) {
260 lock_.AssertAcquired(); 335 lock_.AssertAcquired();
261 if (!task_queue_manager_) 336 if (!task_queue_manager_)
262 return; 337 return;
263 if (pump_policy_ == TaskQueueManager::PumpPolicy::AUTO && 338 if (pump_policy_ == TaskQueueManager::PumpPolicy::AUTO &&
264 incoming_queue_.empty()) 339 incoming_queue_.empty())
265 task_queue_manager_->MaybePostDoWorkOnMainRunner(); 340 task_queue_manager_->MaybePostDoWorkOnMainRunner();
266 incoming_queue_.push(pending_task); 341 incoming_queue_.push(pending_task);
267 342
268 if (!pending_task.delayed_run_time.is_null()) { 343 if (!pending_task.delayed_run_time.is_null()) {
269 // Update the time of the next pending delayed task.
270 while (!delayed_task_run_times_.empty() &&
271 delayed_task_run_times_.top() <= pending_task.delayed_run_time) {
272 delayed_task_run_times_.pop();
273 }
274 // Clear the delayed run time because we've already applied the delay 344 // Clear the delayed run time because we've already applied the delay
275 // before getting here. 345 // before getting here.
276 incoming_queue_.back().delayed_run_time = base::TimeTicks(); 346 incoming_queue_.back().delayed_run_time = base::TimeTicks();
277 } 347 }
278 TraceQueueSize(true); 348 TraceQueueSize(true);
279 } 349 }
280 350
281 void TaskQueue::SetPumpPolicy(TaskQueueManager::PumpPolicy pump_policy) { 351 void TaskQueue::SetPumpPolicy(TaskQueueManager::PumpPolicy pump_policy) {
282 base::AutoLock lock(lock_); 352 base::AutoLock lock(lock_);
283 if (pump_policy == TaskQueueManager::PumpPolicy::AUTO && 353 if (pump_policy == TaskQueueManager::PumpPolicy::AUTO &&
284 pump_policy_ != TaskQueueManager::PumpPolicy::AUTO) { 354 pump_policy_ != TaskQueueManager::PumpPolicy::AUTO) {
285 PumpQueueLocked(); 355 PumpQueueLocked();
286 } 356 }
287 pump_policy_ = pump_policy; 357 pump_policy_ = pump_policy;
288 } 358 }
289 359
290 void TaskQueue::PumpQueueLocked() { 360 void TaskQueue::PumpQueueLocked() {
291 lock_.AssertAcquired(); 361 lock_.AssertAcquired();
362 if (task_queue_manager_) {
363 LazyNow lazy_now(task_queue_manager_);
364 MoveReadyDelayedTasksToIncomingQueueLocked(&lazy_now);
365 }
292 while (!incoming_queue_.empty()) { 366 while (!incoming_queue_.empty()) {
293 work_queue_.push(incoming_queue_.front()); 367 work_queue_.push(incoming_queue_.front());
294 incoming_queue_.pop(); 368 incoming_queue_.pop();
295 } 369 }
296 if (!work_queue_.empty()) 370 if (!work_queue_.empty())
297 task_queue_manager_->MaybePostDoWorkOnMainRunner(); 371 task_queue_manager_->MaybePostDoWorkOnMainRunner();
298 } 372 }
299 373
300 void TaskQueue::PumpQueue() { 374 void TaskQueue::PumpQueue() {
301 base::AutoLock lock(lock_); 375 base::AutoLock lock(lock_);
302 PumpQueueLocked(); 376 PumpQueueLocked();
303 } 377 }
304 378
305 void TaskQueue::AsValueInto(base::trace_event::TracedValue* state) const { 379 void TaskQueue::AsValueInto(base::trace_event::TracedValue* state) const {
306 base::AutoLock lock(lock_); 380 base::AutoLock lock(lock_);
307 state->BeginDictionary(); 381 state->BeginDictionary();
308 if (name_) 382 if (name_)
309 state->SetString("name", name_); 383 state->SetString("name", name_);
310 state->SetString("pump_policy", PumpPolicyToString(pump_policy_)); 384 state->SetString("pump_policy", PumpPolicyToString(pump_policy_));
311 state->BeginArray("incoming_queue"); 385 state->BeginArray("incoming_queue");
312 QueueAsValueInto(incoming_queue_, state); 386 QueueAsValueInto(incoming_queue_, state);
313 state->EndArray(); 387 state->EndArray();
314 state->BeginArray("work_queue"); 388 state->BeginArray("work_queue");
315 QueueAsValueInto(work_queue_, state); 389 QueueAsValueInto(work_queue_, state);
390 state->BeginArray("delayed_task_queue");
391 QueueAsValueInto(delayed_task_queue_, state);
316 state->EndArray(); 392 state->EndArray();
317 state->EndDictionary(); 393 state->EndDictionary();
318 } 394 }
319 395
320 // static 396 // static
321 const char* TaskQueue::PumpPolicyToString( 397 const char* TaskQueue::PumpPolicyToString(
322 TaskQueueManager::PumpPolicy pump_policy) { 398 TaskQueueManager::PumpPolicy pump_policy) {
323 switch (pump_policy) { 399 switch (pump_policy) {
324 case TaskQueueManager::PumpPolicy::AUTO: 400 case TaskQueueManager::PumpPolicy::AUTO:
325 return "auto"; 401 return "auto";
(...skipping 11 matching lines...) Expand all
337 void TaskQueue::QueueAsValueInto(const base::TaskQueue& queue, 413 void TaskQueue::QueueAsValueInto(const base::TaskQueue& queue,
338 base::trace_event::TracedValue* state) { 414 base::trace_event::TracedValue* state) {
339 base::TaskQueue queue_copy(queue); 415 base::TaskQueue queue_copy(queue);
340 while (!queue_copy.empty()) { 416 while (!queue_copy.empty()) {
341 TaskAsValueInto(queue_copy.front(), state); 417 TaskAsValueInto(queue_copy.front(), state);
342 queue_copy.pop(); 418 queue_copy.pop();
343 } 419 }
344 } 420 }
345 421
346 // static 422 // static
423 void TaskQueue::QueueAsValueInto(const base::DelayedTaskQueue& queue,
424 base::trace_event::TracedValue* state) {
425 base::DelayedTaskQueue queue_copy(queue);
426 while (!queue_copy.empty()) {
427 TaskAsValueInto(queue_copy.top(), state);
428 queue_copy.pop();
429 }
430 }
431
432 // static
347 void TaskQueue::TaskAsValueInto(const base::PendingTask& task, 433 void TaskQueue::TaskAsValueInto(const base::PendingTask& task,
348 base::trace_event::TracedValue* state) { 434 base::trace_event::TracedValue* state) {
349 state->BeginDictionary(); 435 state->BeginDictionary();
350 state->SetString("posted_from", task.posted_from.ToString()); 436 state->SetString("posted_from", task.posted_from.ToString());
351 state->SetInteger("sequence_num", task.sequence_num); 437 state->SetInteger("sequence_num", task.sequence_num);
352 state->SetBoolean("nestable", task.nestable); 438 state->SetBoolean("nestable", task.nestable);
353 state->SetBoolean("is_high_res", task.is_high_res); 439 state->SetBoolean("is_high_res", task.is_high_res);
354 state->SetDouble( 440 state->SetDouble(
355 "delayed_run_time", 441 "delayed_run_time",
356 (task.delayed_run_time - base::TimeTicks()).InMicroseconds() / 1000.0L); 442 (task.delayed_run_time - base::TimeTicks()).InMicroseconds() / 1000.0L);
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
409 internal::TaskQueue* queue = Queue(queue_index); 495 internal::TaskQueue* queue = Queue(queue_index);
410 return queue->IsQueueEmpty(); 496 return queue->IsQueueEmpty();
411 } 497 }
412 498
413 base::TimeTicks TaskQueueManager::NextPendingDelayedTaskRunTime() { 499 base::TimeTicks TaskQueueManager::NextPendingDelayedTaskRunTime() {
414 DCHECK(main_thread_checker_.CalledOnValidThread()); 500 DCHECK(main_thread_checker_.CalledOnValidThread());
415 bool found_pending_task = false; 501 bool found_pending_task = false;
416 base::TimeTicks next_pending_delayed_task( 502 base::TimeTicks next_pending_delayed_task(
417 base::TimeTicks::FromInternalValue(kMaxTimeTicks)); 503 base::TimeTicks::FromInternalValue(kMaxTimeTicks));
418 for (auto& queue : queues_) { 504 for (auto& queue : queues_) {
419 found_pending_task |= 505 base::TimeTicks queues_next_pending_delayed_task;
420 queue->NextPendingDelayedTaskRunTime(&next_pending_delayed_task); 506 if (queue->NextPendingDelayedTaskRunTime(
507 &queues_next_pending_delayed_task)) {
508 found_pending_task = true;
509 next_pending_delayed_task =
510 std::min(next_pending_delayed_task, queues_next_pending_delayed_task);
511 }
421 } 512 }
422 513
423 if (!found_pending_task) 514 if (!found_pending_task)
424 return base::TimeTicks(); 515 return base::TimeTicks();
425 516
426 DCHECK_NE(next_pending_delayed_task, 517 DCHECK_NE(next_pending_delayed_task,
427 base::TimeTicks::FromInternalValue(kMaxTimeTicks)); 518 base::TimeTicks::FromInternalValue(kMaxTimeTicks));
428 return next_pending_delayed_task; 519 return next_pending_delayed_task;
429 } 520 }
430 521
431 void TaskQueueManager::SetPumpPolicy(size_t queue_index, 522 void TaskQueueManager::SetPumpPolicy(size_t queue_index,
432 PumpPolicy pump_policy) { 523 PumpPolicy pump_policy) {
433 DCHECK(main_thread_checker_.CalledOnValidThread()); 524 DCHECK(main_thread_checker_.CalledOnValidThread());
434 internal::TaskQueue* queue = Queue(queue_index); 525 internal::TaskQueue* queue = Queue(queue_index);
435 queue->SetPumpPolicy(pump_policy); 526 queue->SetPumpPolicy(pump_policy);
436 } 527 }
437 528
438 void TaskQueueManager::PumpQueue(size_t queue_index) { 529 void TaskQueueManager::PumpQueue(size_t queue_index) {
439 DCHECK(main_thread_checker_.CalledOnValidThread()); 530 DCHECK(main_thread_checker_.CalledOnValidThread());
440 internal::TaskQueue* queue = Queue(queue_index); 531 internal::TaskQueue* queue = Queue(queue_index);
441 queue->PumpQueue(); 532 queue->PumpQueue();
442 } 533 }
443 534
444 bool TaskQueueManager::UpdateWorkQueues( 535 bool TaskQueueManager::UpdateWorkQueues(
445 base::TimeTicks* next_pending_delayed_task,
446 const base::PendingTask* previous_task) { 536 const base::PendingTask* previous_task) {
447 // TODO(skyostil): This is not efficient when the number of queues grows very 537 // TODO(skyostil): This is not efficient when the number of queues grows very
448 // large due to the number of locks taken. Consider optimizing when we get 538 // large due to the number of locks taken. Consider optimizing when we get
449 // there. 539 // there.
450 DCHECK(main_thread_checker_.CalledOnValidThread()); 540 DCHECK(main_thread_checker_.CalledOnValidThread());
541 internal::LazyNow lazy_now(this);
451 bool has_work = false; 542 bool has_work = false;
452 for (auto& queue : queues_) { 543 for (auto& queue : queues_) {
453 has_work |= queue->UpdateWorkQueue(next_pending_delayed_task, 544 has_work |= queue->UpdateWorkQueue(&lazy_now, previous_task);
454 previous_task);
455 if (!queue->work_queue().empty()) { 545 if (!queue->work_queue().empty()) {
456 // Currently we should not be getting tasks with delayed run times in any 546 // Currently we should not be getting tasks with delayed run times in any
457 // of the work queues. 547 // of the work queues.
458 DCHECK(queue->work_queue().front().delayed_run_time.is_null()); 548 DCHECK(queue->work_queue().front().delayed_run_time.is_null());
459 } 549 }
460 } 550 }
461 return has_work; 551 return has_work;
462 } 552 }
463 553
464 void TaskQueueManager::MaybePostDoWorkOnMainRunner() { 554 void TaskQueueManager::MaybePostDoWorkOnMainRunner() {
(...skipping 12 matching lines...) Expand all
477 on_main_thread)); 567 on_main_thread));
478 } 568 }
479 569
480 void TaskQueueManager::DoWork(bool posted_from_main_thread) { 570 void TaskQueueManager::DoWork(bool posted_from_main_thread) {
481 if (posted_from_main_thread) { 571 if (posted_from_main_thread) {
482 pending_dowork_count_--; 572 pending_dowork_count_--;
483 DCHECK_GE(pending_dowork_count_, 0); 573 DCHECK_GE(pending_dowork_count_, 0);
484 } 574 }
485 DCHECK(main_thread_checker_.CalledOnValidThread()); 575 DCHECK(main_thread_checker_.CalledOnValidThread());
486 576
487 base::TimeTicks next_pending_delayed_task( 577 // Pass nullptr to UpdateWorkQueues here to prevent waking up a
488 base::TimeTicks::FromInternalValue(kMaxTimeTicks));
489
490 // Pass nullptr to UpdateWorkQueues here to prevent waking up an
491 // pump-after-wakeup queue. 578 // pump-after-wakeup queue.
492 if (!UpdateWorkQueues(&next_pending_delayed_task, nullptr)) 579 if (!UpdateWorkQueues(nullptr))
493 return; 580 return;
494 581
495 base::PendingTask previous_task((tracked_objects::Location()), 582 base::PendingTask previous_task((tracked_objects::Location()),
496 (base::Closure())); 583 (base::Closure()));
497 for (int i = 0; i < work_batch_size_; i++) { 584 for (int i = 0; i < work_batch_size_; i++) {
498 // Interrupt the work batch if we should run the next delayed task.
499 if (i > 0 && next_pending_delayed_task.ToInternalValue() != kMaxTimeTicks &&
500 Now() >= next_pending_delayed_task)
501 return;
502
503 size_t queue_index; 585 size_t queue_index;
504 if (!SelectWorkQueueToService(&queue_index)) 586 if (!SelectWorkQueueToService(&queue_index))
505 return; 587 return;
506 // Note that this function won't post another call to DoWork if one is 588 // Note that this function won't post another call to DoWork if one is
507 // already pending, so it is safe to call it in a loop. 589 // already pending, so it is safe to call it in a loop.
508 MaybePostDoWorkOnMainRunner(); 590 MaybePostDoWorkOnMainRunner();
509 ProcessTaskFromWorkQueue(queue_index, i > 0, &previous_task); 591 ProcessTaskFromWorkQueue(queue_index, i > 0, &previous_task);
510 592
511 if (!UpdateWorkQueues(&next_pending_delayed_task, &previous_task)) 593 if (!UpdateWorkQueues(&previous_task))
512 return; 594 return;
513 } 595 }
514 } 596 }
515 597
516 bool TaskQueueManager::SelectWorkQueueToService(size_t* out_queue_index) { 598 bool TaskQueueManager::SelectWorkQueueToService(size_t* out_queue_index) {
517 bool should_run = selector_->SelectWorkQueueToService(out_queue_index); 599 bool should_run = selector_->SelectWorkQueueToService(out_queue_index);
518 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( 600 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
519 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "TaskQueueManager", this, 601 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "TaskQueueManager", this,
520 AsValueWithSelectorResult(should_run, *out_queue_index)); 602 AsValueWithSelectorResult(should_run, *out_queue_index));
521 return should_run; 603 return should_run;
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
615 state->EndArray(); 697 state->EndArray();
616 state->BeginDictionary("selector"); 698 state->BeginDictionary("selector");
617 selector_->AsValueInto(state.get()); 699 selector_->AsValueInto(state.get());
618 state->EndDictionary(); 700 state->EndDictionary();
619 if (should_run) 701 if (should_run)
620 state->SetInteger("selected_queue", selected_queue); 702 state->SetInteger("selected_queue", selected_queue);
621 return state; 703 return state;
622 } 704 }
623 705
624 } // namespace content 706 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/scheduler/task_queue_manager.h ('k') | content/renderer/scheduler/task_queue_manager_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698