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

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: Sami's Suggestions 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 class LazyNow {
Sami 2015/03/17 15:54:45 Neat helper!
alex clarke (OOO till 29th) 2015/03/17 16:53:06 Acknowledged.
25 public:
26 explicit LazyNow(base::TimeTicks now)
27 : task_queue_manager_(nullptr), now_(now) {
28 DCHECK(!now.is_null());
29 }
30
31 explicit LazyNow(TaskQueueManager* task_queue_manager)
32 : task_queue_manager_(task_queue_manager) {}
33
34 base::TimeTicks Now() {
35 if (now_.is_null())
36 now_ = task_queue_manager_->Now();
37 return now_;
38 }
39
40 private:
41 TaskQueueManager* task_queue_manager_; // NOT OWNED
42 base::TimeTicks now_;
43 };
44
23 class TaskQueue : public base::SingleThreadTaskRunner { 45 class TaskQueue : public base::SingleThreadTaskRunner {
24 public: 46 public:
25 TaskQueue(TaskQueueManager* task_queue_manager); 47 TaskQueue(TaskQueueManager* task_queue_manager);
26 48
27 // base::SingleThreadTaskRunner implementation. 49 // base::SingleThreadTaskRunner implementation.
28 bool RunsTasksOnCurrentThread() const override; 50 bool RunsTasksOnCurrentThread() const override;
29 bool PostDelayedTask(const tracked_objects::Location& from_here, 51 bool PostDelayedTask(const tracked_objects::Location& from_here,
30 const base::Closure& task, 52 const base::Closure& task,
31 base::TimeDelta delay) override { 53 base::TimeDelta delay) override {
32 return PostDelayedTaskImpl(from_here, task, delay, TaskType::NORMAL); 54 return PostDelayedTaskImpl(from_here, task, delay, TaskType::NORMAL);
33 } 55 }
34 56
35 bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here, 57 bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
36 const base::Closure& task, 58 const base::Closure& task,
37 base::TimeDelta delay) override { 59 base::TimeDelta delay) override {
38 return PostDelayedTaskImpl(from_here, task, delay, TaskType::NON_NESTABLE); 60 return PostDelayedTaskImpl(from_here, task, delay, TaskType::NON_NESTABLE);
39 } 61 }
40 62
41 bool IsQueueEmpty() const; 63 bool IsQueueEmpty() const;
42 64
43 void SetPumpPolicy(TaskQueueManager::PumpPolicy pump_policy); 65 void SetPumpPolicy(TaskQueueManager::PumpPolicy pump_policy);
44 void PumpQueue(); 66 void PumpQueue();
45 67
46 bool UpdateWorkQueue(base::TimeTicks* next_pending_delayed_task, 68 bool UpdateWorkQueue(LazyNow* lazy_now,
47 const base::PendingTask* previous_task); 69 const base::PendingTask* previous_task);
48 base::PendingTask TakeTaskFromWorkQueue(); 70 base::PendingTask TakeTaskFromWorkQueue();
49 71
50 void WillDeleteTaskQueueManager(); 72 void WillDeleteTaskQueueManager();
51 73
52 base::TaskQueue& work_queue() { return work_queue_; } 74 base::TaskQueue& work_queue() { return work_queue_; }
53 75
54 void set_name(const char* name) { name_ = name; } 76 void set_name(const char* name) { name_ = name; }
55 77
56 void AsValueInto(base::trace_event::TracedValue* state) const; 78 void AsValueInto(base::trace_event::TracedValue* state) const;
57 79
58 private: 80 private:
59 enum class TaskType { 81 enum class TaskType {
60 NORMAL, 82 NORMAL,
61 NON_NESTABLE, 83 NON_NESTABLE,
62 }; 84 };
63 85
64 ~TaskQueue() override; 86 ~TaskQueue() override;
65 87
66 bool PostDelayedTaskImpl(const tracked_objects::Location& from_here, 88 bool PostDelayedTaskImpl(const tracked_objects::Location& from_here,
67 const base::Closure& task, 89 const base::Closure& task,
68 base::TimeDelta delay, 90 base::TimeDelta delay,
69 TaskType task_type); 91 TaskType task_type);
70 92
71 // Adds a task at the end of the incoming task queue and schedules a call to 93 // Delayed task posted to the chromium run loop, which calls
Sami 2015/03/17 15:54:44 nit: Replace "chromium" with "base" or "underlying
alex clarke (OOO till 29th) 2015/03/17 16:53:06 Done.
72 // TaskQueueManager::DoWork() if the incoming queue was empty and automatic 94 // ScheduleDelayedWorkLocked to enqueue any delayed timers which should be run
73 // pumping is enabled. Can be called on an arbitrary thread. 95 // now.
74 void EnqueueTask(const base::PendingTask& pending_task); 96 void KickDelayedTasks();
97
98 // Enqueues any delayed timers which should be run now, and (maybe) posts
99 // KickDelayedTasks if there isn't already a timer posted on the chromium
100 // runloop for the next task's scheduled run time.
101 bool ScheduleDelayedWorkLocked(LazyNow* lazy_now);
102
103 // Enqueues any delayed timers which should be run now.
104 bool EnqueueReadyDelayedTasksLocked(LazyNow* lazy_now);
Sami 2015/03/17 15:54:45 We should come up with a better name for this beca
alex clarke (OOO till 29th) 2015/03/17 16:53:06 How about MoveReadyDelayedTasksToWorkQueueLocked?
75 105
76 void PumpQueueLocked(); 106 void PumpQueueLocked();
77 bool TaskIsOlderThanQueuedTasks(const base::PendingTask* task); 107 bool TaskIsOlderThanQueuedTasks(const base::PendingTask* task);
78 bool ShouldAutoPumpQueueLocked(const base::PendingTask* previous_task); 108 bool ShouldAutoPumpQueueLocked(const base::PendingTask* previous_task);
79 void EnqueueTaskLocked(const base::PendingTask& pending_task); 109 void EnqueueTaskLocked(const base::PendingTask& pending_task);
80 110
81 void TraceQueueSize(bool is_locked) const; 111 void TraceQueueSize(bool is_locked) const;
82 static const char* PumpPolicyToString( 112 static const char* PumpPolicyToString(
83 TaskQueueManager::PumpPolicy pump_policy); 113 TaskQueueManager::PumpPolicy pump_policy);
84 static void QueueAsValueInto(const base::TaskQueue& queue, 114 static void QueueAsValueInto(const base::TaskQueue& queue,
85 base::trace_event::TracedValue* state); 115 base::trace_event::TracedValue* state);
86 static void TaskAsValueInto(const base::PendingTask& task, 116 static void TaskAsValueInto(const base::PendingTask& task,
87 base::trace_event::TracedValue* state); 117 base::trace_event::TracedValue* state);
88 118
89 // This lock protects all members except the work queue. 119 // This lock protects all members except the work queue.
90 mutable base::Lock lock_; 120 mutable base::Lock lock_;
91 base::PlatformThreadId thread_id_; 121 base::PlatformThreadId thread_id_;
92 TaskQueueManager* task_queue_manager_; 122 TaskQueueManager* task_queue_manager_;
93 base::TaskQueue incoming_queue_; 123 base::TaskQueue incoming_queue_;
94 TaskQueueManager::PumpPolicy pump_policy_; 124 TaskQueueManager::PumpPolicy pump_policy_;
95 const char* name_; 125 const char* name_;
96 std::priority_queue<base::TimeTicks, 126 base::DelayedTaskQueue delayed_task_queue_;
97 std::vector<base::TimeTicks>, 127 std::set<base::TimeTicks> in_flight_kick_delayed_tasks_;
98 std::greater<base::TimeTicks>> delayed_task_run_times_;
99 128
100 base::TaskQueue work_queue_; 129 base::TaskQueue work_queue_;
101 130
102 DISALLOW_COPY_AND_ASSIGN(TaskQueue); 131 DISALLOW_COPY_AND_ASSIGN(TaskQueue);
103 }; 132 };
104 133
105 TaskQueue::TaskQueue(TaskQueueManager* task_queue_manager) 134 TaskQueue::TaskQueue(TaskQueueManager* task_queue_manager)
106 : thread_id_(base::PlatformThread::CurrentId()), 135 : thread_id_(base::PlatformThread::CurrentId()),
107 task_queue_manager_(task_queue_manager), 136 task_queue_manager_(task_queue_manager),
108 pump_policy_(TaskQueueManager::PumpPolicy::AUTO), 137 pump_policy_(TaskQueueManager::PumpPolicy::AUTO),
109 name_(nullptr) { 138 name_(nullptr) {
110 } 139 }
111 140
112 TaskQueue::~TaskQueue() { 141 TaskQueue::~TaskQueue() {
113 } 142 }
114 143
115 void TaskQueue::WillDeleteTaskQueueManager() { 144 void TaskQueue::WillDeleteTaskQueueManager() {
116 base::AutoLock lock(lock_); 145 base::AutoLock lock(lock_);
117 task_queue_manager_ = nullptr; 146 task_queue_manager_ = nullptr;
147
148 // Clear all delayed tasks because we need them to be deleted before the blink
Sami 2015/03/17 15:54:44 TQM shouldn't really know anything about blink so
alex clarke (OOO till 29th) 2015/03/17 16:53:06 Probably no since the existing implementations of
149 // heap goes away.
150 while (!delayed_task_queue_.empty())
Sami 2015/03/17 15:54:45 nit: would delayed_task_queue_ = base::DelayedTask
alex clarke (OOO till 29th) 2015/03/17 16:53:06 Done.
151 delayed_task_queue_.pop();
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 return 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 bool TaskQueue::EnqueueReadyDelayedTasksLocked(LazyNow* lazy_now) {
187 lock_.AssertAcquired();
Sami 2015/03/17 15:54:45 Could you DCHECK that we're on the main thread her
alex clarke (OOO till 29th) 2015/03/17 16:53:06 Done.
188 bool task_enqueued = false;
189 // Enqueue all delayed tasks that should be running now.
190 while (!delayed_task_queue_.empty() &&
191 delayed_task_queue_.top().delayed_run_time <= lazy_now->Now()) {
192 in_flight_kick_delayed_tasks_.erase(
193 delayed_task_queue_.top().delayed_run_time);
194 base::PendingTask task = delayed_task_queue_.top();
195 delayed_task_queue_.pop();
196 task.delayed_run_time = base::TimeTicks();
Sami 2015/03/17 15:54:45 Could you add a TODO here about not clearing this
alex clarke (OOO till 29th) 2015/03/17 16:53:06 Done.
197 work_queue_.push(task);
198 task_enqueued = true;
199 }
200 return task_enqueued;
201 }
202
203 bool TaskQueue::ScheduleDelayedWorkLocked(LazyNow* lazy_now) {
204 lock_.AssertAcquired();
205 bool task_enqueued = false;
206 if (pump_policy_ == TaskQueueManager::PumpPolicy::AUTO)
207 task_enqueued = EnqueueReadyDelayedTasksLocked(lazy_now);
Sami 2015/03/17 15:54:45 We can't call this here because the work queue is
alex clarke (OOO till 29th) 2015/03/17 16:53:06 Done.
208
209 // Any remaining tasks are in the future, so queue a task to kick them.
210 if (!delayed_task_queue_.empty()) {
211 base::TimeTicks next_run_time = delayed_task_queue_.top().delayed_run_time;
212 // Make sure we don't have more than one KickDelayedTasks posted for a
213 // particular scheduled run time (note it's fine to have multiple ones in
214 // flight for distinct run times).
215 if (in_flight_kick_delayed_tasks_.find(next_run_time) ==
216 in_flight_kick_delayed_tasks_.end()) {
217 in_flight_kick_delayed_tasks_.insert(next_run_time);
218 base::TimeDelta delay = next_run_time - lazy_now->Now();
219 task_queue_manager_->PostDelayedTask(
220 FROM_HERE, Bind(&TaskQueue::KickDelayedTasks, this), delay);
221 }
222 }
223 return task_enqueued;
224 }
225
226 void TaskQueue::KickDelayedTasks() {
227 bool task_enqueued;
Sami 2015/03/17 15:54:45 DCHECK main thread.
alex clarke (OOO till 29th) 2015/03/17 16:53:06 Done.
228 {
229 base::AutoLock lock(lock_);
230 LazyNow lazy_now(task_queue_manager_);
Sami 2015/03/17 15:54:45 task_queue_manager_ might be deleted by now.
alex clarke (OOO till 29th) 2015/03/17 16:53:06 Done.
231 task_enqueued = ScheduleDelayedWorkLocked(&lazy_now);
232 }
233 if (task_enqueued)
234 task_queue_manager_->DoWork(false);
235 }
236
147 bool TaskQueue::IsQueueEmpty() const { 237 bool TaskQueue::IsQueueEmpty() const {
148 if (!work_queue_.empty()) 238 if (!work_queue_.empty())
149 return false; 239 return false;
150 240
151 { 241 {
152 base::AutoLock lock(lock_); 242 base::AutoLock lock(lock_);
153 return incoming_queue_.empty(); 243 return incoming_queue_.empty();
154 } 244 }
155 } 245 }
156 246
(...skipping 25 matching lines...) Expand all
182 if (pump_policy_ == TaskQueueManager::PumpPolicy::MANUAL) 272 if (pump_policy_ == TaskQueueManager::PumpPolicy::MANUAL)
183 return false; 273 return false;
184 if (pump_policy_ == TaskQueueManager::PumpPolicy::AFTER_WAKEUP && 274 if (pump_policy_ == TaskQueueManager::PumpPolicy::AFTER_WAKEUP &&
185 TaskIsOlderThanQueuedTasks(previous_task)) 275 TaskIsOlderThanQueuedTasks(previous_task))
186 return false; 276 return false;
187 if (incoming_queue_.empty()) 277 if (incoming_queue_.empty())
188 return false; 278 return false;
189 return true; 279 return true;
190 } 280 }
191 281
192 bool TaskQueue::UpdateWorkQueue( 282 bool TaskQueue::UpdateWorkQueue(LazyNow* lazy_now,
193 base::TimeTicks* next_pending_delayed_task, 283 const base::PendingTask* previous_task) {
194 const base::PendingTask* previous_task) {
195 if (!work_queue_.empty()) 284 if (!work_queue_.empty())
196 return true; 285 return true;
197 286
198 { 287 {
199 base::AutoLock lock(lock_); 288 base::AutoLock lock(lock_);
200 if (!delayed_task_run_times_.empty()) { 289 EnqueueReadyDelayedTasksLocked(lazy_now);
201 *next_pending_delayed_task =
202 std::min(*next_pending_delayed_task, delayed_task_run_times_.top());
203 }
204 if (!ShouldAutoPumpQueueLocked(previous_task)) 290 if (!ShouldAutoPumpQueueLocked(previous_task))
205 return false; 291 return false;
206 work_queue_.Swap(&incoming_queue_); 292 work_queue_.Swap(&incoming_queue_);
207 TraceQueueSize(true); 293 TraceQueueSize(true);
208 return true; 294 return true;
209 } 295 }
210 } 296 }
211 297
212 base::PendingTask TaskQueue::TakeTaskFromWorkQueue() { 298 base::PendingTask TaskQueue::TakeTaskFromWorkQueue() {
213 base::PendingTask pending_task = work_queue_.front(); 299 base::PendingTask pending_task = work_queue_.front();
214 work_queue_.pop(); 300 work_queue_.pop();
215 TraceQueueSize(false); 301 TraceQueueSize(false);
216 return pending_task; 302 return pending_task;
217 } 303 }
218 304
219 void TaskQueue::TraceQueueSize(bool is_locked) const { 305 void TaskQueue::TraceQueueSize(bool is_locked) const {
220 bool is_tracing; 306 bool is_tracing;
221 TRACE_EVENT_CATEGORY_GROUP_ENABLED( 307 TRACE_EVENT_CATEGORY_GROUP_ENABLED(
222 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), &is_tracing); 308 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), &is_tracing);
223 if (!is_tracing || !name_) 309 if (!is_tracing || !name_)
224 return; 310 return;
225 if (!is_locked) 311 if (!is_locked)
226 lock_.Acquire(); 312 lock_.Acquire();
227 else 313 else
228 lock_.AssertAcquired(); 314 lock_.AssertAcquired();
229 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), name_, 315 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), name_,
Sami 2015/03/17 15:54:45 Could you add the delayed task queue here too?
alex clarke (OOO till 29th) 2015/03/17 16:53:06 Done.
230 incoming_queue_.size() + work_queue_.size()); 316 incoming_queue_.size() + work_queue_.size());
231 if (!is_locked) 317 if (!is_locked)
232 lock_.Release(); 318 lock_.Release();
233 } 319 }
234 320
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) { 321 void TaskQueue::EnqueueTaskLocked(const base::PendingTask& pending_task) {
241 lock_.AssertAcquired(); 322 lock_.AssertAcquired();
242 if (!task_queue_manager_) 323 if (!task_queue_manager_)
243 return; 324 return;
244 if (pump_policy_ == TaskQueueManager::PumpPolicy::AUTO && 325 if (pump_policy_ == TaskQueueManager::PumpPolicy::AUTO &&
245 incoming_queue_.empty()) 326 incoming_queue_.empty())
246 task_queue_manager_->MaybePostDoWorkOnMainRunner(); 327 task_queue_manager_->MaybePostDoWorkOnMainRunner();
247 incoming_queue_.push(pending_task); 328 incoming_queue_.push(pending_task);
248 329
249 if (!pending_task.delayed_run_time.is_null()) { 330 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 331 // Clear the delayed run time because we've already applied the delay
256 // before getting here. 332 // before getting here.
257 incoming_queue_.back().delayed_run_time = base::TimeTicks(); 333 incoming_queue_.back().delayed_run_time = base::TimeTicks();
258 } 334 }
259 TraceQueueSize(true); 335 TraceQueueSize(true);
260 } 336 }
261 337
262 void TaskQueue::SetPumpPolicy(TaskQueueManager::PumpPolicy pump_policy) { 338 void TaskQueue::SetPumpPolicy(TaskQueueManager::PumpPolicy pump_policy) {
263 base::AutoLock lock(lock_); 339 base::AutoLock lock(lock_);
264 if (pump_policy == TaskQueueManager::PumpPolicy::AUTO && 340 if (pump_policy == TaskQueueManager::PumpPolicy::AUTO &&
265 pump_policy_ != TaskQueueManager::PumpPolicy::AUTO) { 341 pump_policy_ != TaskQueueManager::PumpPolicy::AUTO) {
266 PumpQueueLocked(); 342 PumpQueueLocked();
267 } 343 }
268 pump_policy_ = pump_policy; 344 pump_policy_ = pump_policy;
269 } 345 }
270 346
271 void TaskQueue::PumpQueueLocked() { 347 void TaskQueue::PumpQueueLocked() {
272 lock_.AssertAcquired(); 348 lock_.AssertAcquired();
349 if (task_queue_manager_) {
350 LazyNow lazy_now(task_queue_manager_);
351 EnqueueReadyDelayedTasksLocked(&lazy_now);
352 }
273 while (!incoming_queue_.empty()) { 353 while (!incoming_queue_.empty()) {
274 work_queue_.push(incoming_queue_.front()); 354 work_queue_.push(incoming_queue_.front());
275 incoming_queue_.pop(); 355 incoming_queue_.pop();
276 } 356 }
277 if (!work_queue_.empty()) 357 if (!work_queue_.empty())
278 task_queue_manager_->MaybePostDoWorkOnMainRunner(); 358 task_queue_manager_->MaybePostDoWorkOnMainRunner();
279 } 359 }
280 360
281 void TaskQueue::PumpQueue() { 361 void TaskQueue::PumpQueue() {
282 base::AutoLock lock(lock_); 362 base::AutoLock lock(lock_);
283 PumpQueueLocked(); 363 PumpQueueLocked();
284 } 364 }
285 365
286 void TaskQueue::AsValueInto(base::trace_event::TracedValue* state) const { 366 void TaskQueue::AsValueInto(base::trace_event::TracedValue* state) const {
287 base::AutoLock lock(lock_); 367 base::AutoLock lock(lock_);
288 state->BeginDictionary(); 368 state->BeginDictionary();
289 if (name_) 369 if (name_)
290 state->SetString("name", name_); 370 state->SetString("name", name_);
291 state->SetString("pump_policy", PumpPolicyToString(pump_policy_)); 371 state->SetString("pump_policy", PumpPolicyToString(pump_policy_));
292 state->BeginArray("incoming_queue"); 372 state->BeginArray("incoming_queue");
293 QueueAsValueInto(incoming_queue_, state); 373 QueueAsValueInto(incoming_queue_, state);
294 state->EndArray(); 374 state->EndArray();
295 state->BeginArray("work_queue"); 375 state->BeginArray("work_queue");
Sami 2015/03/17 15:54:45 Could you dump the delayed task queue here too? Al
alex clarke (OOO till 29th) 2015/03/17 16:53:06 Done.
296 QueueAsValueInto(work_queue_, state); 376 QueueAsValueInto(work_queue_, state);
297 state->EndArray(); 377 state->EndArray();
298 state->EndDictionary(); 378 state->EndDictionary();
299 } 379 }
300 380
301 // static 381 // static
302 const char* TaskQueue::PumpPolicyToString( 382 const char* TaskQueue::PumpPolicyToString(
303 TaskQueueManager::PumpPolicy pump_policy) { 383 TaskQueueManager::PumpPolicy pump_policy) {
304 switch (pump_policy) { 384 switch (pump_policy) {
305 case TaskQueueManager::PumpPolicy::AUTO: 385 case TaskQueueManager::PumpPolicy::AUTO:
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
398 queue->SetPumpPolicy(pump_policy); 478 queue->SetPumpPolicy(pump_policy);
399 } 479 }
400 480
401 void TaskQueueManager::PumpQueue(size_t queue_index) { 481 void TaskQueueManager::PumpQueue(size_t queue_index) {
402 DCHECK(main_thread_checker_.CalledOnValidThread()); 482 DCHECK(main_thread_checker_.CalledOnValidThread());
403 internal::TaskQueue* queue = Queue(queue_index); 483 internal::TaskQueue* queue = Queue(queue_index);
404 queue->PumpQueue(); 484 queue->PumpQueue();
405 } 485 }
406 486
407 bool TaskQueueManager::UpdateWorkQueues( 487 bool TaskQueueManager::UpdateWorkQueues(
408 base::TimeTicks* next_pending_delayed_task,
409 const base::PendingTask* previous_task) { 488 const base::PendingTask* previous_task) {
410 // TODO(skyostil): This is not efficient when the number of queues grows very 489 // 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 490 // large due to the number of locks taken. Consider optimizing when we get
412 // there. 491 // there.
413 DCHECK(main_thread_checker_.CalledOnValidThread()); 492 DCHECK(main_thread_checker_.CalledOnValidThread());
493 internal::LazyNow lazy_now(this);
414 bool has_work = false; 494 bool has_work = false;
415 for (auto& queue : queues_) { 495 for (auto& queue : queues_) {
416 has_work |= queue->UpdateWorkQueue(next_pending_delayed_task, 496 has_work |= queue->UpdateWorkQueue(&lazy_now, previous_task);
417 previous_task);
418 if (!queue->work_queue().empty()) { 497 if (!queue->work_queue().empty()) {
419 // Currently we should not be getting tasks with delayed run times in any 498 // Currently we should not be getting tasks with delayed run times in any
420 // of the work queues. 499 // of the work queues.
421 DCHECK(queue->work_queue().front().delayed_run_time.is_null()); 500 DCHECK(queue->work_queue().front().delayed_run_time.is_null());
422 } 501 }
423 } 502 }
424 return has_work; 503 return has_work;
425 } 504 }
426 505
427 void TaskQueueManager::MaybePostDoWorkOnMainRunner() { 506 void TaskQueueManager::MaybePostDoWorkOnMainRunner() {
(...skipping 12 matching lines...) Expand all
440 on_main_thread)); 519 on_main_thread));
441 } 520 }
442 521
443 void TaskQueueManager::DoWork(bool posted_from_main_thread) { 522 void TaskQueueManager::DoWork(bool posted_from_main_thread) {
444 if (posted_from_main_thread) { 523 if (posted_from_main_thread) {
445 pending_dowork_count_--; 524 pending_dowork_count_--;
446 DCHECK_GE(pending_dowork_count_, 0); 525 DCHECK_GE(pending_dowork_count_, 0);
447 } 526 }
448 DCHECK(main_thread_checker_.CalledOnValidThread()); 527 DCHECK(main_thread_checker_.CalledOnValidThread());
449 528
450 base::TimeTicks next_pending_delayed_task( 529 // 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. 530 // pump-after-wakeup queue.
455 if (!UpdateWorkQueues(&next_pending_delayed_task, nullptr)) 531 if (!UpdateWorkQueues(nullptr))
456 return; 532 return;
457 533
458 base::PendingTask previous_task((tracked_objects::Location()), 534 base::PendingTask previous_task((tracked_objects::Location()),
459 (base::Closure())); 535 (base::Closure()));
460 for (int i = 0; i < work_batch_size_; i++) { 536 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; 537 size_t queue_index;
467 if (!SelectWorkQueueToService(&queue_index)) 538 if (!SelectWorkQueueToService(&queue_index))
468 return; 539 return;
469 // Note that this function won't post another call to DoWork if one is 540 // 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. 541 // already pending, so it is safe to call it in a loop.
471 MaybePostDoWorkOnMainRunner(); 542 MaybePostDoWorkOnMainRunner();
472 ProcessTaskFromWorkQueue(queue_index, i > 0, &previous_task); 543 ProcessTaskFromWorkQueue(queue_index, i > 0, &previous_task);
473 544
474 if (!UpdateWorkQueues(&next_pending_delayed_task, &previous_task)) 545 if (!UpdateWorkQueues(&previous_task))
475 return; 546 return;
476 } 547 }
477 } 548 }
478 549
479 bool TaskQueueManager::SelectWorkQueueToService(size_t* out_queue_index) { 550 bool TaskQueueManager::SelectWorkQueueToService(size_t* out_queue_index) {
480 bool should_run = selector_->SelectWorkQueueToService(out_queue_index); 551 bool should_run = selector_->SelectWorkQueueToService(out_queue_index);
481 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( 552 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
482 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "TaskQueueManager", this, 553 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "TaskQueueManager", this,
483 AsValueWithSelectorResult(should_run, *out_queue_index)); 554 AsValueWithSelectorResult(should_run, *out_queue_index));
484 return should_run; 555 return should_run;
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
578 state->EndArray(); 649 state->EndArray();
579 state->BeginDictionary("selector"); 650 state->BeginDictionary("selector");
580 selector_->AsValueInto(state.get()); 651 selector_->AsValueInto(state.get());
581 state->EndDictionary(); 652 state->EndDictionary();
582 if (should_run) 653 if (should_run)
583 state->SetInteger("selected_queue", selected_queue); 654 state->SetInteger("selected_queue", selected_queue);
584 return state; 655 return state;
585 } 656 }
586 657
587 } // namespace content 658 } // 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