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 "content/renderer/scheduler/renderer_scheduler_impl.h" | 5 #include "content/renderer/scheduler/renderer_scheduler_impl.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/message_loop/message_loop_proxy.h" | 8 #include "base/message_loop/message_loop_proxy.h" |
9 #include "base/trace_event/trace_event.h" | 9 #include "base/trace_event/trace_event.h" |
10 #include "base/trace_event/trace_event_argument.h" | 10 #include "base/trace_event/trace_event_argument.h" |
(...skipping 23 matching lines...) Expand all Loading... | |
34 current_policy_(Policy::NORMAL), | 34 current_policy_(Policy::NORMAL), |
35 last_input_type_(blink::WebInputEvent::Undefined), | 35 last_input_type_(blink::WebInputEvent::Undefined), |
36 input_stream_state_(InputStreamState::INACTIVE), | 36 input_stream_state_(InputStreamState::INACTIVE), |
37 policy_may_need_update_(&incoming_signals_lock_), | 37 policy_may_need_update_(&incoming_signals_lock_), |
38 weak_factory_(this) { | 38 weak_factory_(this) { |
39 weak_renderer_scheduler_ptr_ = weak_factory_.GetWeakPtr(); | 39 weak_renderer_scheduler_ptr_ = weak_factory_.GetWeakPtr(); |
40 update_policy_closure_ = base::Bind(&RendererSchedulerImpl::UpdatePolicy, | 40 update_policy_closure_ = base::Bind(&RendererSchedulerImpl::UpdatePolicy, |
41 weak_renderer_scheduler_ptr_); | 41 weak_renderer_scheduler_ptr_); |
42 end_idle_period_closure_.Reset(base::Bind( | 42 end_idle_period_closure_.Reset(base::Bind( |
43 &RendererSchedulerImpl::EndIdlePeriod, weak_renderer_scheduler_ptr_)); | 43 &RendererSchedulerImpl::EndIdlePeriod, weak_renderer_scheduler_ptr_)); |
44 initiate_next_long_idle_period_closure_.Reset(base::Bind( | |
45 &RendererSchedulerImpl::InitiateLongIdlePeriod, | |
46 weak_renderer_scheduler_ptr_)); | |
47 after_wakeup_initiate_next_long_idle_period_closure_.Reset(base::Bind( | |
48 &RendererSchedulerImpl::InitiateLongIdlePeriodAfterWakeup, | |
49 weak_renderer_scheduler_ptr_)); | |
50 | |
44 idle_task_runner_ = make_scoped_refptr(new SingleThreadIdleTaskRunner( | 51 idle_task_runner_ = make_scoped_refptr(new SingleThreadIdleTaskRunner( |
45 task_queue_manager_->TaskRunnerForQueue(IDLE_TASK_QUEUE), | 52 task_queue_manager_->TaskRunnerForQueue(IDLE_TASK_QUEUE), |
46 control_task_after_wakeup_runner_, | 53 control_task_after_wakeup_runner_, |
47 base::Bind(&RendererSchedulerImpl::CurrentIdleTaskDeadlineCallback, | 54 base::Bind(&RendererSchedulerImpl::CurrentIdleTaskDeadlineCallback, |
48 weak_renderer_scheduler_ptr_))); | 55 weak_renderer_scheduler_ptr_))); |
49 | 56 |
50 renderer_task_queue_selector_->SetQueuePriority( | 57 renderer_task_queue_selector_->SetQueuePriority( |
51 CONTROL_TASK_QUEUE, RendererTaskQueueSelector::CONTROL_PRIORITY); | 58 CONTROL_TASK_QUEUE, RendererTaskQueueSelector::CONTROL_PRIORITY); |
52 | 59 |
53 renderer_task_queue_selector_->SetQueuePriority( | 60 renderer_task_queue_selector_->SetQueuePriority( |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
135 control_task_runner_->PostDelayedTask(FROM_HERE, | 142 control_task_runner_->PostDelayedTask(FROM_HERE, |
136 end_idle_period_closure_.callback(), | 143 end_idle_period_closure_.callback(), |
137 estimated_next_frame_begin_ - now); | 144 estimated_next_frame_begin_ - now); |
138 } | 145 } |
139 } | 146 } |
140 | 147 |
141 void RendererSchedulerImpl::BeginFrameNotExpectedSoon() { | 148 void RendererSchedulerImpl::BeginFrameNotExpectedSoon() { |
142 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), | 149 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), |
143 "RendererSchedulerImpl::BeginFrameNotExpectedSoon"); | 150 "RendererSchedulerImpl::BeginFrameNotExpectedSoon"); |
144 DCHECK(main_thread_checker_.CalledOnValidThread()); | 151 DCHECK(main_thread_checker_.CalledOnValidThread()); |
152 if (!task_queue_manager_) | |
153 return; | |
154 | |
145 // TODO(skyostil): Wire up real notification of input events processing | 155 // TODO(skyostil): Wire up real notification of input events processing |
146 // instead of this approximation. | 156 // instead of this approximation. |
147 DidProcessInputEvent(base::TimeTicks()); | 157 DidProcessInputEvent(base::TimeTicks()); |
148 // TODO(rmcilroy): Implement long idle times. | 158 |
159 InitiateLongIdlePeriod(); | |
149 } | 160 } |
150 | 161 |
151 void RendererSchedulerImpl::DidReceiveInputEventOnCompositorThread( | 162 void RendererSchedulerImpl::DidReceiveInputEventOnCompositorThread( |
152 const blink::WebInputEvent& web_input_event) { | 163 const blink::WebInputEvent& web_input_event) { |
153 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), | 164 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), |
154 "RendererSchedulerImpl::DidReceiveInputEventOnCompositorThread"); | 165 "RendererSchedulerImpl::DidReceiveInputEventOnCompositorThread"); |
155 // We regard MouseMove events with the left mouse button down as a signal | 166 // We regard MouseMove events with the left mouse button down as a signal |
156 // that the user is doing something requiring a smooth frame rate. | 167 // that the user is doing something requiring a smooth frame rate. |
157 if (web_input_event.type == blink::WebInputEvent::MouseMove && | 168 if (web_input_event.type == blink::WebInputEvent::MouseMove && |
158 (web_input_event.modifiers & blink::WebInputEvent::LeftButtonDown)) { | 169 (web_input_event.modifiers & blink::WebInputEvent::LeftButtonDown)) { |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
278 DCHECK(main_thread_checker_.CalledOnValidThread()); | 289 DCHECK(main_thread_checker_.CalledOnValidThread()); |
279 if (!task_queue_manager_) | 290 if (!task_queue_manager_) |
280 return; | 291 return; |
281 | 292 |
282 base::AutoLock lock(incoming_signals_lock_); | 293 base::AutoLock lock(incoming_signals_lock_); |
283 base::TimeTicks now; | 294 base::TimeTicks now; |
284 policy_may_need_update_.SetWhileLocked(false); | 295 policy_may_need_update_.SetWhileLocked(false); |
285 | 296 |
286 base::TimeDelta new_policy_duration; | 297 base::TimeDelta new_policy_duration; |
287 Policy new_policy = ComputeNewPolicy(&new_policy_duration); | 298 Policy new_policy = ComputeNewPolicy(&new_policy_duration); |
288 if (new_policy_duration > base::TimeDelta()) | 299 if (new_policy_duration > base::TimeDelta()) { |
300 current_policy_expiration_time_ = now + new_policy_duration; | |
289 PostUpdatePolicyOnControlRunner(new_policy_duration); | 301 PostUpdatePolicyOnControlRunner(new_policy_duration); |
302 } else { | |
303 current_policy_expiration_time_ = base::TimeTicks(); | |
304 } | |
290 | 305 |
291 if (new_policy == current_policy_) | 306 if (new_policy == current_policy_) |
292 return; | 307 return; |
293 | 308 |
294 switch (new_policy) { | 309 switch (new_policy) { |
295 case Policy::COMPOSITOR_PRIORITY: | 310 case Policy::COMPOSITOR_PRIORITY: |
296 renderer_task_queue_selector_->SetQueuePriority( | 311 renderer_task_queue_selector_->SetQueuePriority( |
297 COMPOSITOR_TASK_QUEUE, RendererTaskQueueSelector::HIGH_PRIORITY); | 312 COMPOSITOR_TASK_QUEUE, RendererTaskQueueSelector::HIGH_PRIORITY); |
298 // TODO(scheduler-dev): Add a task priority between HIGH and BEST_EFFORT | 313 // TODO(scheduler-dev): Add a task priority between HIGH and BEST_EFFORT |
299 // that still has some guarantee of running. | 314 // that still has some guarantee of running. |
(...skipping 29 matching lines...) Expand all Loading... | |
329 base::TimeDelta* new_policy_duration) { | 344 base::TimeDelta* new_policy_duration) { |
330 DCHECK(main_thread_checker_.CalledOnValidThread()); | 345 DCHECK(main_thread_checker_.CalledOnValidThread()); |
331 incoming_signals_lock_.AssertAcquired(); | 346 incoming_signals_lock_.AssertAcquired(); |
332 | 347 |
333 Policy new_policy = Policy::NORMAL; | 348 Policy new_policy = Policy::NORMAL; |
334 *new_policy_duration = base::TimeDelta(); | 349 *new_policy_duration = base::TimeDelta(); |
335 | 350 |
336 if (input_stream_state_ == InputStreamState::INACTIVE) | 351 if (input_stream_state_ == InputStreamState::INACTIVE) |
337 return new_policy; | 352 return new_policy; |
338 | 353 |
339 base::TimeDelta new_priority_duration = | |
340 base::TimeDelta::FromMilliseconds(kPriorityEscalationAfterInputMillis); | |
341 Policy input_priority_policy = | 354 Policy input_priority_policy = |
342 input_stream_state_ == | 355 input_stream_state_ == |
343 InputStreamState::ACTIVE_AND_AWAITING_TOUCHSTART_RESPONSE | 356 InputStreamState::ACTIVE_AND_AWAITING_TOUCHSTART_RESPONSE |
344 ? Policy::TOUCHSTART_PRIORITY | 357 ? Policy::TOUCHSTART_PRIORITY |
345 : Policy::COMPOSITOR_PRIORITY; | 358 : Policy::COMPOSITOR_PRIORITY; |
359 base::TimeDelta time_left_in_policy = TimeLeftInInputEscalatedPolicy(); | |
360 if (time_left_in_policy > base::TimeDelta()) { | |
361 new_policy = input_priority_policy; | |
362 *new_policy_duration = time_left_in_policy; | |
363 } else { | |
364 // Reset |input_stream_state_| to ensure | |
365 // DidReceiveInputEventOnCompositorThread will post an UpdatePolicy task | |
366 // when it's next called. | |
367 input_stream_state_ = InputStreamState::INACTIVE; | |
368 } | |
369 return new_policy; | |
370 } | |
346 | 371 |
347 // If the input event is still pending, go into input prioritized policy | 372 base::TimeDelta RendererSchedulerImpl::TimeLeftInInputEscalatedPolicy() const { |
348 // and check again later. | 373 DCHECK(main_thread_checker_.CalledOnValidThread()); |
374 // TODO(rmcilroy): Change this to DCHECK_EQ when crbug.com/463869 is fixed. | |
375 DCHECK(input_stream_state_ != InputStreamState::INACTIVE); | |
376 incoming_signals_lock_.AssertAcquired(); | |
377 | |
378 base::TimeDelta escalated_priority_duration = | |
379 base::TimeDelta::FromMilliseconds(kPriorityEscalationAfterInputMillis); | |
380 base::TimeDelta time_left_in_policy; | |
349 if (last_input_process_time_on_main_.is_null() && | 381 if (last_input_process_time_on_main_.is_null() && |
350 !task_queue_manager_->IsQueueEmpty(COMPOSITOR_TASK_QUEUE)) { | 382 !task_queue_manager_->IsQueueEmpty(COMPOSITOR_TASK_QUEUE)) { |
351 new_policy = input_priority_policy; | 383 // If the input event is still pending, go into input prioritized policy |
352 *new_policy_duration = new_priority_duration; | 384 // and check again later. |
385 time_left_in_policy = escalated_priority_duration; | |
353 } else { | 386 } else { |
354 // Otherwise make sure the input prioritization policy ends on time. | 387 // Otherwise make sure the input prioritization policy ends on time. |
355 base::TimeTicks new_priority_end( | 388 base::TimeTicks new_priority_end( |
356 std::max(last_input_receipt_time_on_compositor_, | 389 std::max(last_input_receipt_time_on_compositor_, |
357 last_input_process_time_on_main_) + | 390 last_input_process_time_on_main_) + |
358 new_priority_duration); | 391 escalated_priority_duration); |
359 base::TimeDelta time_left_in_policy = new_priority_end - Now(); | 392 time_left_in_policy = new_priority_end - Now(); |
393 } | |
394 return time_left_in_policy; | |
395 } | |
360 | 396 |
361 if (time_left_in_policy > base::TimeDelta()) { | 397 bool RendererSchedulerImpl::ShouldStartLongIdlePeriod( |
362 new_policy = input_priority_policy; | 398 const base::TimeTicks now, |
363 *new_policy_duration = time_left_in_policy; | 399 base::TimeDelta* next_long_idle_period_delay_out) { |
364 } else { | 400 DCHECK(main_thread_checker_.CalledOnValidThread()); |
365 // Reset |input_stream_state_| to ensure | 401 |
366 // DidReceiveInputEventOnCompositorThread will post an UpdatePolicy task | 402 MaybeUpdatePolicy(); |
367 // when it's next called. | 403 if (SchedulerPolicy() == Policy::TOUCHSTART_PRIORITY) { |
368 input_stream_state_ = InputStreamState::INACTIVE; | 404 // Don't start a long idle task in touch start priority, try again when |
369 } | 405 // the policy is scheduled to end. |
406 *next_long_idle_period_delay_out = current_policy_expiration_time_ - now; | |
407 return false; | |
370 } | 408 } |
371 return new_policy; | 409 |
410 base::TimeTicks next_pending_delayed_task = | |
411 task_queue_manager_->NextPendingDelayedTaskRunTime(); | |
412 | |
413 base::TimeDelta long_idle_period_duration = | |
414 base::TimeDelta::FromMilliseconds(kMaximumIdlePeriodMillis); | |
415 if (!next_pending_delayed_task.is_null()) { | |
416 // Limit the idle period duration to be before the next pending task. | |
417 long_idle_period_duration = std::min( | |
418 next_pending_delayed_task - now, long_idle_period_duration); | |
419 } | |
420 | |
421 if (long_idle_period_duration > base::TimeDelta()) { | |
422 *next_long_idle_period_delay_out = long_idle_period_duration; | |
423 return true; | |
424 } else { | |
425 // If we can't start the idle period yet then try again after wakeup. | |
426 *next_long_idle_period_delay_out = base::TimeDelta::FromMilliseconds( | |
427 kRetryInitiateLongIdlePeriodDelayMillis); | |
428 return false; | |
429 } | |
430 } | |
431 | |
432 void RendererSchedulerImpl::InitiateLongIdlePeriod() { | |
433 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), | |
434 "InitiateLongIdlePeriod"); | |
435 DCHECK(main_thread_checker_.CalledOnValidThread()); | |
436 | |
437 // End any previous idle period. | |
438 EndIdlePeriod(); | |
439 | |
440 base::TimeTicks now(Now()); | |
441 base::TimeDelta next_long_idle_period_delay; | |
442 if (ShouldStartLongIdlePeriod(now, &next_long_idle_period_delay)) { | |
443 estimated_next_frame_begin_ = now + next_long_idle_period_delay; | |
444 StartIdlePeriod(); | |
445 } | |
446 | |
447 if (task_queue_manager_->IsQueueEmpty(IDLE_TASK_QUEUE)) { | |
448 // If there are no current idle tasks or we need to wait for a pending | |
449 // delayed task to run then post the call to initiate the next idle for | |
450 // execution after wakeup (at which point after-wakeup idle tasks might | |
451 // be eligible to run or more idle tasks posted). | |
452 control_task_after_wakeup_runner_->PostDelayedTask( | |
453 FROM_HERE, | |
454 after_wakeup_initiate_next_long_idle_period_closure_.callback(), | |
455 next_long_idle_period_delay); | |
456 } else { | |
457 // Otherwise post on the normal control task queue. | |
458 control_task_runner_->PostDelayedTask( | |
459 FROM_HERE, | |
460 initiate_next_long_idle_period_closure_.callback(), | |
461 next_long_idle_period_delay); | |
462 } | |
463 } | |
464 | |
465 void RendererSchedulerImpl::InitiateLongIdlePeriodAfterWakeup() { | |
466 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), | |
467 "AfterWakeupInitiateLongIdlePeriod"); | |
468 DCHECK(main_thread_checker_.CalledOnValidThread()); | |
469 | |
470 if (in_idle_period_) { | |
471 // Since we were asleep until now, end the async idle period trace event at | |
472 // the time when it would have ended were we awake. | |
473 TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP0( | |
474 "renderer.scheduler", "RendererSchedulerIdlePeriod", this, | |
475 std::min(estimated_next_frame_begin_, Now()).ToInternalValue()); | |
476 } | |
Sami
2015/03/04 18:26:40
Forgot to reset in_idle_period_? Also in EndIdlePe
Sami
2015/03/05 12:01:51
Missed this comment?
rmcilroy
2015/03/05 12:29:41
opps, yes thanks. Done for EndIdlePeriod but I do
| |
477 | |
478 // Post a task to initiate the next long idle period rather than calling it | |
479 // directly to allow all pending PostIdleTaskAfterWakeup tasks to get enqueued | |
480 // on the idle task queue before the next idle period starts so they are | |
481 // eligible to be run during the new idle period. | |
482 control_task_runner_->PostTask( | |
483 FROM_HERE, | |
484 initiate_next_long_idle_period_closure_.callback()); | |
372 } | 485 } |
373 | 486 |
374 void RendererSchedulerImpl::StartIdlePeriod() { | 487 void RendererSchedulerImpl::StartIdlePeriod() { |
375 TRACE_EVENT_ASYNC_BEGIN0("renderer.scheduler", | 488 TRACE_EVENT_ASYNC_BEGIN0("renderer.scheduler", |
376 "RendererSchedulerIdlePeriod", this); | 489 "RendererSchedulerIdlePeriod", this); |
377 DCHECK(main_thread_checker_.CalledOnValidThread()); | 490 DCHECK(main_thread_checker_.CalledOnValidThread()); |
378 renderer_task_queue_selector_->EnableQueue( | 491 renderer_task_queue_selector_->EnableQueue( |
379 IDLE_TASK_QUEUE, RendererTaskQueueSelector::BEST_EFFORT_PRIORITY); | 492 IDLE_TASK_QUEUE, RendererTaskQueueSelector::BEST_EFFORT_PRIORITY); |
380 task_queue_manager_->PumpQueue(IDLE_TASK_QUEUE); | 493 task_queue_manager_->PumpQueue(IDLE_TASK_QUEUE); |
494 in_idle_period_ = true; | |
381 } | 495 } |
382 | 496 |
383 void RendererSchedulerImpl::EndIdlePeriod() { | 497 void RendererSchedulerImpl::EndIdlePeriod() { |
498 DCHECK(main_thread_checker_.CalledOnValidThread()); | |
499 | |
500 end_idle_period_closure_.Cancel(); | |
501 initiate_next_long_idle_period_closure_.Cancel(); | |
502 after_wakeup_initiate_next_long_idle_period_closure_.Cancel(); | |
503 | |
504 if (!in_idle_period_) | |
505 return; | |
506 | |
507 renderer_task_queue_selector_->DisableQueue(IDLE_TASK_QUEUE); | |
384 bool is_tracing; | 508 bool is_tracing; |
385 TRACE_EVENT_CATEGORY_GROUP_ENABLED("renderer.scheduler", &is_tracing); | 509 TRACE_EVENT_CATEGORY_GROUP_ENABLED("renderer.scheduler", &is_tracing); |
386 if (is_tracing && !estimated_next_frame_begin_.is_null() && | 510 if (is_tracing && !estimated_next_frame_begin_.is_null() && |
387 base::TimeTicks::Now() > estimated_next_frame_begin_) { | 511 base::TimeTicks::Now() > estimated_next_frame_begin_) { |
388 TRACE_EVENT_ASYNC_STEP_INTO_WITH_TIMESTAMP0( | 512 TRACE_EVENT_ASYNC_STEP_INTO_WITH_TIMESTAMP0( |
389 "renderer.scheduler", | 513 "renderer.scheduler", |
390 "RendererSchedulerIdlePeriod", | 514 "RendererSchedulerIdlePeriod", |
391 this, | 515 this, |
392 "DeadlineOverrun", | 516 "DeadlineOverrun", |
393 estimated_next_frame_begin_.ToInternalValue()); | 517 estimated_next_frame_begin_.ToInternalValue()); |
394 } | 518 } |
395 TRACE_EVENT_ASYNC_END0("renderer.scheduler", | 519 TRACE_EVENT_ASYNC_END0("renderer.scheduler", |
396 "RendererSchedulerIdlePeriod", this); | 520 "RendererSchedulerIdlePeriod", this); |
397 DCHECK(main_thread_checker_.CalledOnValidThread()); | |
398 end_idle_period_closure_.Cancel(); | |
399 renderer_task_queue_selector_->DisableQueue(IDLE_TASK_QUEUE); | |
400 } | 521 } |
401 | 522 |
402 void RendererSchedulerImpl::SetTimeSourceForTesting( | 523 void RendererSchedulerImpl::SetTimeSourceForTesting( |
403 scoped_refptr<cc::TestNowSource> time_source) { | 524 scoped_refptr<cc::TestNowSource> time_source) { |
404 DCHECK(main_thread_checker_.CalledOnValidThread()); | 525 DCHECK(main_thread_checker_.CalledOnValidThread()); |
405 time_source_ = time_source; | 526 time_source_ = time_source; |
406 task_queue_manager_->SetTimeSourceForTesting(time_source); | 527 task_queue_manager_->SetTimeSourceForTesting(time_source); |
407 } | 528 } |
408 | 529 |
409 void RendererSchedulerImpl::SetWorkBatchSizeForTesting(size_t work_batch_size) { | 530 void RendererSchedulerImpl::SetWorkBatchSizeForTesting(size_t work_batch_size) { |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
555 } | 676 } |
556 | 677 |
557 void RendererSchedulerImpl::RemoveTaskObserver( | 678 void RendererSchedulerImpl::RemoveTaskObserver( |
558 base::MessageLoop::TaskObserver* task_observer) { | 679 base::MessageLoop::TaskObserver* task_observer) { |
559 DCHECK(main_thread_checker_.CalledOnValidThread()); | 680 DCHECK(main_thread_checker_.CalledOnValidThread()); |
560 if (task_queue_manager_) | 681 if (task_queue_manager_) |
561 task_queue_manager_->RemoveTaskObserver(task_observer); | 682 task_queue_manager_->RemoveTaskObserver(task_observer); |
562 } | 683 } |
563 | 684 |
564 } // namespace content | 685 } // namespace content |
OLD | NEW |