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