Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 "components/scheduler/base/task_queue_manager.h" | 5 #include "components/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" |
| 11 #include "base/metrics/histogram_macros.h" | 11 #include "base/metrics/histogram_macros.h" |
| 12 #include "base/trace_event/trace_event.h" | 12 #include "base/trace_event/trace_event.h" |
| 13 #include "components/scheduler/base/real_time_domain.h" | 13 #include "components/scheduler/base/real_time_domain.h" |
| 14 #include "components/scheduler/base/task_queue_impl.h" | 14 #include "components/scheduler/base/task_queue_impl.h" |
| 15 #include "components/scheduler/base/task_queue_manager_delegate.h" | 15 #include "components/scheduler/base/task_queue_manager_delegate.h" |
| 16 #include "components/scheduler/base/task_queue_selector.h" | 16 #include "components/scheduler/base/task_queue_selector.h" |
| 17 #include "components/scheduler/base/task_time_tracker.h" | |
| 17 #include "components/scheduler/base/work_queue.h" | 18 #include "components/scheduler/base/work_queue.h" |
| 18 #include "components/scheduler/base/work_queue_sets.h" | 19 #include "components/scheduler/base/work_queue_sets.h" |
| 19 | 20 |
| 20 namespace scheduler { | 21 namespace scheduler { |
| 21 | 22 |
| 22 namespace { | 23 namespace { |
| 23 const size_t kRecordRecordTaskDelayHistogramsEveryNTasks = 10; | 24 const size_t kRecordRecordTaskDelayHistogramsEveryNTasks = 10; |
| 24 | 25 |
| 25 void RecordDelayedTaskLateness(base::TimeDelta lateness) { | 26 void RecordDelayedTaskLateness(base::TimeDelta lateness) { |
| 26 UMA_HISTOGRAM_TIMES("RendererScheduler.TaskQueueManager.DelayedTaskLateness", | 27 UMA_HISTOGRAM_TIMES("RendererScheduler.TaskQueueManager.DelayedTaskLateness", |
| 27 lateness); | 28 lateness); |
| 28 } | 29 } |
| 29 | 30 |
| 30 void RecordImmediateTaskQueueingDuration(tracked_objects::Duration duration) { | 31 void RecordImmediateTaskQueueingDuration(tracked_objects::Duration duration) { |
| 31 UMA_HISTOGRAM_TIMES( | 32 UMA_HISTOGRAM_TIMES( |
| 32 "RendererScheduler.TaskQueueManager.ImmediateTaskQueueingDuration", | 33 "RendererScheduler.TaskQueueManager.ImmediateTaskQueueingDuration", |
| 33 base::TimeDelta::FromMilliseconds(duration.InMilliseconds())); | 34 base::TimeDelta::FromMilliseconds(duration.InMilliseconds())); |
| 34 } | 35 } |
| 35 } | 36 } |
| 36 | 37 |
| 37 TaskQueueManager::TaskQueueManager( | 38 TaskQueueManager::TaskQueueManager( |
| 38 scoped_refptr<TaskQueueManagerDelegate> delegate, | 39 scoped_refptr<TaskQueueManagerDelegate> delegate, |
| 39 const char* tracing_category, | 40 const char* tracing_category, |
| 40 const char* disabled_by_default_tracing_category, | 41 const char* disabled_by_default_tracing_category, |
| 41 const char* disabled_by_default_verbose_tracing_category) | 42 const char* disabled_by_default_verbose_tracing_category, |
| 43 TaskTimeTracker* task_time_tracker) | |
| 42 : real_time_domain_(new RealTimeDomain(tracing_category)), | 44 : real_time_domain_(new RealTimeDomain(tracing_category)), |
| 43 delegate_(delegate), | 45 delegate_(delegate), |
| 44 task_was_run_on_quiescence_monitored_queue_(false), | 46 task_was_run_on_quiescence_monitored_queue_(false), |
| 45 work_batch_size_(1), | 47 work_batch_size_(1), |
| 46 task_count_(0), | 48 task_count_(0), |
| 49 task_time_tracker_(task_time_tracker), | |
| 50 do_work_depth_(0), | |
| 47 tracing_category_(tracing_category), | 51 tracing_category_(tracing_category), |
| 48 disabled_by_default_tracing_category_( | 52 disabled_by_default_tracing_category_( |
| 49 disabled_by_default_tracing_category), | 53 disabled_by_default_tracing_category), |
| 50 disabled_by_default_verbose_tracing_category_( | 54 disabled_by_default_verbose_tracing_category_( |
| 51 disabled_by_default_verbose_tracing_category), | 55 disabled_by_default_verbose_tracing_category), |
| 52 currently_executing_task_queue_(nullptr), | 56 currently_executing_task_queue_(nullptr), |
| 53 observer_(nullptr), | 57 observer_(nullptr), |
| 54 deletion_sentinel_(new DeletionSentinel()), | 58 deletion_sentinel_(new DeletionSentinel()), |
| 55 weak_factory_(this) { | 59 weak_factory_(this) { |
| 56 DCHECK(delegate->RunsTasksOnCurrentThread()); | 60 DCHECK(delegate->RunsTasksOnCurrentThread()); |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 167 // De-duplicate DoWork posts. | 171 // De-duplicate DoWork posts. |
| 168 if (!main_thread_pending_wakeups_.insert(run_time).second) | 172 if (!main_thread_pending_wakeups_.insert(run_time).second) |
| 169 return; | 173 return; |
| 170 delegate_->PostDelayedTask( | 174 delegate_->PostDelayedTask( |
| 171 from_here, base::Bind(&TaskQueueManager::DoWork, | 175 from_here, base::Bind(&TaskQueueManager::DoWork, |
| 172 weak_factory_.GetWeakPtr(), run_time, true), | 176 weak_factory_.GetWeakPtr(), run_time, true), |
| 173 delay); | 177 delay); |
| 174 } | 178 } |
| 175 | 179 |
| 176 void TaskQueueManager::DoWork(base::TimeTicks run_time, bool from_main_thread) { | 180 void TaskQueueManager::DoWork(base::TimeTicks run_time, bool from_main_thread) { |
| 181 do_work_depth_++; | |
|
Sami
2016/07/05 14:40:38
Could we use a base::AutoReset for this? (might no
tdresser
2016/07/05 15:52:20
Alex pointed out this isn't needed.
| |
| 177 DCHECK(main_thread_checker_.CalledOnValidThread()); | 182 DCHECK(main_thread_checker_.CalledOnValidThread()); |
| 178 TRACE_EVENT1(tracing_category_, "TaskQueueManager::DoWork", | 183 TRACE_EVENT1(tracing_category_, "TaskQueueManager::DoWork", |
| 179 "from_main_thread", from_main_thread); | 184 "from_main_thread", from_main_thread); |
| 180 if (from_main_thread) { | 185 if (from_main_thread) { |
| 181 main_thread_pending_wakeups_.erase(run_time); | 186 main_thread_pending_wakeups_.erase(run_time); |
| 182 } else { | 187 } else { |
| 183 base::AutoLock lock(other_thread_lock_); | 188 base::AutoLock lock(other_thread_lock_); |
| 184 other_thread_pending_wakeups_.erase(run_time); | 189 other_thread_pending_wakeups_.erase(run_time); |
| 185 } | 190 } |
| 186 | 191 |
| 187 if (!delegate_->IsNested()) | 192 if (!delegate_->IsNested()) |
| 188 queues_to_delete_.clear(); | 193 queues_to_delete_.clear(); |
| 189 | 194 |
| 190 // Pass false and nullptr to UpdateWorkQueues here to prevent waking up a | 195 // Pass false and nullptr to UpdateWorkQueues here to prevent waking up a |
| 191 // pump-after-wakeup queue. | 196 // pump-after-wakeup queue. |
| 192 UpdateWorkQueues(false, nullptr); | 197 UpdateWorkQueues(false, nullptr); |
| 193 | 198 |
| 194 internal::TaskQueueImpl::Task previous_task; | 199 internal::TaskQueueImpl::Task previous_task; |
| 200 base::TimeTicks task_start_time; | |
| 201 if (do_work_depth_ == 1 && from_main_thread) | |
|
Sami
2016/07/05 14:40:38
Why the check for |from_main_thread|? That flag sa
tdresser
2016/07/05 20:09:38
Done.
| |
| 202 task_start_time = real_time_domain()->Now(); | |
| 203 | |
| 195 for (int i = 0; i < work_batch_size_; i++) { | 204 for (int i = 0; i < work_batch_size_; i++) { |
| 196 internal::WorkQueue* work_queue; | 205 internal::WorkQueue* work_queue; |
| 197 if (!SelectWorkQueueToService(&work_queue)) { | 206 if (!SelectWorkQueueToService(&work_queue)) { |
| 198 break; | 207 break; |
| 199 } | 208 } |
| 200 | 209 |
| 201 bool should_trigger_wakeup = work_queue->task_queue()->wakeup_policy() == | 210 bool should_trigger_wakeup = work_queue->task_queue()->wakeup_policy() == |
| 202 TaskQueue::WakeupPolicy::CAN_WAKE_OTHER_QUEUES; | 211 TaskQueue::WakeupPolicy::CAN_WAKE_OTHER_QUEUES; |
| 212 | |
| 203 switch (ProcessTaskFromWorkQueue(work_queue, &previous_task)) { | 213 switch (ProcessTaskFromWorkQueue(work_queue, &previous_task)) { |
| 204 case ProcessTaskResult::DEFERRED: | 214 case ProcessTaskResult::DEFERRED: |
| 205 // If a task was deferred, try again with another task. Note that this | 215 // If a task was deferred, try again with another task. Note that this |
| 206 // means deferred tasks (i.e. non-nestable tasks) will never trigger | 216 // means deferred tasks (i.e. non-nestable tasks) will never trigger |
| 207 // queue wake-ups. | 217 // queue wake-ups. |
| 208 continue; | 218 continue; |
| 209 case ProcessTaskResult::EXECUTED: | 219 case ProcessTaskResult::EXECUTED: |
| 210 break; | 220 break; |
| 211 case ProcessTaskResult::TASK_QUEUE_MANAGER_DELETED: | 221 case ProcessTaskResult::TASK_QUEUE_MANAGER_DELETED: |
| 212 return; // The TaskQueueManager got deleted, we must bail out. | 222 return; // The TaskQueueManager got deleted, we must bail out. |
| 213 } | 223 } |
| 224 if (do_work_depth_ == 1 && from_main_thread) { | |
|
alex clarke (OOO till 29th)
2016/07/05 13:47:45
Isn't do_work_depth_ == 1 equivalent to !delegate
tdresser
2016/07/05 14:30:13
Awesome, thanks.
| |
| 225 // Only report top level task durations. | |
| 226 base::TimeTicks task_end_time = real_time_domain()->Now(); | |
| 227 task_time_tracker_->ReportTaskTime(task_start_time, task_end_time); | |
| 228 task_start_time = task_end_time; | |
| 229 } | |
| 230 | |
| 214 work_queue = nullptr; // The queue may have been unregistered. | 231 work_queue = nullptr; // The queue may have been unregistered. |
| 215 | 232 |
| 216 UpdateWorkQueues(should_trigger_wakeup, &previous_task); | 233 UpdateWorkQueues(should_trigger_wakeup, &previous_task); |
| 217 | 234 |
| 218 // Only run a single task per batch in nested run loops so that we can | 235 // Only run a single task per batch in nested run loops so that we can |
| 219 // properly exit the nested loop when someone calls RunLoop::Quit(). | 236 // properly exit the nested loop when someone calls RunLoop::Quit(). |
| 220 if (delegate_->IsNested()) | 237 if (delegate_->IsNested()) |
| 221 break; | 238 break; |
| 222 } | 239 } |
| 223 | 240 |
| 224 // TODO(alexclarke): Consider refactoring the above loop to terminate only | 241 // TODO(alexclarke): Consider refactoring the above loop to terminate only |
| 225 // when there's no more work left to be done, rather than posting a | 242 // when there's no more work left to be done, rather than posting a |
| 226 // continuation task. | 243 // continuation task. |
| 227 if (!selector_.EnabledWorkQueuesEmpty() || TryAdvanceTimeDomains()) | 244 if (!selector_.EnabledWorkQueuesEmpty() || TryAdvanceTimeDomains()) |
| 228 MaybeScheduleImmediateWork(FROM_HERE); | 245 MaybeScheduleImmediateWork(FROM_HERE); |
| 246 do_work_depth_--; | |
| 229 } | 247 } |
| 230 | 248 |
| 231 bool TaskQueueManager::TryAdvanceTimeDomains() { | 249 bool TaskQueueManager::TryAdvanceTimeDomains() { |
| 232 bool can_advance = false; | 250 bool can_advance = false; |
| 233 for (TimeDomain* time_domain : time_domains_) { | 251 for (TimeDomain* time_domain : time_domains_) { |
| 234 can_advance |= time_domain->MaybeAdvanceTime(); | 252 can_advance |= time_domain->MaybeAdvanceTime(); |
| 235 } | 253 } |
| 236 return can_advance; | 254 return can_advance; |
| 237 } | 255 } |
| 238 | 256 |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 409 internal::WorkQueue* work_queue) { | 427 internal::WorkQueue* work_queue) { |
| 410 DCHECK(main_thread_checker_.CalledOnValidThread()); | 428 DCHECK(main_thread_checker_.CalledOnValidThread()); |
| 411 DCHECK(!work_queue->Empty()); | 429 DCHECK(!work_queue->Empty()); |
| 412 if (observer_) { | 430 if (observer_) { |
| 413 observer_->OnTriedToExecuteBlockedTask(*work_queue->task_queue(), | 431 observer_->OnTriedToExecuteBlockedTask(*work_queue->task_queue(), |
| 414 *work_queue->GetFrontTask()); | 432 *work_queue->GetFrontTask()); |
| 415 } | 433 } |
| 416 } | 434 } |
| 417 | 435 |
| 418 } // namespace scheduler | 436 } // namespace scheduler |
| OLD | NEW |