| 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 "config.h" | 5 #include "config.h" |
| 6 #include "platform/scheduler/Scheduler.h" | 6 #include "platform/scheduler/Scheduler.h" |
| 7 | 7 |
| 8 #include "platform/PlatformThreadData.h" | 8 #include "platform/TraceLocation.h" |
| 9 #include "platform/RuntimeEnabledFeatures.h" | |
| 10 #include "platform/Task.h" | |
| 11 #include "platform/ThreadTimers.h" | |
| 12 #include "platform/TraceEvent.h" | |
| 13 #include "public/platform/Platform.h" | 9 #include "public/platform/Platform.h" |
| 14 #include "wtf/MainThread.h" | 10 #include "public/platform/WebScheduler.h" |
| 15 | 11 |
| 16 namespace blink { | 12 namespace blink { |
| 17 | 13 |
| 18 namespace { | 14 class IdleTaskRunner : public WebScheduler::IdleTask { |
| 19 | |
| 20 // The time we should stay in CompositorPriority mode for, after a touch event. | |
| 21 double kLowSchedulerPolicyAfterTouchTimeSeconds = 0.1; | |
| 22 | |
| 23 } // namespace | |
| 24 | |
| 25 // Typically only created from compositor or render threads. | |
| 26 // Note if the scheduler gets shutdown, this may be run after. | |
| 27 class Scheduler::MainThreadPendingHighPriorityTaskRunner : public WebThread::Tas
k { | |
| 28 public: | 15 public: |
| 29 MainThreadPendingHighPriorityTaskRunner( | 16 explicit IdleTaskRunner(const Scheduler::IdleTask& task) |
| 30 const Scheduler::Task& task, const TraceLocation& location, const char*
traceName) | 17 : m_task(task) |
| 31 : m_task(internal::TracedStandardTask::Create(task, location, traceName)
) | |
| 32 { | 18 { |
| 33 ASSERT(Scheduler::shared()); | |
| 34 } | 19 } |
| 35 | 20 |
| 36 // WebThread::Task implementation. | 21 virtual ~IdleTaskRunner() |
| 37 virtual void run() override | |
| 38 { | 22 { |
| 39 m_task->run(); | |
| 40 if (Scheduler* scheduler = Scheduler::shared()) { | |
| 41 scheduler->updatePolicy(); | |
| 42 scheduler->didRunHighPriorityTask(); | |
| 43 } | |
| 44 } | 23 } |
| 45 | 24 |
| 25 // WebScheduler::IdleTask implementation. |
| 26 void run(double deadlineSeconds) override |
| 27 { |
| 28 m_task(deadlineSeconds); |
| 29 } |
| 46 private: | 30 private: |
| 47 OwnPtr<internal::TracedStandardTask> m_task; | 31 Scheduler::IdleTask m_task; |
| 48 }; | 32 }; |
| 49 | 33 |
| 50 // Can be created from any thread. | |
| 51 // Note if the scheduler gets shutdown, this may be run after. | |
| 52 class Scheduler::MainThreadPendingTaskRunner : public WebThread::Task { | |
| 53 public: | |
| 54 MainThreadPendingTaskRunner( | |
| 55 const Scheduler::Task& task, const TraceLocation& location, const char*
traceName) | |
| 56 : m_task(internal::TracedStandardTask::Create(task, location, traceName)
) | |
| 57 { | |
| 58 ASSERT(Scheduler::shared()); | |
| 59 } | |
| 60 | |
| 61 // WebThread::Task implementation. | |
| 62 virtual void run() override | |
| 63 { | |
| 64 m_task->run(); | |
| 65 if (Scheduler* scheduler = Scheduler::shared()) { | |
| 66 scheduler->updatePolicy(); | |
| 67 } | |
| 68 } | |
| 69 | |
| 70 private: | |
| 71 OwnPtr<internal::TracedStandardTask> m_task; | |
| 72 }; | |
| 73 | |
| 74 | |
| 75 // Can be created from any thread. | |
| 76 // Note if the scheduler gets shutdown, this may be run after. | |
| 77 class Scheduler::MainThreadPendingIdleTaskRunner : public WebThread::Task { | |
| 78 public: | |
| 79 MainThreadPendingIdleTaskRunner() | |
| 80 { | |
| 81 ASSERT(Scheduler::shared()); | |
| 82 } | |
| 83 | |
| 84 // WebThread::Task implementation. | |
| 85 virtual void run() override | |
| 86 { | |
| 87 if (Scheduler* scheduler = Scheduler::shared()) { | |
| 88 scheduler->maybeRunPendingIdleTask(); | |
| 89 // If possible, run the next idle task by reposting on the main thre
ad. | |
| 90 scheduler->maybePostMainThreadPendingIdleTask(); | |
| 91 } | |
| 92 } | |
| 93 | |
| 94 }; | |
| 95 | |
| 96 | |
| 97 Scheduler* Scheduler::s_sharedScheduler = nullptr; | 34 Scheduler* Scheduler::s_sharedScheduler = nullptr; |
| 98 | 35 |
| 99 void Scheduler::initializeOnMainThread() | |
| 100 { | |
| 101 s_sharedScheduler = new Scheduler(); | |
| 102 } | |
| 103 | |
| 104 void Scheduler::shutdown() | 36 void Scheduler::shutdown() |
| 105 { | 37 { |
| 106 delete s_sharedScheduler; | 38 delete s_sharedScheduler; |
| 107 s_sharedScheduler = nullptr; | 39 s_sharedScheduler = nullptr; |
| 108 } | 40 } |
| 109 | 41 |
| 110 Scheduler* Scheduler::shared() | 42 Scheduler* Scheduler::shared() |
| 111 { | 43 { |
| 44 if (!s_sharedScheduler) |
| 45 s_sharedScheduler = new Scheduler(Platform::current()->scheduler()); |
| 112 return s_sharedScheduler; | 46 return s_sharedScheduler; |
| 113 } | 47 } |
| 114 | 48 |
| 115 Scheduler::Scheduler() | 49 Scheduler::Scheduler(WebScheduler* webScheduler) |
| 116 : m_sharedTimerFunction(nullptr) | 50 : m_webScheduler(webScheduler) |
| 117 , m_mainThread(blink::Platform::current()->currentThread()) | |
| 118 , m_estimatedNextBeginFrameSeconds(0) | |
| 119 , m_highPriorityTaskCount(0) | |
| 120 , m_highPriorityTaskRunnerPosted(false) | |
| 121 , m_compositorPriorityPolicyEndTimeSeconds(0) | |
| 122 , m_schedulerPolicy(Normal) | |
| 123 { | 51 { |
| 124 } | 52 } |
| 125 | 53 |
| 126 Scheduler::~Scheduler() | 54 Scheduler::~Scheduler() |
| 127 { | 55 { |
| 128 } | 56 if (m_webScheduler) |
| 129 | 57 m_webScheduler->shutdown(); |
| 130 void Scheduler::willBeginFrame(double estimatedNextBeginFrameSeconds) | |
| 131 { | |
| 132 ASSERT(isMainThread()); | |
| 133 m_currentFrameCommitted = false; | |
| 134 m_estimatedNextBeginFrameSeconds = estimatedNextBeginFrameSeconds; | |
| 135 // TODO: Schedule a deferred task here to run idle work if didCommitFrameToC
ompositor never gets called. | |
| 136 } | |
| 137 | |
| 138 void Scheduler::didCommitFrameToCompositor() | |
| 139 { | |
| 140 ASSERT(isMainThread()); | |
| 141 m_currentFrameCommitted = true; | |
| 142 flushIncomingIdleTasks(); | |
| 143 maybePostMainThreadPendingIdleTask(); | |
| 144 } | |
| 145 | |
| 146 void Scheduler::postHighPriorityTaskInternal(const TraceLocation& location, cons
t Task& task, const char* traceName) | |
| 147 { | |
| 148 m_mainThread->postTask(new MainThreadPendingHighPriorityTaskRunner(task, loc
ation, traceName)); | |
| 149 atomicIncrement(&m_highPriorityTaskCount); | |
| 150 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), "PendingHighPri
orityTasks", m_highPriorityTaskCount); | |
| 151 } | |
| 152 | |
| 153 void Scheduler::didRunHighPriorityTask() | |
| 154 { | |
| 155 atomicDecrement(&m_highPriorityTaskCount); | |
| 156 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), "PendingHighPri
orityTasks", m_highPriorityTaskCount); | |
| 157 } | |
| 158 | |
| 159 void Scheduler::postIdleTaskInternal(const TraceLocation& location, const IdleTa
sk& idleTask, const char* traceName) | |
| 160 { | |
| 161 Locker<Mutex> lock(m_incomingIdleTasksMutex); | |
| 162 m_incomingIdleTasks.append(internal::TracedIdleTask::Create(idleTask, locati
on, traceName)); | |
| 163 } | |
| 164 | |
| 165 void Scheduler::postTask(const TraceLocation& location, const Task& task) | |
| 166 { | |
| 167 m_mainThread->postTask(new MainThreadPendingTaskRunner(task, location, "Sche
duler::MainThreadTask")); | |
| 168 } | |
| 169 | |
| 170 void Scheduler::postInputTask(const TraceLocation& location, const Task& task) | |
| 171 { | |
| 172 postHighPriorityTaskInternal(location, task, "Scheduler::InputTask"); | |
| 173 } | |
| 174 | |
| 175 void Scheduler::didReceiveInputEvent() | |
| 176 { | |
| 177 // FIXME: We probably want an explicit Disabled policy rather than disabling
CompositorPriority. | |
| 178 if (RuntimeEnabledFeatures::blinkSchedulerEnabled()) | |
| 179 enterSchedulerPolicy(CompositorPriority); | |
| 180 } | |
| 181 | |
| 182 void Scheduler::postCompositorTask(const TraceLocation& location, const Task& ta
sk) | |
| 183 { | |
| 184 postHighPriorityTaskInternal(location, task, "Scheduler::CompositorTask"); | |
| 185 } | |
| 186 | |
| 187 void Scheduler::postIpcTask(const TraceLocation& location, const Task& task) | |
| 188 { | |
| 189 // FIXME: we want IPCs to be high priority, but we can't currently do that b
ecause some of them can take a very long | |
| 190 // time to process. These need refactoring but we need to add some infrastru
cture to identify them. | |
| 191 m_mainThread->postTask(new MainThreadPendingTaskRunner(task, location, "Sche
duler::IpcTask")); | |
| 192 } | 58 } |
| 193 | 59 |
| 194 void Scheduler::postIdleTask(const TraceLocation& location, const IdleTask& idle
Task) | 60 void Scheduler::postIdleTask(const TraceLocation& location, const IdleTask& idle
Task) |
| 195 { | 61 { |
| 196 postIdleTaskInternal(location, idleTask, "Scheduler::IdleTask"); | 62 if (m_webScheduler) |
| 197 } | 63 m_webScheduler->postIdleTask(location.toWebTraceLocation(), new IdleTask
Runner(idleTask)); |
| 198 | |
| 199 bool Scheduler::maybePostMainThreadPendingIdleTask() | |
| 200 { | |
| 201 ASSERT(isMainThread()); | |
| 202 TRACE_EVENT0("blink", "Scheduler::maybePostMainThreadPendingIdleTask"); | |
| 203 if (canRunIdleTask()) { | |
| 204 if (!m_pendingIdleTasks.isEmpty()) { | |
| 205 m_mainThread->postTask(new MainThreadPendingIdleTaskRunner()); | |
| 206 return true; | |
| 207 } | |
| 208 } | |
| 209 return false; | |
| 210 } | |
| 211 | |
| 212 void Scheduler::tickSharedTimer() | |
| 213 { | |
| 214 TRACE_EVENT0("blink", "Scheduler::tickSharedTimer"); | |
| 215 m_sharedTimerFunction(); | |
| 216 } | |
| 217 | |
| 218 void Scheduler::updatePolicy() | |
| 219 { | |
| 220 ASSERT(isMainThread()); | |
| 221 Locker<Mutex> lock(m_policyStateMutex); | |
| 222 | |
| 223 // Go back to the normal scheduler policy if enough time has elapsed. | |
| 224 if (schedulerPolicy() == CompositorPriority && Platform::current()->monotoni
callyIncreasingTime() > m_compositorPriorityPolicyEndTimeSeconds) | |
| 225 enterSchedulerPolicyLocked(Normal); | |
| 226 } | |
| 227 | |
| 228 void Scheduler::sharedTimerAdapter() | |
| 229 { | |
| 230 shared()->tickSharedTimer(); | |
| 231 } | |
| 232 | |
| 233 void Scheduler::setSharedTimerFiredFunction(void (*function)()) | |
| 234 { | |
| 235 m_sharedTimerFunction = function; | |
| 236 blink::Platform::current()->setSharedTimerFiredFunction(function ? &Schedule
r::sharedTimerAdapter : nullptr); | |
| 237 } | |
| 238 | |
| 239 void Scheduler::setSharedTimerFireInterval(double interval) | |
| 240 { | |
| 241 blink::Platform::current()->setSharedTimerFireInterval(interval); | |
| 242 } | |
| 243 | |
| 244 void Scheduler::stopSharedTimer() | |
| 245 { | |
| 246 blink::Platform::current()->stopSharedTimer(); | |
| 247 } | 64 } |
| 248 | 65 |
| 249 bool Scheduler::shouldYieldForHighPriorityWork() const | 66 bool Scheduler::shouldYieldForHighPriorityWork() const |
| 250 { | 67 { |
| 251 // It's only worthwhile yielding in CompositorPriority mode. | 68 if (m_webScheduler) |
| 252 if (schedulerPolicy() != CompositorPriority) | 69 return m_webScheduler->shouldYieldForHighPriorityWork(); |
| 253 return false; | 70 return false; |
| 254 | |
| 255 // This method is expected to be run on the main thread, but the high priori
ty tasks will be posted by | |
| 256 // other threads. We could use locks here, but this function is (sometimes)
called a lot by | |
| 257 // ThreadTimers::sharedTimerFiredInternal so we decided to use atomics + bar
rier loads here which | |
| 258 // should be cheaper. | |
| 259 // NOTE it's possible the barrier read is overkill here, since delayed yield
ing isn't a big deal. | |
| 260 return acquireLoad(&m_highPriorityTaskCount) != 0; | |
| 261 } | |
| 262 | |
| 263 bool Scheduler::maybeRunPendingIdleTask() | |
| 264 { | |
| 265 ASSERT(isMainThread()); | |
| 266 if (!canRunIdleTask() || m_pendingIdleTasks.isEmpty()) | |
| 267 return false; | |
| 268 | |
| 269 m_pendingIdleTasks.takeFirst()->run(); | |
| 270 return true; | |
| 271 } | |
| 272 | |
| 273 void Scheduler::flushIncomingIdleTasks() | |
| 274 { | |
| 275 ASSERT(isMainThread()); | |
| 276 Locker<Mutex> lock(m_incomingIdleTasksMutex); | |
| 277 while (!m_incomingIdleTasks.isEmpty()) | |
| 278 m_pendingIdleTasks.append(m_incomingIdleTasks.takeFirst()); | |
| 279 } | |
| 280 | |
| 281 double Scheduler::currentFrameDeadlineForIdleTasks() const | |
| 282 { | |
| 283 ASSERT(isMainThread()); | |
| 284 // TODO: Make idle time more fine-grain chunks when in Compositor priority. | |
| 285 return m_estimatedNextBeginFrameSeconds; | |
| 286 } | |
| 287 | |
| 288 bool Scheduler::canRunIdleTask() const | |
| 289 { | |
| 290 ASSERT(isMainThread()); | |
| 291 return m_currentFrameCommitted | |
| 292 && !shouldYieldForHighPriorityWork() | |
| 293 && (m_estimatedNextBeginFrameSeconds > Platform::current()->monotonicall
yIncreasingTime()); | |
| 294 } | |
| 295 | |
| 296 Scheduler::SchedulerPolicy Scheduler::schedulerPolicy() const | |
| 297 { | |
| 298 ASSERT(isMainThread()); | |
| 299 // It's important not to miss the transition from normal to low latency mode
, otherwise we're likely to | |
| 300 // delay the processing of input tasks. Since that transition is triggered b
y a different thread, we | |
| 301 // need either a lock or a memory barrier, and the memory barrier is probabl
y cheaper. | |
| 302 return static_cast<SchedulerPolicy>(acquireLoad(&m_schedulerPolicy)); | |
| 303 } | |
| 304 | |
| 305 void Scheduler::enterSchedulerPolicy(SchedulerPolicy schedulerPolicy) | |
| 306 { | |
| 307 Locker<Mutex> lock(m_policyStateMutex); | |
| 308 enterSchedulerPolicyLocked(schedulerPolicy); | |
| 309 } | |
| 310 | |
| 311 void Scheduler::enterSchedulerPolicyLocked(SchedulerPolicy schedulerPolicy) | |
| 312 { | |
| 313 ASSERT(m_policyStateMutex.locked()); | |
| 314 if (schedulerPolicy == CompositorPriority) | |
| 315 m_compositorPriorityPolicyEndTimeSeconds = Platform::current()->monotoni
callyIncreasingTime() + kLowSchedulerPolicyAfterTouchTimeSeconds; | |
| 316 | |
| 317 releaseStore(&m_schedulerPolicy, schedulerPolicy); | |
| 318 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), "SchedulerPolic
y", schedulerPolicy); | |
| 319 } | 71 } |
| 320 | 72 |
| 321 } // namespace blink | 73 } // namespace blink |
| OLD | NEW |