diff options
Diffstat (limited to 'chromium/third_party/blink/renderer/platform/scheduler/child/idle_helper.h')
-rw-r--r-- | chromium/third_party/blink/renderer/platform/scheduler/child/idle_helper.h | 249 |
1 files changed, 249 insertions, 0 deletions
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/child/idle_helper.h b/chromium/third_party/blink/renderer/platform/scheduler/child/idle_helper.h new file mode 100644 index 00000000000..8f0ec9a79c5 --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/scheduler/child/idle_helper.h @@ -0,0 +1,249 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_CHILD_IDLE_HELPER_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_CHILD_IDLE_HELPER_H_ + +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "base/message_loop/message_loop.h" +#include "third_party/blink/public/platform/scheduler/single_thread_idle_task_runner.h" +#include "third_party/blink/renderer/platform/platform_export.h" +#include "third_party/blink/renderer/platform/scheduler/base/task_queue_selector.h" +#include "third_party/blink/renderer/platform/scheduler/child/cancelable_closure_holder.h" +#include "third_party/blink/renderer/platform/scheduler/common/scheduler_helper.h" + +namespace blink { +namespace scheduler { +namespace idle_helper_unittest { +class BaseIdleHelperTest; +class IdleHelperTest; +} // namespace idle_helper_unittest + +class SchedulerHelper; + +// The job of the IdleHelper is to run idle tasks when the system is otherwise +// idle. Idle tasks should be optional work, with no guarantee they will be run +// at all. Idle tasks are subject to three levels of throttling: +// +// 1. Both idle queues are run a BEST_EFFORT priority (i.e. only selected if +// there is nothing else to do. +// 2. The idle queues are only enabled during an idle period. +// 3. Idle tasks posted from within an idle task run in the next idle period. +// This is achieved by inserting a fence into the queue. +// +// There are two types of idle periods: +// 1. Short idle period - typically less than 10ms run after begin main frame +// has finished, with the idle period ending at the compositor provided +// deadline. +// 2. Long idle periods - typically up to 50ms when no frames are being +// produced. +// +// Idle tasks are supplied a deadline, and should endeavor to finished before it +// ends to avoid jank. +class PLATFORM_EXPORT IdleHelper : public base::MessageLoop::TaskObserver, + public SingleThreadIdleTaskRunner::Delegate { + public: + // Used to by scheduler implementations to customize idle behaviour. + class PLATFORM_EXPORT Delegate { + public: + Delegate(); + virtual ~Delegate(); + + // If it's ok to enter a long idle period, return true. Otherwise return + // false and set next_long_idle_period_delay_out so we know when to try + // again. + virtual bool CanEnterLongIdlePeriod( + base::TimeTicks now, + base::TimeDelta* next_long_idle_period_delay_out) = 0; + + // Signals that the Long Idle Period hasn't started yet because the system + // isn't quiescent. + virtual void IsNotQuiescent() = 0; + + // Signals that we have started an Idle Period. + virtual void OnIdlePeriodStarted() = 0; + + // Signals that we have finished an Idle Period. + virtual void OnIdlePeriodEnded() = 0; + + // Signals that the task list has changed. + virtual void OnPendingTasksChanged(bool has_tasks) = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(Delegate); + }; + + // Keep IdleHelper::IdlePeriodStateToString in sync with this enum. + enum class IdlePeriodState { + kNotInIdlePeriod, + kInShortIdlePeriod, + kInLongIdlePeriod, + kInLongIdlePeriodWithMaxDeadline, + kInLongIdlePeriodPaused, + // Must be the last entry. + kIdlePeriodStateCount, + kFirstIdlePeriodState = kNotInIdlePeriod, + }; + + // The maximum length of an idle period. + static const int kMaximumIdlePeriodMillis = 50; + + // |helper| and |delegate| are not owned by IdleHelper object and must + // outlive it. + IdleHelper( + SchedulerHelper* helper, + Delegate* delegate, + const char* idle_period_tracing_name, + base::TimeDelta required_quiescence_duration_before_long_idle_period, + scoped_refptr<TaskQueue> idle_queue); + ~IdleHelper() override; + + // Prevents any further idle tasks from running. + void Shutdown(); + + // Returns the idle task runner. Tasks posted to this runner may be reordered + // relative to other task types and may be starved for an arbitrarily long + // time if no idle time is available. + scoped_refptr<SingleThreadIdleTaskRunner> IdleTaskRunner(); + + // If |required_quiescence_duration_before_long_idle_period_| is zero then + // immediately initiate a long idle period, otherwise check if any tasks have + // run recently and if so, check again after a delay of + // |required_quiescence_duration_before_long_idle_period_|. + // Calling this function will end any previous idle period immediately, and + // potentially again later if + // |required_quiescence_duration_before_long_idle_period_| is non-zero. + // NOTE EndIdlePeriod will disable the long idle periods. + void EnableLongIdlePeriod(); + + // Start an idle period with a given idle period deadline. + void StartIdlePeriod(IdlePeriodState new_idle_period_state, + base::TimeTicks now, + base::TimeTicks idle_period_deadline); + + // This will end an idle period either started with StartIdlePeriod or + // EnableLongIdlePeriod. + void EndIdlePeriod(); + + // Returns true if a currently running idle task could exceed its deadline + // without impacting user experience too much. This should only be used if + // there is a task which cannot be pre-empted and is likely to take longer + // than the largest expected idle task deadline. It should NOT be polled to + // check whether more work can be performed on the current idle task after + // its deadline has expired - post a new idle task for the continuation of the + // work in this case. + // Must be called from the thread this class was created on. + bool CanExceedIdleDeadlineIfRequired() const; + + // Returns the deadline for the current idle task. + base::TimeTicks CurrentIdleTaskDeadline() const; + + // SingleThreadIdleTaskRunner::Delegate implementation: + void OnIdleTaskPosted() override; + base::TimeTicks WillProcessIdleTask() override; + void DidProcessIdleTask() override; + base::TimeTicks NowTicks() override; + + // base::MessageLoop::TaskObserver implementation: + void WillProcessTask(const base::PendingTask& pending_task) override; + void DidProcessTask(const base::PendingTask& pending_task) override; + + IdlePeriodState SchedulerIdlePeriodState() const; + static const char* IdlePeriodStateToString(IdlePeriodState state); + + private: + friend class idle_helper_unittest::BaseIdleHelperTest; + friend class idle_helper_unittest::IdleHelperTest; + + const scoped_refptr<TaskQueue>& idle_queue() const { return idle_queue_; } + + class State { + public: + State(SchedulerHelper* helper, + Delegate* delegate, + const char* idle_period_tracing_name); + virtual ~State(); + + void UpdateState(IdlePeriodState new_state, + base::TimeTicks new_deadline, + base::TimeTicks optional_now); + bool IsIdlePeriodPaused() const; + + IdlePeriodState idle_period_state() const; + base::TimeTicks idle_period_deadline() const; + + void TraceIdleIdleTaskStart(); + void TraceIdleIdleTaskEnd(); + + private: + void TraceEventIdlePeriodStateChange(IdlePeriodState new_state, + bool new_running_idle_task, + base::TimeTicks new_deadline, + base::TimeTicks optional_now); + + SchedulerHelper* helper_; // NOT OWNED + Delegate* delegate_; // NOT OWNED + + IdlePeriodState idle_period_state_; + base::TimeTicks idle_period_deadline_; + + base::TimeTicks last_idle_task_trace_time_; + bool idle_period_trace_event_started_; + bool running_idle_task_for_tracing_; + const char* idle_period_tracing_name_; + + DISALLOW_COPY_AND_ASSIGN(State); + }; + + // The minimum duration of an idle period. + static const int kMinimumIdlePeriodDurationMillis = 1; + + // The minimum delay to wait between retrying to initiate a long idle time. + static const int kRetryEnableLongIdlePeriodDelayMillis = 1; + + // Returns the new idle period state for the next long idle period. Fills in + // |next_long_idle_period_delay_out| with the next time we should try to + // initiate the next idle period. + IdlePeriodState ComputeNewLongIdlePeriodState( + const base::TimeTicks now, + base::TimeDelta* next_long_idle_period_delay_out); + + bool ShouldWaitForQuiescence(); + void OnIdleTaskPostedOnMainThread(); + void UpdateLongIdlePeriodStateAfterIdleTask(); + + void SetIdlePeriodState(IdlePeriodState new_state, + base::TimeTicks new_deadline, + base::TimeTicks optional_now); + + // Returns true if |state| represents being within an idle period state. + static bool IsInIdlePeriod(IdlePeriodState state); + // Returns true if |state| represents being within a long idle period state. + static bool IsInLongIdlePeriod(IdlePeriodState state); + + SchedulerHelper* helper_; // NOT OWNED + Delegate* delegate_; // NOT OWNED + scoped_refptr<TaskQueue> idle_queue_; + scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_; + + CancelableClosureHolder enable_next_long_idle_period_closure_; + CancelableClosureHolder on_idle_task_posted_closure_; + + State state_; + + base::TimeDelta required_quiescence_duration_before_long_idle_period_; + + bool is_shutdown_; + + base::WeakPtr<IdleHelper> weak_idle_helper_ptr_; + base::WeakPtrFactory<IdleHelper> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(IdleHelper); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_CHILD_IDLE_HELPER_H_ |