sequence_manager.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. // Copyright 2018 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef BASE_TASK_SEQUENCE_MANAGER_SEQUENCE_MANAGER_H_
  5. #define BASE_TASK_SEQUENCE_MANAGER_SEQUENCE_MANAGER_H_
  6. #include <memory>
  7. #include <string>
  8. #include <utility>
  9. #include "base/message_loop/message_pump_type.h"
  10. #include "base/message_loop/timer_slack.h"
  11. #include "base/sequenced_task_runner.h"
  12. #include "base/single_thread_task_runner.h"
  13. #include "base/task/sequence_manager/task_queue_impl.h"
  14. #include "base/task/sequence_manager/task_time_observer.h"
  15. #include "base/time/default_tick_clock.h"
  16. namespace base {
  17. class MessagePump;
  18. class TaskObserver;
  19. namespace sequence_manager {
  20. class TimeDomain;
  21. // Represent outstanding work the sequence underlying a SequenceManager (e.g.,
  22. // a native system task for drawing the UI). As long as this handle is alive,
  23. // the work is considered to be pending.
  24. class NativeWorkHandle {
  25. public:
  26. virtual ~NativeWorkHandle();
  27. NativeWorkHandle(const NativeWorkHandle&) = delete;
  28. protected:
  29. NativeWorkHandle() = default;
  30. };
  31. // SequenceManager manages TaskQueues which have different properties
  32. // (e.g. priority, common task type) multiplexing all posted tasks into
  33. // a single backing sequence (currently bound to a single thread, which is
  34. // refererred as *main thread* in the comments below). SequenceManager
  35. // implementation can be used in a various ways to apply scheduling logic.
  36. class BASE_EXPORT SequenceManager {
  37. public:
  38. class Observer {
  39. public:
  40. virtual ~Observer() = default;
  41. // Called back on the main thread.
  42. virtual void OnBeginNestedRunLoop() = 0;
  43. virtual void OnExitNestedRunLoop() = 0;
  44. };
  45. struct MetricRecordingSettings {
  46. // This parameter will be updated for consistency on creation (setting
  47. // value to 0 when ThreadTicks are not supported).
  48. explicit MetricRecordingSettings(
  49. double task_sampling_rate_for_recording_cpu_time);
  50. // The proportion of the tasks for which the cpu time will be
  51. // sampled or 0 if this is not enabled.
  52. // Since randomised sampling requires the use of Rand(), it is enabled only
  53. // on platforms which support it.
  54. // If it is 1 then cpu time is measured for each task, so the integral
  55. // metrics (as opposed to per-task metrics) can be recorded.
  56. double task_sampling_rate_for_recording_cpu_time = 0;
  57. bool records_cpu_time_for_some_tasks() const {
  58. return task_sampling_rate_for_recording_cpu_time > 0.0;
  59. }
  60. bool records_cpu_time_for_all_tasks() const {
  61. return task_sampling_rate_for_recording_cpu_time == 1.0;
  62. }
  63. };
  64. // Settings defining the desired SequenceManager behaviour: the type of the
  65. // MessageLoop and whether randomised sampling should be enabled.
  66. struct BASE_EXPORT Settings {
  67. class Builder;
  68. Settings();
  69. Settings(const Settings&) = delete;
  70. Settings& operator=(const Settings&) = delete;
  71. // In the future MessagePump (which is move-only) will also be a setting,
  72. // so we are making Settings move-only in preparation.
  73. Settings(Settings&& move_from) noexcept;
  74. MessagePumpType message_loop_type = MessagePumpType::DEFAULT;
  75. bool randomised_sampling_enabled = false;
  76. const TickClock* clock = DefaultTickClock::GetInstance();
  77. // If true, add the timestamp the task got queued to the task.
  78. bool add_queue_time_to_tasks = false;
  79. #if DCHECK_IS_ON()
  80. // TODO(alexclarke): Consider adding command line flags to control these.
  81. enum class TaskLogging {
  82. kNone,
  83. kEnabled,
  84. kEnabledWithBacktrace,
  85. // Logs high priority tasks and the lower priority tasks they skipped
  86. // past. Useful for debugging test failures caused by scheduler policy
  87. // changes.
  88. kReorderedOnly,
  89. };
  90. TaskLogging task_execution_logging = TaskLogging::kNone;
  91. // If true PostTask will emit a debug log.
  92. bool log_post_task = false;
  93. // If true debug logs will be emitted when a delayed task becomes eligible
  94. // to run.
  95. bool log_task_delay_expiry = false;
  96. // If true usages of the RunLoop API will be logged.
  97. bool log_runloop_quit_and_quit_when_idle = false;
  98. // Scheduler policy induced raciness is an area of concern. This lets us
  99. // apply an extra delay per priority for cross thread posting.
  100. std::array<TimeDelta, TaskQueue::kQueuePriorityCount>
  101. per_priority_cross_thread_task_delay;
  102. // Like the above but for same thread posting.
  103. std::array<TimeDelta, TaskQueue::kQueuePriorityCount>
  104. per_priority_same_thread_task_delay;
  105. // If not zero this seeds a PRNG used by the task selection logic to choose
  106. // a random TaskQueue for a given priority rather than the TaskQueue with
  107. // the oldest EnqueueOrder.
  108. int random_task_selection_seed = 0;
  109. #endif // DCHECK_IS_ON()
  110. };
  111. virtual ~SequenceManager() = default;
  112. // Binds the SequenceManager and its TaskQueues to the current thread. Should
  113. // only be called once. Note that CreateSequenceManagerOnCurrentThread()
  114. // performs this initialization automatically.
  115. virtual void BindToCurrentThread() = 0;
  116. // Returns the task runner the current task was posted on. Returns null if no
  117. // task is currently running. Must be called on the bound thread.
  118. virtual scoped_refptr<SequencedTaskRunner> GetTaskRunnerForCurrentTask() = 0;
  119. // Finishes the initialization for a SequenceManager created via
  120. // CreateUnboundSequenceManager(). Must not be called in any other
  121. // circumstances. The ownership of the pump is transferred to SequenceManager.
  122. virtual void BindToMessagePump(std::unique_ptr<MessagePump> message_pump) = 0;
  123. // Must be called on the main thread.
  124. // Can be called only once, before creating TaskQueues.
  125. // Observer must outlive the SequenceManager.
  126. virtual void SetObserver(Observer* observer) = 0;
  127. // Must be called on the main thread.
  128. virtual void AddTaskTimeObserver(TaskTimeObserver* task_time_observer) = 0;
  129. virtual void RemoveTaskTimeObserver(TaskTimeObserver* task_time_observer) = 0;
  130. // Registers a TimeDomain with SequenceManager.
  131. // TaskQueues must only be created with a registered TimeDomain.
  132. // Conversely, any TimeDomain must remain registered until no
  133. // TaskQueues (using that TimeDomain) remain.
  134. virtual void RegisterTimeDomain(TimeDomain* time_domain) = 0;
  135. virtual void UnregisterTimeDomain(TimeDomain* time_domain) = 0;
  136. virtual TimeDomain* GetRealTimeDomain() const = 0;
  137. virtual const TickClock* GetTickClock() const = 0;
  138. virtual TimeTicks NowTicks() const = 0;
  139. // Sets the SingleThreadTaskRunner that will be returned by
  140. // ThreadTaskRunnerHandle::Get on the main thread.
  141. virtual void SetDefaultTaskRunner(
  142. scoped_refptr<SingleThreadTaskRunner> task_runner) = 0;
  143. // Removes all canceled delayed tasks, and considers resizing to fit all
  144. // internal queues.
  145. virtual void ReclaimMemory() = 0;
  146. // Returns true if no tasks were executed in TaskQueues that monitor
  147. // quiescence since the last call to this method.
  148. virtual bool GetAndClearSystemIsQuiescentBit() = 0;
  149. // Set the number of tasks executed in a single SequenceManager invocation.
  150. // Increasing this number reduces the overhead of the tasks dispatching
  151. // logic at the cost of a potentially worse latency. 1 by default.
  152. virtual void SetWorkBatchSize(int work_batch_size) = 0;
  153. // Requests desired timer precision from the OS.
  154. // Has no effect on some platforms.
  155. virtual void SetTimerSlack(TimerSlack timer_slack) = 0;
  156. // Enables crash keys that can be set in the scope of a task which help
  157. // to identify the culprit if upcoming work results in a crash.
  158. // Key names must be thread-specific to avoid races and corrupted crash dumps.
  159. virtual void EnableCrashKeys(const char* async_stack_crash_key) = 0;
  160. // Returns the metric recording configuration for the current SequenceManager.
  161. virtual const MetricRecordingSettings& GetMetricRecordingSettings() const = 0;
  162. // Creates a task queue with the given type, |spec| and args.
  163. // Must be called on the main thread.
  164. // TODO(scheduler-dev): SequenceManager should not create TaskQueues.
  165. template <typename TaskQueueType, typename... Args>
  166. scoped_refptr<TaskQueueType> CreateTaskQueueWithType(
  167. const TaskQueue::Spec& spec,
  168. Args&&... args) {
  169. return WrapRefCounted(new TaskQueueType(CreateTaskQueueImpl(spec), spec,
  170. std::forward<Args>(args)...));
  171. }
  172. // Creates a vanilla TaskQueue rather than a user type derived from it. This
  173. // should be used if you don't wish to sub class TaskQueue.
  174. // Must be called on the main thread.
  175. virtual scoped_refptr<TaskQueue> CreateTaskQueue(
  176. const TaskQueue::Spec& spec) = 0;
  177. // Returns true iff this SequenceManager has no immediate work to do. I.e.
  178. // there are no pending non-delayed tasks or delayed tasks that are due to
  179. // run. This method ignores any pending delayed tasks that might have become
  180. // eligible to run since the last task was executed. This is important because
  181. // if it did tests would become flaky depending on the exact timing of this
  182. // call. This is moderately expensive.
  183. virtual bool IsIdleForTesting() = 0;
  184. // The total number of posted tasks that haven't executed yet.
  185. virtual size_t GetPendingTaskCountForTesting() const = 0;
  186. // Returns a JSON string which describes all pending tasks.
  187. virtual std::string DescribeAllPendingTasks() const = 0;
  188. // Indicates that the underlying sequence (e.g., the message pump) has pending
  189. // work at priority |priority|. If the priority of the work in this
  190. // SequenceManager is lower, it will yield to let the native work run. The
  191. // native work is assumed to remain pending while the returned handle is
  192. // valid.
  193. //
  194. // Must be called on the main thread, and the returned handle must also be
  195. // deleted on the main thread.
  196. virtual std::unique_ptr<NativeWorkHandle> OnNativeWorkPending(
  197. TaskQueue::QueuePriority priority) = 0;
  198. // Adds an observer which reports task execution. Can only be called on the
  199. // same thread that |this| is running on.
  200. virtual void AddTaskObserver(TaskObserver* task_observer) = 0;
  201. // Removes an observer which reports task execution. Can only be called on the
  202. // same thread that |this| is running on.
  203. virtual void RemoveTaskObserver(TaskObserver* task_observer) = 0;
  204. protected:
  205. virtual std::unique_ptr<internal::TaskQueueImpl> CreateTaskQueueImpl(
  206. const TaskQueue::Spec& spec) = 0;
  207. };
  208. class BASE_EXPORT SequenceManager::Settings::Builder {
  209. public:
  210. Builder();
  211. ~Builder();
  212. // Sets the MessagePumpType which is used to create a MessagePump.
  213. Builder& SetMessagePumpType(MessagePumpType message_loop_type);
  214. Builder& SetRandomisedSamplingEnabled(bool randomised_sampling_enabled);
  215. // Sets the TickClock the SequenceManager uses to obtain Now.
  216. Builder& SetTickClock(const TickClock* clock);
  217. // Whether or not queueing timestamp will be added to tasks.
  218. Builder& SetAddQueueTimeToTasks(bool add_queue_time_to_tasks);
  219. #if DCHECK_IS_ON()
  220. // Controls task execution logging.
  221. Builder& SetTaskLogging(TaskLogging task_execution_logging);
  222. // Whether or not PostTask will emit a debug log.
  223. Builder& SetLogPostTask(bool log_post_task);
  224. // Whether or not debug logs will be emitted when a delayed task becomes
  225. // eligible to run.
  226. Builder& SetLogTaskDelayExpiry(bool log_task_delay_expiry);
  227. // Whether or not usages of the RunLoop API will be logged.
  228. Builder& SetLogRunloopQuitAndQuitWhenIdle(
  229. bool log_runloop_quit_and_quit_when_idle);
  230. // Scheduler policy induced raciness is an area of concern. This lets us
  231. // apply an extra delay per priority for cross thread posting.
  232. Builder& SetPerPriorityCrossThreadTaskDelay(
  233. std::array<TimeDelta, TaskQueue::kQueuePriorityCount>
  234. per_priority_cross_thread_task_delay);
  235. // Scheduler policy induced raciness is an area of concern. This lets us
  236. // apply an extra delay per priority for same thread posting.
  237. Builder& SetPerPrioritySameThreadTaskDelay(
  238. std::array<TimeDelta, TaskQueue::kQueuePriorityCount>
  239. per_priority_same_thread_task_delay);
  240. // If not zero this seeds a PRNG used by the task selection logic to choose a
  241. // random TaskQueue for a given priority rather than the TaskQueue with the
  242. // oldest EnqueueOrder.
  243. Builder& SetRandomTaskSelectionSeed(int random_task_selection_seed);
  244. #endif // DCHECK_IS_ON()
  245. Settings Build();
  246. private:
  247. Settings settings_;
  248. };
  249. // Create SequenceManager using MessageLoop on the current thread.
  250. // Implementation is located in sequence_manager_impl.cc.
  251. // TODO(scheduler-dev): Remove after every thread has a SequenceManager.
  252. BASE_EXPORT std::unique_ptr<SequenceManager>
  253. CreateSequenceManagerOnCurrentThread(SequenceManager::Settings settings);
  254. // Create a SequenceManager using the given MessagePump on the current thread.
  255. // MessagePump instances can be created with
  256. // MessagePump::CreateMessagePumpForType().
  257. BASE_EXPORT std::unique_ptr<SequenceManager>
  258. CreateSequenceManagerOnCurrentThreadWithPump(
  259. std::unique_ptr<MessagePump> message_pump,
  260. SequenceManager::Settings settings = SequenceManager::Settings());
  261. // Create an unbound SequenceManager (typically for a future thread or because
  262. // additional setup is required before binding). The SequenceManager can be
  263. // initialized on the current thread and then needs to be bound and initialized
  264. // on the target thread by calling one of the Bind*() methods.
  265. BASE_EXPORT std::unique_ptr<SequenceManager> CreateUnboundSequenceManager(
  266. SequenceManager::Settings settings = SequenceManager::Settings());
  267. } // namespace sequence_manager
  268. } // namespace base
  269. #endif // BASE_TASK_SEQUENCE_MANAGER_SEQUENCE_MANAGER_H_