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

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

Powered by Google App Engine
This is Rietveld 408576698