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

Side by Side Diff: components/scheduler/base/task_queue_manager.cc

Issue 1898233002: Report expected task queueing time via UMA (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix perf test Created 4 years, 5 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 "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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698