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

Side by Side Diff: third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc

Issue 2644553002: Refactor TimeDomain::MaybeAdvanceTime in preparation for DoWork deduping (Closed)
Patch Set: Add tests for ComputeDelayTillNextTask Created 3 years, 11 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 "platform/scheduler/base/task_queue_manager.h" 5 #include "platform/scheduler/base/task_queue_manager.h"
6 6
7 #include <queue> 7 #include <queue>
8 #include <set> 8 #include <set>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
140 observer_->OnUnregisterTaskQueue(task_queue); 140 observer_->OnUnregisterTaskQueue(task_queue);
141 141
142 // Add |task_queue| to |queues_to_delete_| so we can prevent it from being 142 // Add |task_queue| to |queues_to_delete_| so we can prevent it from being
143 // freed while any of our structures hold hold a raw pointer to it. 143 // freed while any of our structures hold hold a raw pointer to it.
144 queues_to_delete_.insert(task_queue); 144 queues_to_delete_.insert(task_queue);
145 queues_.erase(task_queue); 145 queues_.erase(task_queue);
146 146
147 selector_.RemoveQueue(task_queue.get()); 147 selector_.RemoveQueue(task_queue.get());
148 } 148 }
149 149
150 void TaskQueueManager::UpdateWorkQueues(LazyNow lazy_now) { 150 void TaskQueueManager::UpdateWorkQueues(LazyNow* lazy_now) {
151 TRACE_EVENT0(disabled_by_default_tracing_category_, 151 TRACE_EVENT0(disabled_by_default_tracing_category_,
152 "TaskQueueManager::UpdateWorkQueues"); 152 "TaskQueueManager::UpdateWorkQueues");
153 153
154 for (TimeDomain* time_domain : time_domains_) { 154 for (TimeDomain* time_domain : time_domains_) {
155 LazyNow lazy_now_in_domain = time_domain == real_time_domain_.get() 155 if (time_domain == real_time_domain_.get()) {
156 ? lazy_now 156 time_domain->UpdateWorkQueues(lazy_now);
157 : time_domain->CreateLazyNow(); 157 } else {
158 time_domain->UpdateWorkQueues(lazy_now_in_domain); 158 LazyNow time_domain_lazy_now = time_domain->CreateLazyNow();
159 time_domain->UpdateWorkQueues(&time_domain_lazy_now);
160 }
159 } 161 }
160 } 162 }
161 163
162 void TaskQueueManager::OnBeginNestedMessageLoop() { 164 void TaskQueueManager::OnBeginNestedMessageLoop() {
163 // We just entered a nested message loop, make sure there's a DoWork posted or 165 // We just entered a nested message loop, make sure there's a DoWork posted or
164 // the system will grind to a halt. 166 // the system will grind to a halt.
165 delegate_->PostTask(FROM_HERE, from_main_thread_immediate_do_work_closure_); 167 delegate_->PostTask(FROM_HERE, from_main_thread_immediate_do_work_closure_);
166 } 168 }
167 169
168 void TaskQueueManager::MaybeScheduleImmediateWork( 170 void TaskQueueManager::MaybeScheduleImmediateWork(
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
224 base::AutoLock lock(other_thread_lock_); 226 base::AutoLock lock(other_thread_lock_);
225 other_thread_pending_wakeup_ = false; 227 other_thread_pending_wakeup_ = false;
226 } 228 }
227 229
228 // Posting a DoWork while a DoWork is running leads to spurious DoWorks. 230 // Posting a DoWork while a DoWork is running leads to spurious DoWorks.
229 main_thread_pending_wakeups_.insert(base::TimeTicks()); 231 main_thread_pending_wakeups_.insert(base::TimeTicks());
230 232
231 if (!delegate_->IsNested()) 233 if (!delegate_->IsNested())
232 queues_to_delete_.clear(); 234 queues_to_delete_.clear();
233 235
234 LazyNow lazy_now(real_time_domain()->CreateLazyNow()); 236 LazyNow lazy_now(real_time_domain()->CreateLazyNow());
Sami 2017/01/18 18:45:57 General comment re: |lazy_now|, not sure if it con
235 UpdateWorkQueues(lazy_now); 237 UpdateWorkQueues(&lazy_now);
236 238
237 for (int i = 0; i < work_batch_size_; i++) { 239 for (int i = 0; i < work_batch_size_; i++) {
238 internal::WorkQueue* work_queue; 240 internal::WorkQueue* work_queue;
239 if (!SelectWorkQueueToService(&work_queue)) 241 if (!SelectWorkQueueToService(&work_queue))
240 break; 242 break;
241 243
242 switch (ProcessTaskFromWorkQueue(work_queue, &lazy_now)) { 244 switch (ProcessTaskFromWorkQueue(work_queue, &lazy_now)) {
243 case ProcessTaskResult::DEFERRED: 245 case ProcessTaskResult::DEFERRED:
244 // If a task was deferred, try again with another task. 246 // If a task was deferred, try again with another task.
245 continue; 247 continue;
246 case ProcessTaskResult::EXECUTED: 248 case ProcessTaskResult::EXECUTED:
247 break; 249 break;
248 case ProcessTaskResult::TASK_QUEUE_MANAGER_DELETED: 250 case ProcessTaskResult::TASK_QUEUE_MANAGER_DELETED:
249 return; // The TaskQueueManager got deleted, we must bail out. 251 return; // The TaskQueueManager got deleted, we must bail out.
250 } 252 }
251 253
252 work_queue = nullptr; // The queue may have been unregistered. 254 work_queue = nullptr; // The queue may have been unregistered.
253 255
254 UpdateWorkQueues(lazy_now); 256 UpdateWorkQueues(&lazy_now);
255 257
256 // Only run a single task per batch in nested run loops so that we can 258 // Only run a single task per batch in nested run loops so that we can
257 // properly exit the nested loop when someone calls RunLoop::Quit(). 259 // properly exit the nested loop when someone calls RunLoop::Quit().
258 if (delegate_->IsNested()) 260 if (delegate_->IsNested())
259 break; 261 break;
260 } 262 }
261 263
262 main_thread_pending_wakeups_.erase(base::TimeTicks()); 264 main_thread_pending_wakeups_.erase(base::TimeTicks());
263 265
264 // TODO(alexclarke): Consider refactoring the above loop to terminate only 266 // TODO(alexclarke): Consider refactoring the above loop to terminate only
265 // when there's no more work left to be done, rather than posting a 267 // when there's no more work left to be done, rather than posting a
266 // continuation task. 268 // continuation task.
267 if (!selector_.EnabledWorkQueuesEmpty() || TryAdvanceTimeDomains()) 269 base::Optional<base::TimeDelta> next_delay =
270 ComputeDelayTillNextTask(&lazy_now);
271
272 if (!next_delay)
273 return;
274
275 base::TimeDelta delay = next_delay.value();
276 if (delay.is_zero()) {
268 MaybeScheduleImmediateWork(FROM_HERE); 277 MaybeScheduleImmediateWork(FROM_HERE);
278 } else {
279 MaybeScheduleDelayedWork(FROM_HERE, lazy_now.Now(), delay);
280 }
269 } 281 }
270 282
271 bool TaskQueueManager::TryAdvanceTimeDomains() { 283 base::Optional<base::TimeDelta> TaskQueueManager::ComputeDelayTillNextTask(
272 bool can_advance = false; 284 LazyNow* lazy_now) {
285 // If the selector has non-empty queues we trivially know there is immediate
286 // work to be done.
287 if (!selector_.EnabledWorkQueuesEmpty())
288 return base::TimeDelta();
289
290 // Otherwise we need to find the shortest delay, if any.
291 base::Optional<base::TimeDelta> next_continuation;
273 for (TimeDomain* time_domain : time_domains_) { 292 for (TimeDomain* time_domain : time_domains_) {
274 can_advance |= time_domain->MaybeAdvanceTime(); 293 base::Optional<base::TimeDelta> continuation =
294 time_domain->DelayTillNextTask(lazy_now);
295 if (!continuation)
296 continue;
297 if (!next_continuation || next_continuation.value() > continuation.value())
298 next_continuation = continuation;
275 } 299 }
276 return can_advance; 300 return next_continuation;
277 } 301 }
278 302
279 bool TaskQueueManager::SelectWorkQueueToService( 303 bool TaskQueueManager::SelectWorkQueueToService(
280 internal::WorkQueue** out_work_queue) { 304 internal::WorkQueue** out_work_queue) {
281 bool should_run = selector_.SelectWorkQueueToService(out_work_queue); 305 bool should_run = selector_.SelectWorkQueueToService(out_work_queue);
282 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( 306 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
283 disabled_by_default_tracing_category_, "TaskQueueManager", this, 307 disabled_by_default_tracing_category_, "TaskQueueManager", this,
284 AsValueWithSelectorResult(should_run, *out_work_queue)); 308 AsValueWithSelectorResult(should_run, *out_work_queue));
285 return should_run; 309 return should_run;
286 } 310 }
287 311
288 void TaskQueueManager::DidQueueTask( 312 void TaskQueueManager::DidQueueTask(
289 const internal::TaskQueueImpl::Task& pending_task) { 313 const internal::TaskQueueImpl::Task& pending_task) {
290 task_annotator_.DidQueueTask("TaskQueueManager::PostTask", pending_task); 314 task_annotator_.DidQueueTask("TaskQueueManager::PostTask", pending_task);
291 } 315 }
292 316
293 TaskQueueManager::ProcessTaskResult TaskQueueManager::ProcessTaskFromWorkQueue( 317 TaskQueueManager::ProcessTaskResult TaskQueueManager::ProcessTaskFromWorkQueue(
294 internal::WorkQueue* work_queue, 318 internal::WorkQueue* work_queue,
295 LazyNow* lazy_now) { 319 LazyNow* lazy_now) {
296 DCHECK(main_thread_checker_.CalledOnValidThread()); 320 DCHECK(main_thread_checker_.CalledOnValidThread());
297 scoped_refptr<DeletionSentinel> protect(deletion_sentinel_); 321 scoped_refptr<DeletionSentinel> protect(deletion_sentinel_);
298 internal::TaskQueueImpl::Task pending_task = 322 internal::TaskQueueImpl::Task pending_task =
299 work_queue->TakeTaskFromWorkQueue(); 323 work_queue->TakeTaskFromWorkQueue();
300 324
301 // It's possible the task was canceled, if so bail out. 325 // It's possible the task was canceled, if so bail out.
302 if (pending_task.task.IsCancelled()) 326 if (pending_task.task.IsCancelled()) {
327 *lazy_now = real_time_domain()->CreateLazyNow();
Sami 2017/01/18 18:45:57 We were assuming that operations not involving run
alex clarke (OOO till 29th) 2017/01/19 08:56:10 Yes because task selection takes time. Constructi
Sami 2017/01/19 12:01:00 Yeah, actually I think we could just create one at
Sami 2017/01/19 12:10:15 Offline: turns out we can't because of time observ
alex clarke (OOO till 29th) 2017/01/19 14:25:02 Done.
303 return ProcessTaskResult::EXECUTED; 328 return ProcessTaskResult::EXECUTED;
329 }
304 330
305 internal::TaskQueueImpl* queue = work_queue->task_queue(); 331 internal::TaskQueueImpl* queue = work_queue->task_queue();
306 if (queue->GetQuiescenceMonitored()) 332 if (queue->GetQuiescenceMonitored())
307 task_was_run_on_quiescence_monitored_queue_ = true; 333 task_was_run_on_quiescence_monitored_queue_ = true;
308 334
309 if (!pending_task.nestable && delegate_->IsNested()) { 335 if (!pending_task.nestable && delegate_->IsNested()) {
310 // Defer non-nestable work to the main task runner. NOTE these tasks can be 336 // Defer non-nestable work to the main task runner. NOTE these tasks can be
311 // arbitrarily delayed so the additional delay should not be a problem. 337 // arbitrarily delayed so the additional delay should not be a problem.
312 // TODO(skyostil): Figure out a way to not forget which task queue the 338 // TODO(skyostil): Figure out a way to not forget which task queue the
313 // task is associated with. See http://crbug.com/522843. 339 // task is associated with. See http://crbug.com/522843.
314 // TODO(tzik): Remove base::UnsafeConvertOnceClosureToRepeating once 340 // TODO(tzik): Remove base::UnsafeConvertOnceClosureToRepeating once
315 // TaskRunners have migrated to OnceClosure. 341 // TaskRunners have migrated to OnceClosure.
316 delegate_->PostNonNestableTask( 342 delegate_->PostNonNestableTask(
317 pending_task.posted_from, 343 pending_task.posted_from,
318 UnsafeConvertOnceClosureToRepeating(std::move(pending_task.task))); 344 UnsafeConvertOnceClosureToRepeating(std::move(pending_task.task)));
345 *lazy_now = real_time_domain()->CreateLazyNow();
319 return ProcessTaskResult::DEFERRED; 346 return ProcessTaskResult::DEFERRED;
320 } 347 }
321 348
322 MaybeRecordTaskDelayHistograms(pending_task, queue); 349 MaybeRecordTaskDelayHistograms(pending_task, queue);
323 350
324 double task_start_time = 0; 351 double task_start_time = 0;
325 TRACE_TASK_EXECUTION("TaskQueueManager::ProcessTaskFromWorkQueue", 352 TRACE_TASK_EXECUTION("TaskQueueManager::ProcessTaskFromWorkQueue",
326 pending_task); 353 pending_task);
327 if (queue->GetShouldNotifyObservers()) { 354 if (queue->GetShouldNotifyObservers()) {
328 for (auto& observer : task_observers_) 355 for (auto& observer : task_observers_)
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after
499 for (const scoped_refptr<internal::TaskQueueImpl>& queue : queues_) { 526 for (const scoped_refptr<internal::TaskQueueImpl>& queue : queues_) {
500 TimeDomain* time_domain = queue->GetTimeDomain(); 527 TimeDomain* time_domain = queue->GetTimeDomain();
501 if (time_domain_now.find(time_domain) == time_domain_now.end()) 528 if (time_domain_now.find(time_domain) == time_domain_now.end())
502 time_domain_now.insert(std::make_pair(time_domain, time_domain->Now())); 529 time_domain_now.insert(std::make_pair(time_domain, time_domain->Now()));
503 queue->SweepCanceledDelayedTasks(time_domain_now[time_domain]); 530 queue->SweepCanceledDelayedTasks(time_domain_now[time_domain]);
504 } 531 }
505 } 532 }
506 533
507 } // namespace scheduler 534 } // namespace scheduler
508 } // namespace blink 535 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698