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

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

Issue 2276353002: Remove after wakeup logic and replace PumpTask with Fences (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Slight simplification Created 4 years, 3 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 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
124 if (observer_) 124 if (observer_)
125 observer_->OnUnregisterTaskQueue(task_queue); 125 observer_->OnUnregisterTaskQueue(task_queue);
126 126
127 // Add |task_queue| to |queues_to_delete_| so we can prevent it from being 127 // Add |task_queue| to |queues_to_delete_| so we can prevent it from being
128 // freed while any of our structures hold hold a raw pointer to it. 128 // freed while any of our structures hold hold a raw pointer to it.
129 queues_to_delete_.insert(task_queue); 129 queues_to_delete_.insert(task_queue);
130 queues_.erase(task_queue); 130 queues_.erase(task_queue);
131 selector_.RemoveQueue(task_queue.get()); 131 selector_.RemoveQueue(task_queue.get());
132 } 132 }
133 133
134 void TaskQueueManager::UpdateWorkQueues( 134 void TaskQueueManager::UpdateWorkQueues(LazyNow lazy_now) {
135 bool should_trigger_wakeup,
136 const internal::TaskQueueImpl::Task* previous_task,
137 LazyNow lazy_now) {
138 TRACE_EVENT0(disabled_by_default_tracing_category_, 135 TRACE_EVENT0(disabled_by_default_tracing_category_,
139 "TaskQueueManager::UpdateWorkQueues"); 136 "TaskQueueManager::UpdateWorkQueues");
140 137
141 for (TimeDomain* time_domain : time_domains_) { 138 for (TimeDomain* time_domain : time_domains_) {
142 LazyNow lazy_now_in_domain = time_domain == real_time_domain_.get() 139 LazyNow lazy_now_in_domain = time_domain == real_time_domain_.get()
143 ? lazy_now 140 ? lazy_now
144 : time_domain->CreateLazyNow(); 141 : time_domain->CreateLazyNow();
145 time_domain->UpdateWorkQueues(should_trigger_wakeup, previous_task, 142 time_domain->UpdateWorkQueues(lazy_now_in_domain);
146 lazy_now_in_domain);
147 } 143 }
148 } 144 }
149 145
150 void TaskQueueManager::MaybeScheduleImmediateWork( 146 void TaskQueueManager::MaybeScheduleImmediateWork(
151 const tracked_objects::Location& from_here) { 147 const tracked_objects::Location& from_here) {
152 bool on_main_thread = delegate_->BelongsToCurrentThread(); 148 bool on_main_thread = delegate_->BelongsToCurrentThread();
153 // De-duplicate DoWork posts. 149 // De-duplicate DoWork posts.
154 if (on_main_thread) { 150 if (on_main_thread) {
155 if (!main_thread_pending_wakeups_.insert(base::TimeTicks()).second) { 151 if (!main_thread_pending_wakeups_.insert(base::TimeTicks()).second) {
156 return; 152 return;
(...skipping 30 matching lines...) Expand all
187 DCHECK(main_thread_checker_.CalledOnValidThread()); 183 DCHECK(main_thread_checker_.CalledOnValidThread());
188 TRACE_EVENT1(tracing_category_, "TaskQueueManager::DoWork", 184 TRACE_EVENT1(tracing_category_, "TaskQueueManager::DoWork",
189 "from_main_thread", from_main_thread); 185 "from_main_thread", from_main_thread);
190 if (from_main_thread) { 186 if (from_main_thread) {
191 main_thread_pending_wakeups_.erase(run_time); 187 main_thread_pending_wakeups_.erase(run_time);
192 } else { 188 } else {
193 base::AutoLock lock(other_thread_lock_); 189 base::AutoLock lock(other_thread_lock_);
194 other_thread_pending_wakeups_.erase(run_time); 190 other_thread_pending_wakeups_.erase(run_time);
195 } 191 }
196 192
193 // TODO(alexclarke): Add a base::RunLoop observer and prevent
194 // MaybeScheduleImmediateWork posting MaybeScheduleImmediateWork while DoWork
195 // is running. We'll need to post a DoWork on entering and leaving a nested
196 // run loop.
197
197 if (!delegate_->IsNested()) 198 if (!delegate_->IsNested())
198 queues_to_delete_.clear(); 199 queues_to_delete_.clear();
199 200
200 LazyNow lazy_now(real_time_domain()->CreateLazyNow()); 201 LazyNow lazy_now(real_time_domain()->CreateLazyNow());
201 base::TimeTicks task_start_time; 202 base::TimeTicks task_start_time;
202 203
203 if (!delegate_->IsNested() && task_time_observers_.might_have_observers()) 204 if (!delegate_->IsNested() && task_time_observers_.might_have_observers())
204 task_start_time = lazy_now.Now(); 205 task_start_time = lazy_now.Now();
205 206
206 // Pass false and nullptr to UpdateWorkQueues here to prevent waking up a 207 // TODO(alexclarke): Get rid of this and call once per loop iteration.
207 // pump-after-wakeup queue. 208 UpdateWorkQueues(lazy_now);
208 UpdateWorkQueues(false, nullptr, lazy_now);
209
210 internal::TaskQueueImpl::Task previous_task;
211 209
212 for (int i = 0; i < work_batch_size_; i++) { 210 for (int i = 0; i < work_batch_size_; i++) {
213 internal::WorkQueue* work_queue; 211 internal::WorkQueue* work_queue;
214 if (!SelectWorkQueueToService(&work_queue)) { 212 if (!SelectWorkQueueToService(&work_queue))
215 break; 213 break;
216 }
217 214
218 bool should_trigger_wakeup = work_queue->task_queue()->wakeup_policy() == 215 switch (ProcessTaskFromWorkQueue(work_queue)) {
219 TaskQueue::WakeupPolicy::CAN_WAKE_OTHER_QUEUES;
220
221 switch (ProcessTaskFromWorkQueue(work_queue, &previous_task)) {
222 case ProcessTaskResult::DEFERRED: 216 case ProcessTaskResult::DEFERRED:
223 // If a task was deferred, try again with another task. Note that this 217 // If a task was deferred, try again with another task.
224 // means deferred tasks (i.e. non-nestable tasks) will never trigger
225 // queue wake-ups.
226 continue; 218 continue;
227 case ProcessTaskResult::EXECUTED: 219 case ProcessTaskResult::EXECUTED:
228 break; 220 break;
229 case ProcessTaskResult::TASK_QUEUE_MANAGER_DELETED: 221 case ProcessTaskResult::TASK_QUEUE_MANAGER_DELETED:
230 return; // The TaskQueueManager got deleted, we must bail out. 222 return; // The TaskQueueManager got deleted, we must bail out.
231 } 223 }
232 224
233 lazy_now = real_time_domain()->CreateLazyNow(); 225 lazy_now = real_time_domain()->CreateLazyNow();
234 if (!delegate_->IsNested() && task_start_time != base::TimeTicks()) { 226 if (!delegate_->IsNested() && task_start_time != base::TimeTicks()) {
235 // Only report top level task durations. 227 // Only report top level task durations.
236 base::TimeTicks task_end_time = lazy_now.Now(); 228 base::TimeTicks task_end_time = lazy_now.Now();
237 FOR_EACH_OBSERVER(TaskTimeObserver, task_time_observers_, 229 FOR_EACH_OBSERVER(TaskTimeObserver, task_time_observers_,
238 ReportTaskTime(MonotonicTimeInSeconds(task_start_time), 230 ReportTaskTime(MonotonicTimeInSeconds(task_start_time),
239 MonotonicTimeInSeconds(task_end_time))); 231 MonotonicTimeInSeconds(task_end_time)));
240 task_start_time = task_end_time; 232 task_start_time = task_end_time;
241 } 233 }
242 234
243 work_queue = nullptr; // The queue may have been unregistered. 235 work_queue = nullptr; // The queue may have been unregistered.
244 236
245 UpdateWorkQueues(should_trigger_wakeup, &previous_task, lazy_now); 237 UpdateWorkQueues(lazy_now);
246 238
247 // Only run a single task per batch in nested run loops so that we can 239 // Only run a single task per batch in nested run loops so that we can
248 // properly exit the nested loop when someone calls RunLoop::Quit(). 240 // properly exit the nested loop when someone calls RunLoop::Quit().
249 if (delegate_->IsNested()) 241 if (delegate_->IsNested())
250 break; 242 break;
251 } 243 }
252 244
253 // TODO(alexclarke): Consider refactoring the above loop to terminate only 245 // TODO(alexclarke): Consider refactoring the above loop to terminate only
254 // when there's no more work left to be done, rather than posting a 246 // when there's no more work left to be done, rather than posting a
255 // continuation task. 247 // continuation task.
(...skipping 17 matching lines...) Expand all
273 AsValueWithSelectorResult(should_run, *out_work_queue)); 265 AsValueWithSelectorResult(should_run, *out_work_queue));
274 return should_run; 266 return should_run;
275 } 267 }
276 268
277 void TaskQueueManager::DidQueueTask( 269 void TaskQueueManager::DidQueueTask(
278 const internal::TaskQueueImpl::Task& pending_task) { 270 const internal::TaskQueueImpl::Task& pending_task) {
279 task_annotator_.DidQueueTask("TaskQueueManager::PostTask", pending_task); 271 task_annotator_.DidQueueTask("TaskQueueManager::PostTask", pending_task);
280 } 272 }
281 273
282 TaskQueueManager::ProcessTaskResult TaskQueueManager::ProcessTaskFromWorkQueue( 274 TaskQueueManager::ProcessTaskResult TaskQueueManager::ProcessTaskFromWorkQueue(
283 internal::WorkQueue* work_queue, 275 internal::WorkQueue* work_queue) {
284 internal::TaskQueueImpl::Task* out_previous_task) {
285 DCHECK(main_thread_checker_.CalledOnValidThread()); 276 DCHECK(main_thread_checker_.CalledOnValidThread());
286 scoped_refptr<DeletionSentinel> protect(deletion_sentinel_); 277 scoped_refptr<DeletionSentinel> protect(deletion_sentinel_);
287 internal::TaskQueueImpl* queue = work_queue->task_queue(); 278 internal::TaskQueueImpl* queue = work_queue->task_queue();
288 279
289 if (queue->GetQuiescenceMonitored()) 280 if (queue->GetQuiescenceMonitored())
290 task_was_run_on_quiescence_monitored_queue_ = true; 281 task_was_run_on_quiescence_monitored_queue_ = true;
291 282
292 internal::TaskQueueImpl::Task pending_task = 283 internal::TaskQueueImpl::Task pending_task =
293 work_queue->TakeTaskFromWorkQueue(); 284 work_queue->TakeTaskFromWorkQueue();
294 if (!pending_task.nestable && delegate_->IsNested()) { 285 if (!pending_task.nestable && delegate_->IsNested()) {
(...skipping 16 matching lines...) Expand all
311 } 302 }
312 TRACE_EVENT1(tracing_category_, "TaskQueueManager::RunTask", "queue", 303 TRACE_EVENT1(tracing_category_, "TaskQueueManager::RunTask", "queue",
313 queue->GetName()); 304 queue->GetName());
314 // NOTE when TaskQueues get unregistered a reference ends up getting retained 305 // NOTE when TaskQueues get unregistered a reference ends up getting retained
315 // by |queues_to_delete_| which is cleared at the top of |DoWork|. This means 306 // by |queues_to_delete_| which is cleared at the top of |DoWork|. This means
316 // we are OK to use raw pointers here. 307 // we are OK to use raw pointers here.
317 internal::TaskQueueImpl* prev_executing_task_queue = 308 internal::TaskQueueImpl* prev_executing_task_queue =
318 currently_executing_task_queue_; 309 currently_executing_task_queue_;
319 currently_executing_task_queue_ = queue; 310 currently_executing_task_queue_ = queue;
320 task_annotator_.RunTask("TaskQueueManager::PostTask", pending_task); 311 task_annotator_.RunTask("TaskQueueManager::PostTask", pending_task);
321
322 // Detect if the TaskQueueManager just got deleted. If this happens we must 312 // Detect if the TaskQueueManager just got deleted. If this happens we must
323 // not access any member variables after this point. 313 // not access any member variables after this point.
324 if (protect->HasOneRef()) 314 if (protect->HasOneRef())
325 return ProcessTaskResult::TASK_QUEUE_MANAGER_DELETED; 315 return ProcessTaskResult::TASK_QUEUE_MANAGER_DELETED;
326 316
327 currently_executing_task_queue_ = prev_executing_task_queue; 317 currently_executing_task_queue_ = prev_executing_task_queue;
328 318
329 if (queue->GetShouldNotifyObservers()) { 319 if (queue->GetShouldNotifyObservers()) {
330 FOR_EACH_OBSERVER(base::MessageLoop::TaskObserver, task_observers_, 320 FOR_EACH_OBSERVER(base::MessageLoop::TaskObserver, task_observers_,
331 DidProcessTask(pending_task)); 321 DidProcessTask(pending_task));
332 queue->NotifyDidProcessTask(pending_task); 322 queue->NotifyDidProcessTask(pending_task);
333 } 323 }
334 324
335 pending_task.task.Reset();
336 *out_previous_task = std::move(pending_task);
337 return ProcessTaskResult::EXECUTED; 325 return ProcessTaskResult::EXECUTED;
338 } 326 }
339 327
340 void TaskQueueManager::MaybeRecordTaskDelayHistograms( 328 void TaskQueueManager::MaybeRecordTaskDelayHistograms(
341 const internal::TaskQueueImpl::Task& pending_task, 329 const internal::TaskQueueImpl::Task& pending_task,
342 const internal::TaskQueueImpl* queue) { 330 const internal::TaskQueueImpl* queue) {
343 if ((task_count_++ % kRecordRecordTaskDelayHistogramsEveryNTasks) != 0) 331 if ((task_count_++ % kRecordRecordTaskDelayHistogramsEveryNTasks) != 0)
344 return; 332 return;
345 333
346 // Record delayed task lateness and immediate task queueing durations, but 334 // Record delayed task lateness and immediate task queuing durations.
347 // only for auto-pumped queues. Manually pumped and after wakeup queues can 335 if (!pending_task.delayed_run_time.is_null()) {
348 // have arbitarially large delayes, which would cloud any analysis. 336 RecordDelayedTaskLateness(delegate_->NowTicks() -
349 if (queue->GetPumpPolicy() == TaskQueue::PumpPolicy::AUTO) { 337 pending_task.delayed_run_time);
350 if (!pending_task.delayed_run_time.is_null()) { 338 } else if (!pending_task.time_posted.is_null()) {
351 RecordDelayedTaskLateness(delegate_->NowTicks() - 339 RecordImmediateTaskQueueingDuration(tracked_objects::TrackedTime::Now() -
352 pending_task.delayed_run_time); 340 pending_task.time_posted);
353 } else if (!pending_task.time_posted.is_null()) {
354 RecordImmediateTaskQueueingDuration(tracked_objects::TrackedTime::Now() -
355 pending_task.time_posted);
356 }
357 } 341 }
358 } 342 }
359 343
360 bool TaskQueueManager::RunsTasksOnCurrentThread() const { 344 bool TaskQueueManager::RunsTasksOnCurrentThread() const {
361 return delegate_->RunsTasksOnCurrentThread(); 345 return delegate_->RunsTasksOnCurrentThread();
362 } 346 }
363 347
364 void TaskQueueManager::SetWorkBatchSize(int work_batch_size) { 348 void TaskQueueManager::SetWorkBatchSize(int work_batch_size) {
365 DCHECK(main_thread_checker_.CalledOnValidThread()); 349 DCHECK(main_thread_checker_.CalledOnValidThread());
366 DCHECK_GE(work_batch_size, 1); 350 DCHECK_GE(work_batch_size, 1);
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
432 state->BeginArray("time_domains"); 416 state->BeginArray("time_domains");
433 for (auto* time_domain : time_domains_) 417 for (auto* time_domain : time_domains_)
434 time_domain->AsValueInto(state.get()); 418 time_domain->AsValueInto(state.get());
435 state->EndArray(); 419 state->EndArray();
436 return std::move(state); 420 return std::move(state);
437 } 421 }
438 422
439 void TaskQueueManager::OnTaskQueueEnabled(internal::TaskQueueImpl* queue) { 423 void TaskQueueManager::OnTaskQueueEnabled(internal::TaskQueueImpl* queue) {
440 DCHECK(main_thread_checker_.CalledOnValidThread()); 424 DCHECK(main_thread_checker_.CalledOnValidThread());
441 // Only schedule DoWork if there's something to do. 425 // Only schedule DoWork if there's something to do.
442 if (!queue->immediate_work_queue()->Empty() || 426 if (queue->HasPendingImmediateWork())
443 !queue->delayed_work_queue()->Empty()) {
444 MaybeScheduleImmediateWork(FROM_HERE); 427 MaybeScheduleImmediateWork(FROM_HERE);
445 }
446 } 428 }
447 429
448 void TaskQueueManager::OnTriedToSelectBlockedWorkQueue( 430 void TaskQueueManager::OnTriedToSelectBlockedWorkQueue(
449 internal::WorkQueue* work_queue) { 431 internal::WorkQueue* work_queue) {
450 DCHECK(main_thread_checker_.CalledOnValidThread()); 432 DCHECK(main_thread_checker_.CalledOnValidThread());
451 DCHECK(!work_queue->Empty()); 433 DCHECK(!work_queue->Empty());
452 if (observer_) { 434 if (observer_) {
453 observer_->OnTriedToExecuteBlockedTask(*work_queue->task_queue(), 435 observer_->OnTriedToExecuteBlockedTask(*work_queue->task_queue(),
454 *work_queue->GetFrontTask()); 436 *work_queue->GetFrontTask());
455 } 437 }
456 } 438 }
457 439
458 } // namespace scheduler 440 } // namespace scheduler
459 } // namespace blink 441 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698