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

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: Responding to yet more feedback. Also removed some boilerplate calls to AppendQueueToService 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 UpdateWorkQueue(base::TimeTicks* next_pending_delayed_task, 70 bool UpdateWorkQueue(LazyNow* lazy_now,
47 const base::PendingTask* previous_task); 71 const base::PendingTask* previous_task);
48 base::PendingTask TakeTaskFromWorkQueue(); 72 base::PendingTask TakeTaskFromWorkQueue();
49 73
50 void WillDeleteTaskQueueManager(); 74 void WillDeleteTaskQueueManager();
51 75
52 base::TaskQueue& work_queue() { return work_queue_; } 76 base::TaskQueue& work_queue() { return work_queue_; }
53 77
54 void set_name(const char* name) { name_ = name; } 78 void set_name(const char* name) { name_ = name; }
55 79
56 void AsValueInto(base::trace_event::TracedValue* state) const; 80 void AsValueInto(base::trace_event::TracedValue* state) const;
57 81
58 private: 82 private:
59 enum class TaskType { 83 enum class TaskType {
60 NORMAL, 84 NORMAL,
61 NON_NESTABLE, 85 NON_NESTABLE,
62 }; 86 };
63 87
64 ~TaskQueue() override; 88 ~TaskQueue() override;
65 89
66 bool PostDelayedTaskImpl(const tracked_objects::Location& from_here, 90 bool PostDelayedTaskImpl(const tracked_objects::Location& from_here,
67 const base::Closure& task, 91 const base::Closure& task,
68 base::TimeDelta delay, 92 base::TimeDelta delay,
69 TaskType task_type); 93 TaskType task_type);
70 94
71 // Adds a task at the end of the incoming task queue and schedules a call to 95 // Delayed task posted to the underlying run loop, which locks |lock_| and
72 // TaskQueueManager::DoWork() if the incoming queue was empty and automatic 96 // calls MoveReadyDelayedTasksToIncomingQueueLocked to process dealyed tasks
73 // pumping is enabled. Can be called on an arbitrary thread. 97 // that need to be run now.
74 void EnqueueTask(const base::PendingTask& pending_task); 98 void MoveReadyDelayedTasksToIncomingQueue();
99
100 // Enqueues any delayed tasks which should be run now on the incoming_queue_
101 // and calls ScheduleDelayedWorkLocked to ensure future tasks are scheduled.
102 // Must be called with |lock_| locked.
103 void MoveReadyDelayedTasksToIncomingQueueLocked(LazyNow* lazy_now);
104
105 // Posts MoveReadyDelayedTasksToIncomingQueue if there isn't already a task
106 // posted on the underlying runloop for the next task's scheduled run time.
107 void ScheduleDelayedWorkLocked(LazyNow* lazy_now);
75 108
76 void PumpQueueLocked(); 109 void PumpQueueLocked();
77 bool TaskIsOlderThanQueuedTasks(const base::PendingTask* task); 110 bool TaskIsOlderThanQueuedTasks(const base::PendingTask* task);
78 bool ShouldAutoPumpQueueLocked(const base::PendingTask* previous_task); 111 bool ShouldAutoPumpQueueLocked(const base::PendingTask* previous_task);
79 void EnqueueTaskLocked(const base::PendingTask& pending_task); 112 void EnqueueTaskLocked(const base::PendingTask& pending_task);
80 113
81 void TraceQueueSize(bool is_locked) const; 114 void TraceQueueSize(bool is_locked) const;
82 static const char* PumpPolicyToString( 115 static const char* PumpPolicyToString(
83 TaskQueueManager::PumpPolicy pump_policy); 116 TaskQueueManager::PumpPolicy pump_policy);
84 static void QueueAsValueInto(const base::TaskQueue& queue, 117 static void QueueAsValueInto(const base::TaskQueue& queue,
85 base::trace_event::TracedValue* state); 118 base::trace_event::TracedValue* state);
119 static void QueueAsValueInto(const base::DelayedTaskQueue& queue,
120 base::trace_event::TracedValue* state);
86 static void TaskAsValueInto(const base::PendingTask& task, 121 static void TaskAsValueInto(const base::PendingTask& task,
87 base::trace_event::TracedValue* state); 122 base::trace_event::TracedValue* state);
88 123
89 // This lock protects all members except the work queue. 124 // This lock protects all members except the work queue.
90 mutable base::Lock lock_; 125 mutable base::Lock lock_;
91 base::PlatformThreadId thread_id_; 126 base::PlatformThreadId thread_id_;
92 TaskQueueManager* task_queue_manager_; 127 TaskQueueManager* task_queue_manager_;
93 base::TaskQueue incoming_queue_; 128 base::TaskQueue incoming_queue_;
94 TaskQueueManager::PumpPolicy pump_policy_; 129 TaskQueueManager::PumpPolicy pump_policy_;
95 const char* name_; 130 const char* name_;
96 std::priority_queue<base::TimeTicks, 131 base::DelayedTaskQueue delayed_task_queue_;
97 std::vector<base::TimeTicks>, 132 std::set<base::TimeTicks> in_flight_kick_delayed_tasks_;
98 std::greater<base::TimeTicks>> delayed_task_run_times_; 133 base::ThreadChecker main_thread_checker_;
Sami 2015/03/18 11:13:21 nit: main_thread_checker isn't protected by the lo
alex clarke (OOO till 29th) 2015/03/18 12:15:10 Done.
99 134
100 base::TaskQueue work_queue_; 135 base::TaskQueue work_queue_;
101 136
102 DISALLOW_COPY_AND_ASSIGN(TaskQueue); 137 DISALLOW_COPY_AND_ASSIGN(TaskQueue);
103 }; 138 };
104 139
105 TaskQueue::TaskQueue(TaskQueueManager* task_queue_manager) 140 TaskQueue::TaskQueue(TaskQueueManager* task_queue_manager)
106 : thread_id_(base::PlatformThread::CurrentId()), 141 : thread_id_(base::PlatformThread::CurrentId()),
107 task_queue_manager_(task_queue_manager), 142 task_queue_manager_(task_queue_manager),
108 pump_policy_(TaskQueueManager::PumpPolicy::AUTO), 143 pump_policy_(TaskQueueManager::PumpPolicy::AUTO),
109 name_(nullptr) { 144 name_(nullptr) {
110 } 145 }
111 146
112 TaskQueue::~TaskQueue() { 147 TaskQueue::~TaskQueue() {
113 } 148 }
114 149
115 void TaskQueue::WillDeleteTaskQueueManager() { 150 void TaskQueue::WillDeleteTaskQueueManager() {
116 base::AutoLock lock(lock_); 151 base::AutoLock lock(lock_);
117 task_queue_manager_ = nullptr; 152 task_queue_manager_ = nullptr;
153 // TODO(scheduler-dev): Should we also clear the other queues here too?
154 delayed_task_queue_ = base::DelayedTaskQueue();
118 } 155 }
119 156
120 bool TaskQueue::RunsTasksOnCurrentThread() const { 157 bool TaskQueue::RunsTasksOnCurrentThread() const {
121 base::AutoLock lock(lock_); 158 base::AutoLock lock(lock_);
122 return base::PlatformThread::CurrentId() == thread_id_; 159 return base::PlatformThread::CurrentId() == thread_id_;
123 } 160 }
124 161
125 bool TaskQueue::PostDelayedTaskImpl(const tracked_objects::Location& from_here, 162 bool TaskQueue::PostDelayedTaskImpl(const tracked_objects::Location& from_here,
126 const base::Closure& task, 163 const base::Closure& task,
127 base::TimeDelta delay, 164 base::TimeDelta delay,
128 TaskType task_type) { 165 TaskType task_type) {
129 base::AutoLock lock(lock_); 166 base::AutoLock lock(lock_);
130 if (!task_queue_manager_) 167 if (!task_queue_manager_)
131 return false; 168 return false;
132 169
133 base::PendingTask pending_task(from_here, task, base::TimeTicks(), 170 base::PendingTask pending_task(from_here, task, base::TimeTicks(),
134 task_type != TaskType::NON_NESTABLE); 171 task_type != TaskType::NON_NESTABLE);
135 task_queue_manager_->DidQueueTask(&pending_task); 172 task_queue_manager_->DidQueueTask(&pending_task);
136 173
137 if (delay > base::TimeDelta()) { 174 if (delay > base::TimeDelta()) {
138 pending_task.delayed_run_time = task_queue_manager_->Now() + delay; 175 base::TimeTicks now = task_queue_manager_->Now();
139 delayed_task_run_times_.push(pending_task.delayed_run_time); 176 pending_task.delayed_run_time = now + delay;
140 return task_queue_manager_->PostDelayedTask( 177 delayed_task_queue_.push(pending_task);
Sami 2015/03/18 11:13:21 nit: call TraceQueueSize() here.
alex clarke (OOO till 29th) 2015/03/18 12:15:10 Done.
141 FROM_HERE, Bind(&TaskQueue::EnqueueTask, this, pending_task), delay); 178 // If we changed the topmost task, then it is time to reschedule.
179 if (delayed_task_queue_.top().task.Equals(pending_task.task)) {
180 LazyNow lazy_now(now);
181 ScheduleDelayedWorkLocked(&lazy_now);
182 }
183 return true;
142 } 184 }
143 EnqueueTaskLocked(pending_task); 185 EnqueueTaskLocked(pending_task);
144 return true; 186 return true;
145 } 187 }
146 188
189 void TaskQueue::MoveReadyDelayedTasksToIncomingQueue() {
190 DCHECK(main_thread_checker_.CalledOnValidThread());
191 if (!task_queue_manager_)
Sami 2015/03/18 11:13:21 This should be checked while holding the lock.
alex clarke (OOO till 29th) 2015/03/18 12:15:10 Done.
192 return;
193
194 base::AutoLock lock(lock_);
195 LazyNow lazy_now(task_queue_manager_);
196 MoveReadyDelayedTasksToIncomingQueueLocked(&lazy_now);
197 }
198
199 void TaskQueue::MoveReadyDelayedTasksToIncomingQueueLocked(LazyNow* lazy_now) {
200 lock_.AssertAcquired();
201 // Enqueue all delayed tasks that should be running now.
202 while (!delayed_task_queue_.empty() &&
203 delayed_task_queue_.top().delayed_run_time <= lazy_now->Now()) {
204 in_flight_kick_delayed_tasks_.erase(
205 delayed_task_queue_.top().delayed_run_time);
206 EnqueueTaskLocked(delayed_task_queue_.top());
207 delayed_task_queue_.pop();
208 }
Sami 2015/03/18 11:13:21 nit: call TraceQueueSize() here.
alex clarke (OOO till 29th) 2015/03/18 12:15:10 Done.
209 ScheduleDelayedWorkLocked(lazy_now);
210 }
211
212 void TaskQueue::ScheduleDelayedWorkLocked(LazyNow* lazy_now) {
213 lock_.AssertAcquired();
214 // Any remaining tasks are in the future, so queue a task to kick them.
215 if (!delayed_task_queue_.empty()) {
216 base::TimeTicks next_run_time = delayed_task_queue_.top().delayed_run_time;
217 DCHECK(next_run_time > lazy_now->Now());
Sami 2015/03/18 11:13:21 nit: DCHECK_GT
alex clarke (OOO till 29th) 2015/03/18 12:15:10 Done.
218 // Make sure we don't have more than one
219 // MoveReadyDelayedTasksToIncomingQueue posted for a particular scheduled
220 // run time (note it's fine to have multiple ones in flight for distinct
221 // run times).
222 if (in_flight_kick_delayed_tasks_.find(next_run_time) ==
223 in_flight_kick_delayed_tasks_.end()) {
224 in_flight_kick_delayed_tasks_.insert(next_run_time);
225 base::TimeDelta delay = next_run_time - lazy_now->Now();
226 task_queue_manager_->PostDelayedTask(
227 FROM_HERE,
228 Bind(&TaskQueue::MoveReadyDelayedTasksToIncomingQueue, this), delay);
229 }
230 }
231 }
232
147 bool TaskQueue::IsQueueEmpty() const { 233 bool TaskQueue::IsQueueEmpty() const {
148 if (!work_queue_.empty()) 234 if (!work_queue_.empty())
149 return false; 235 return false;
150 236
151 { 237 {
152 base::AutoLock lock(lock_); 238 base::AutoLock lock(lock_);
153 return incoming_queue_.empty(); 239 return incoming_queue_.empty();
154 } 240 }
155 } 241 }
156 242
(...skipping 25 matching lines...) Expand all
182 if (pump_policy_ == TaskQueueManager::PumpPolicy::MANUAL) 268 if (pump_policy_ == TaskQueueManager::PumpPolicy::MANUAL)
183 return false; 269 return false;
184 if (pump_policy_ == TaskQueueManager::PumpPolicy::AFTER_WAKEUP && 270 if (pump_policy_ == TaskQueueManager::PumpPolicy::AFTER_WAKEUP &&
185 TaskIsOlderThanQueuedTasks(previous_task)) 271 TaskIsOlderThanQueuedTasks(previous_task))
186 return false; 272 return false;
187 if (incoming_queue_.empty()) 273 if (incoming_queue_.empty())
188 return false; 274 return false;
189 return true; 275 return true;
190 } 276 }
191 277
192 bool TaskQueue::UpdateWorkQueue( 278 bool TaskQueue::UpdateWorkQueue(LazyNow* lazy_now,
193 base::TimeTicks* next_pending_delayed_task, 279 const base::PendingTask* previous_task) {
194 const base::PendingTask* previous_task) {
195 if (!work_queue_.empty()) 280 if (!work_queue_.empty())
196 return true; 281 return true;
197 282
198 { 283 {
199 base::AutoLock lock(lock_); 284 base::AutoLock lock(lock_);
200 if (!delayed_task_run_times_.empty()) {
201 *next_pending_delayed_task =
202 std::min(*next_pending_delayed_task, delayed_task_run_times_.top());
203 }
204 if (!ShouldAutoPumpQueueLocked(previous_task)) 285 if (!ShouldAutoPumpQueueLocked(previous_task))
205 return false; 286 return false;
287 MoveReadyDelayedTasksToIncomingQueueLocked(lazy_now);
206 work_queue_.Swap(&incoming_queue_); 288 work_queue_.Swap(&incoming_queue_);
207 TraceQueueSize(true); 289 TraceQueueSize(true);
208 return true; 290 return true;
209 } 291 }
210 } 292 }
211 293
212 base::PendingTask TaskQueue::TakeTaskFromWorkQueue() { 294 base::PendingTask TaskQueue::TakeTaskFromWorkQueue() {
213 base::PendingTask pending_task = work_queue_.front(); 295 base::PendingTask pending_task = work_queue_.front();
214 work_queue_.pop(); 296 work_queue_.pop();
215 TraceQueueSize(false); 297 TraceQueueSize(false);
216 return pending_task; 298 return pending_task;
217 } 299 }
218 300
219 void TaskQueue::TraceQueueSize(bool is_locked) const { 301 void TaskQueue::TraceQueueSize(bool is_locked) const {
220 bool is_tracing; 302 bool is_tracing;
221 TRACE_EVENT_CATEGORY_GROUP_ENABLED( 303 TRACE_EVENT_CATEGORY_GROUP_ENABLED(
222 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), &is_tracing); 304 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), &is_tracing);
223 if (!is_tracing || !name_) 305 if (!is_tracing || !name_)
224 return; 306 return;
225 if (!is_locked) 307 if (!is_locked)
226 lock_.Acquire(); 308 lock_.Acquire();
227 else 309 else
228 lock_.AssertAcquired(); 310 lock_.AssertAcquired();
229 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), name_, 311 TRACE_COUNTER1(
230 incoming_queue_.size() + work_queue_.size()); 312 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), name_,
313 incoming_queue_.size() + work_queue_.size() + delayed_task_queue_.size());
231 if (!is_locked) 314 if (!is_locked)
232 lock_.Release(); 315 lock_.Release();
233 } 316 }
234 317
235 void TaskQueue::EnqueueTask(const base::PendingTask& pending_task) {
236 base::AutoLock lock(lock_);
237 EnqueueTaskLocked(pending_task);
238 }
239
240 void TaskQueue::EnqueueTaskLocked(const base::PendingTask& pending_task) { 318 void TaskQueue::EnqueueTaskLocked(const base::PendingTask& pending_task) {
241 lock_.AssertAcquired(); 319 lock_.AssertAcquired();
242 if (!task_queue_manager_) 320 if (!task_queue_manager_)
243 return; 321 return;
244 if (pump_policy_ == TaskQueueManager::PumpPolicy::AUTO && 322 if (pump_policy_ == TaskQueueManager::PumpPolicy::AUTO &&
245 incoming_queue_.empty()) 323 incoming_queue_.empty())
246 task_queue_manager_->MaybePostDoWorkOnMainRunner(); 324 task_queue_manager_->MaybePostDoWorkOnMainRunner();
247 incoming_queue_.push(pending_task); 325 incoming_queue_.push(pending_task);
248 326
249 if (!pending_task.delayed_run_time.is_null()) { 327 if (!pending_task.delayed_run_time.is_null()) {
250 // Update the time of the next pending delayed task.
251 while (!delayed_task_run_times_.empty() &&
252 delayed_task_run_times_.top() <= pending_task.delayed_run_time) {
253 delayed_task_run_times_.pop();
254 }
255 // Clear the delayed run time because we've already applied the delay 328 // Clear the delayed run time because we've already applied the delay
256 // before getting here. 329 // before getting here.
257 incoming_queue_.back().delayed_run_time = base::TimeTicks(); 330 incoming_queue_.back().delayed_run_time = base::TimeTicks();
258 } 331 }
259 TraceQueueSize(true); 332 TraceQueueSize(true);
260 } 333 }
261 334
262 void TaskQueue::SetPumpPolicy(TaskQueueManager::PumpPolicy pump_policy) { 335 void TaskQueue::SetPumpPolicy(TaskQueueManager::PumpPolicy pump_policy) {
263 base::AutoLock lock(lock_); 336 base::AutoLock lock(lock_);
264 if (pump_policy == TaskQueueManager::PumpPolicy::AUTO && 337 if (pump_policy == TaskQueueManager::PumpPolicy::AUTO &&
265 pump_policy_ != TaskQueueManager::PumpPolicy::AUTO) { 338 pump_policy_ != TaskQueueManager::PumpPolicy::AUTO) {
266 PumpQueueLocked(); 339 PumpQueueLocked();
267 } 340 }
268 pump_policy_ = pump_policy; 341 pump_policy_ = pump_policy;
269 } 342 }
270 343
271 void TaskQueue::PumpQueueLocked() { 344 void TaskQueue::PumpQueueLocked() {
272 lock_.AssertAcquired(); 345 lock_.AssertAcquired();
346 if (task_queue_manager_) {
347 LazyNow lazy_now(task_queue_manager_);
348 MoveReadyDelayedTasksToIncomingQueueLocked(&lazy_now);
349 }
273 while (!incoming_queue_.empty()) { 350 while (!incoming_queue_.empty()) {
274 work_queue_.push(incoming_queue_.front()); 351 work_queue_.push(incoming_queue_.front());
275 incoming_queue_.pop(); 352 incoming_queue_.pop();
276 } 353 }
277 if (!work_queue_.empty()) 354 if (!work_queue_.empty())
278 task_queue_manager_->MaybePostDoWorkOnMainRunner(); 355 task_queue_manager_->MaybePostDoWorkOnMainRunner();
279 } 356 }
280 357
281 void TaskQueue::PumpQueue() { 358 void TaskQueue::PumpQueue() {
282 base::AutoLock lock(lock_); 359 base::AutoLock lock(lock_);
283 PumpQueueLocked(); 360 PumpQueueLocked();
284 } 361 }
285 362
286 void TaskQueue::AsValueInto(base::trace_event::TracedValue* state) const { 363 void TaskQueue::AsValueInto(base::trace_event::TracedValue* state) const {
287 base::AutoLock lock(lock_); 364 base::AutoLock lock(lock_);
288 state->BeginDictionary(); 365 state->BeginDictionary();
289 if (name_) 366 if (name_)
290 state->SetString("name", name_); 367 state->SetString("name", name_);
291 state->SetString("pump_policy", PumpPolicyToString(pump_policy_)); 368 state->SetString("pump_policy", PumpPolicyToString(pump_policy_));
292 state->BeginArray("incoming_queue"); 369 state->BeginArray("incoming_queue");
293 QueueAsValueInto(incoming_queue_, state); 370 QueueAsValueInto(incoming_queue_, state);
294 state->EndArray(); 371 state->EndArray();
295 state->BeginArray("work_queue"); 372 state->BeginArray("work_queue");
296 QueueAsValueInto(work_queue_, state); 373 QueueAsValueInto(work_queue_, state);
374 state->BeginArray("delayed_task_queue");
375 QueueAsValueInto(delayed_task_queue_, state);
297 state->EndArray(); 376 state->EndArray();
298 state->EndDictionary(); 377 state->EndDictionary();
299 } 378 }
300 379
301 // static 380 // static
302 const char* TaskQueue::PumpPolicyToString( 381 const char* TaskQueue::PumpPolicyToString(
303 TaskQueueManager::PumpPolicy pump_policy) { 382 TaskQueueManager::PumpPolicy pump_policy) {
304 switch (pump_policy) { 383 switch (pump_policy) {
305 case TaskQueueManager::PumpPolicy::AUTO: 384 case TaskQueueManager::PumpPolicy::AUTO:
306 return "auto"; 385 return "auto";
(...skipping 11 matching lines...) Expand all
318 void TaskQueue::QueueAsValueInto(const base::TaskQueue& queue, 397 void TaskQueue::QueueAsValueInto(const base::TaskQueue& queue,
319 base::trace_event::TracedValue* state) { 398 base::trace_event::TracedValue* state) {
320 base::TaskQueue queue_copy(queue); 399 base::TaskQueue queue_copy(queue);
321 while (!queue_copy.empty()) { 400 while (!queue_copy.empty()) {
322 TaskAsValueInto(queue_copy.front(), state); 401 TaskAsValueInto(queue_copy.front(), state);
323 queue_copy.pop(); 402 queue_copy.pop();
324 } 403 }
325 } 404 }
326 405
327 // static 406 // static
407 void TaskQueue::QueueAsValueInto(const base::DelayedTaskQueue& queue,
408 base::trace_event::TracedValue* state) {
409 base::DelayedTaskQueue queue_copy(queue);
410 while (!queue_copy.empty()) {
411 TaskAsValueInto(queue_copy.top(), state);
412 queue_copy.pop();
413 }
414 }
415
416 // static
328 void TaskQueue::TaskAsValueInto(const base::PendingTask& task, 417 void TaskQueue::TaskAsValueInto(const base::PendingTask& task,
329 base::trace_event::TracedValue* state) { 418 base::trace_event::TracedValue* state) {
330 state->BeginDictionary(); 419 state->BeginDictionary();
331 state->SetString("posted_from", task.posted_from.ToString()); 420 state->SetString("posted_from", task.posted_from.ToString());
332 state->SetInteger("sequence_num", task.sequence_num); 421 state->SetInteger("sequence_num", task.sequence_num);
333 state->SetBoolean("nestable", task.nestable); 422 state->SetBoolean("nestable", task.nestable);
334 state->SetBoolean("is_high_res", task.is_high_res); 423 state->SetBoolean("is_high_res", task.is_high_res);
335 state->SetDouble( 424 state->SetDouble(
336 "delayed_run_time", 425 "delayed_run_time",
337 (task.delayed_run_time - base::TimeTicks()).InMicroseconds() / 1000.0L); 426 (task.delayed_run_time - base::TimeTicks()).InMicroseconds() / 1000.0L);
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
398 queue->SetPumpPolicy(pump_policy); 487 queue->SetPumpPolicy(pump_policy);
399 } 488 }
400 489
401 void TaskQueueManager::PumpQueue(size_t queue_index) { 490 void TaskQueueManager::PumpQueue(size_t queue_index) {
402 DCHECK(main_thread_checker_.CalledOnValidThread()); 491 DCHECK(main_thread_checker_.CalledOnValidThread());
403 internal::TaskQueue* queue = Queue(queue_index); 492 internal::TaskQueue* queue = Queue(queue_index);
404 queue->PumpQueue(); 493 queue->PumpQueue();
405 } 494 }
406 495
407 bool TaskQueueManager::UpdateWorkQueues( 496 bool TaskQueueManager::UpdateWorkQueues(
408 base::TimeTicks* next_pending_delayed_task,
409 const base::PendingTask* previous_task) { 497 const base::PendingTask* previous_task) {
410 // TODO(skyostil): This is not efficient when the number of queues grows very 498 // TODO(skyostil): This is not efficient when the number of queues grows very
411 // large due to the number of locks taken. Consider optimizing when we get 499 // large due to the number of locks taken. Consider optimizing when we get
412 // there. 500 // there.
413 DCHECK(main_thread_checker_.CalledOnValidThread()); 501 DCHECK(main_thread_checker_.CalledOnValidThread());
502 internal::LazyNow lazy_now(this);
414 bool has_work = false; 503 bool has_work = false;
415 for (auto& queue : queues_) { 504 for (auto& queue : queues_) {
416 has_work |= queue->UpdateWorkQueue(next_pending_delayed_task, 505 has_work |= queue->UpdateWorkQueue(&lazy_now, previous_task);
417 previous_task);
418 if (!queue->work_queue().empty()) { 506 if (!queue->work_queue().empty()) {
419 // Currently we should not be getting tasks with delayed run times in any 507 // Currently we should not be getting tasks with delayed run times in any
420 // of the work queues. 508 // of the work queues.
421 DCHECK(queue->work_queue().front().delayed_run_time.is_null()); 509 DCHECK(queue->work_queue().front().delayed_run_time.is_null());
422 } 510 }
423 } 511 }
424 return has_work; 512 return has_work;
425 } 513 }
426 514
427 void TaskQueueManager::MaybePostDoWorkOnMainRunner() { 515 void TaskQueueManager::MaybePostDoWorkOnMainRunner() {
(...skipping 12 matching lines...) Expand all
440 on_main_thread)); 528 on_main_thread));
441 } 529 }
442 530
443 void TaskQueueManager::DoWork(bool posted_from_main_thread) { 531 void TaskQueueManager::DoWork(bool posted_from_main_thread) {
444 if (posted_from_main_thread) { 532 if (posted_from_main_thread) {
445 pending_dowork_count_--; 533 pending_dowork_count_--;
446 DCHECK_GE(pending_dowork_count_, 0); 534 DCHECK_GE(pending_dowork_count_, 0);
447 } 535 }
448 DCHECK(main_thread_checker_.CalledOnValidThread()); 536 DCHECK(main_thread_checker_.CalledOnValidThread());
449 537
450 base::TimeTicks next_pending_delayed_task( 538 // Pass nullptr to UpdateWorkQueues here to prevent waking up a
451 base::TimeTicks::FromInternalValue(kMaxTimeTicks));
452
453 // Pass nullptr to UpdateWorkQueues here to prevent waking up an
454 // pump-after-wakeup queue. 539 // pump-after-wakeup queue.
455 if (!UpdateWorkQueues(&next_pending_delayed_task, nullptr)) 540 if (!UpdateWorkQueues(nullptr))
456 return; 541 return;
457 542
458 base::PendingTask previous_task((tracked_objects::Location()), 543 base::PendingTask previous_task((tracked_objects::Location()),
459 (base::Closure())); 544 (base::Closure()));
460 for (int i = 0; i < work_batch_size_; i++) { 545 for (int i = 0; i < work_batch_size_; i++) {
461 // Interrupt the work batch if we should run the next delayed task.
462 if (i > 0 && next_pending_delayed_task.ToInternalValue() != kMaxTimeTicks &&
463 Now() >= next_pending_delayed_task)
464 return;
465
466 size_t queue_index; 546 size_t queue_index;
467 if (!SelectWorkQueueToService(&queue_index)) 547 if (!SelectWorkQueueToService(&queue_index))
468 return; 548 return;
469 // Note that this function won't post another call to DoWork if one is 549 // Note that this function won't post another call to DoWork if one is
470 // already pending, so it is safe to call it in a loop. 550 // already pending, so it is safe to call it in a loop.
471 MaybePostDoWorkOnMainRunner(); 551 MaybePostDoWorkOnMainRunner();
472 ProcessTaskFromWorkQueue(queue_index, i > 0, &previous_task); 552 ProcessTaskFromWorkQueue(queue_index, i > 0, &previous_task);
473 553
474 if (!UpdateWorkQueues(&next_pending_delayed_task, &previous_task)) 554 if (!UpdateWorkQueues(&previous_task))
475 return; 555 return;
476 } 556 }
477 } 557 }
478 558
479 bool TaskQueueManager::SelectWorkQueueToService(size_t* out_queue_index) { 559 bool TaskQueueManager::SelectWorkQueueToService(size_t* out_queue_index) {
480 bool should_run = selector_->SelectWorkQueueToService(out_queue_index); 560 bool should_run = selector_->SelectWorkQueueToService(out_queue_index);
481 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( 561 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
482 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "TaskQueueManager", this, 562 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "TaskQueueManager", this,
483 AsValueWithSelectorResult(should_run, *out_queue_index)); 563 AsValueWithSelectorResult(should_run, *out_queue_index));
484 return should_run; 564 return should_run;
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
578 state->EndArray(); 658 state->EndArray();
579 state->BeginDictionary("selector"); 659 state->BeginDictionary("selector");
580 selector_->AsValueInto(state.get()); 660 selector_->AsValueInto(state.get());
581 state->EndDictionary(); 661 state->EndDictionary();
582 if (should_run) 662 if (should_run)
583 state->SetInteger("selected_queue", selected_queue); 663 state->SetInteger("selected_queue", selected_queue);
584 return state; 664 return state;
585 } 665 }
586 666
587 } // namespace content 667 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698