summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/platform/scheduler/child/idle_helper.h
diff options
context:
space:
mode:
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.h249
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_