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