Chromium Code Reviews| 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(); | 87 Scheduler* scheduler = Scheduler::shared(); |
| 91 if (Scheduler* scheduler = Scheduler::shared()) { | 88 // FIXME: This check shouldn't be necessary, tasks should not outlive bl ink. |
|
Sami
2014/10/07 14:17:34
I don't think this comment is accurate any longer.
rmcilroy
2014/10/07 15:37:51
Done.
| |
| 92 scheduler->updatePolicy(); | 89 ASSERT(scheduler); |
| 90 if (scheduler) { | |
| 91 scheduler->maybeRunPendingIdleTask(); | |
| 92 // If possible, run the next idle task by reposting on the main thre ad. | |
| 93 scheduler->maybePostMainThreadPendingIdleTask(); | |
| 93 } | 94 } |
| 94 } | 95 } |
| 95 | 96 |
| 96 TracedTask m_task; | |
| 97 }; | 97 }; |
| 98 | 98 |
| 99 | |
| 99 Scheduler* Scheduler::s_sharedScheduler = nullptr; | 100 Scheduler* Scheduler::s_sharedScheduler = nullptr; |
| 100 | 101 |
| 101 void Scheduler::initializeOnMainThread() | 102 void Scheduler::initializeOnMainThread() |
| 102 { | 103 { |
| 103 s_sharedScheduler = new Scheduler(); | 104 s_sharedScheduler = new Scheduler(); |
| 104 } | 105 } |
| 105 | 106 |
| 106 void Scheduler::shutdown() | 107 void Scheduler::shutdown() |
| 107 { | 108 { |
| 108 delete s_sharedScheduler; | 109 delete s_sharedScheduler; |
| 109 s_sharedScheduler = nullptr; | 110 s_sharedScheduler = nullptr; |
| 110 } | 111 } |
| 111 | 112 |
| 112 Scheduler* Scheduler::shared() | 113 Scheduler* Scheduler::shared() |
| 113 { | 114 { |
| 114 return s_sharedScheduler; | 115 return s_sharedScheduler; |
| 115 } | 116 } |
| 116 | 117 |
| 117 Scheduler::Scheduler() | 118 Scheduler::Scheduler() |
| 118 : m_sharedTimerFunction(nullptr) | 119 : m_sharedTimerFunction(nullptr) |
| 119 , m_mainThread(blink::Platform::current()->currentThread()) | 120 , m_mainThread(blink::Platform::current()->currentThread()) |
| 121 , m_estimatedNextBeginFrameSeconds(0) | |
| 120 , m_highPriorityTaskCount(0) | 122 , m_highPriorityTaskCount(0) |
| 121 , m_highPriorityTaskRunnerPosted(false) | 123 , m_highPriorityTaskRunnerPosted(false) |
| 122 , m_compositorPriorityPolicyEndTimeSeconds(0) | 124 , m_compositorPriorityPolicyEndTimeSeconds(0) |
| 123 , m_schedulerPolicy(Normal) | 125 , m_schedulerPolicy(Normal) |
| 124 { | 126 { |
| 125 } | 127 } |
| 126 | 128 |
| 127 Scheduler::~Scheduler() | 129 Scheduler::~Scheduler() |
| 128 { | 130 { |
| 129 } | 131 } |
| 130 | 132 |
| 131 void Scheduler::willBeginFrame(const WebBeginFrameArgs& args) | 133 void Scheduler::willBeginFrame(double estimatedNextBeginFrameSeconds) |
| 132 { | 134 { |
| 133 // TODO: Use frame deadline and interval to schedule idle tasks. | 135 ASSERT(isMainThread()); |
| 136 m_currentFrameCommitted = false; | |
| 137 m_estimatedNextBeginFrameSeconds = estimatedNextBeginFrameSeconds; | |
| 138 // TODO: Schedule a deferred task here to run idle work if didCommitFrameToC ompositor never gets called. | |
| 134 } | 139 } |
| 135 | 140 |
| 136 void Scheduler::didCommitFrameToCompositor() | 141 void Scheduler::didCommitFrameToCompositor() |
| 137 { | 142 { |
| 138 // TODO: Trigger the frame deadline immediately. | 143 ASSERT(isMainThread()); |
| 139 } | 144 m_currentFrameCommitted = true; |
| 140 | 145 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 } | 146 } |
| 146 | 147 |
| 147 void Scheduler::postHighPriorityTaskInternal(const TraceLocation& location, cons t Task& task, const char* traceName) | 148 void Scheduler::postHighPriorityTaskInternal(const TraceLocation& location, cons t Task& task, const char* traceName) |
| 148 { | 149 { |
| 149 m_mainThread->postTask(new MainThreadPendingHighPriorityTaskRunner(task, loc ation, traceName)); | 150 m_mainThread->postTask(new MainThreadPendingHighPriorityTaskRunner(task, loc ation, traceName)); |
| 150 atomicIncrement(&m_highPriorityTaskCount); | 151 atomicIncrement(&m_highPriorityTaskCount); |
| 151 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), "PendingHighPri orityTasks", m_highPriorityTaskCount); | 152 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), "PendingHighPri orityTasks", m_highPriorityTaskCount); |
| 152 } | 153 } |
| 153 | 154 |
| 154 void Scheduler::didRunHighPriorityTask() | 155 void Scheduler::didRunHighPriorityTask() |
| 155 { | 156 { |
| 156 atomicDecrement(&m_highPriorityTaskCount); | 157 atomicDecrement(&m_highPriorityTaskCount); |
| 157 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), "PendingHighPri orityTasks", m_highPriorityTaskCount); | 158 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), "PendingHighPri orityTasks", m_highPriorityTaskCount); |
| 158 } | 159 } |
| 159 | 160 |
| 161 void Scheduler::postIdleTaskInternal(const TraceLocation& location, const IdleTa sk& idleTask, const char* traceName) | |
| 162 { | |
| 163 Locker<Mutex> lock(m_pendingIdleTasksMutex); | |
| 164 m_pendingIdleTasks.append(internal::TracedIdleTask::Create(idleTask, locatio n, traceName)); | |
| 165 } | |
| 166 | |
| 160 void Scheduler::postTask(const TraceLocation& location, const Task& task) | 167 void Scheduler::postTask(const TraceLocation& location, const Task& task) |
| 161 { | 168 { |
| 162 m_mainThread->postTask(new MainThreadPendingTaskRunner(task, location, "Sche duler::MainThreadTask")); | 169 m_mainThread->postTask(new MainThreadPendingTaskRunner(task, location, "Sche duler::MainThreadTask")); |
| 163 } | 170 } |
| 164 | 171 |
| 165 void Scheduler::postInputTask(const TraceLocation& location, const Task& task) | 172 void Scheduler::postInputTask(const TraceLocation& location, const Task& task) |
| 166 { | 173 { |
| 167 postHighPriorityTaskInternal(location, task, "Scheduler::InputTask"); | 174 postHighPriorityTaskInternal(location, task, "Scheduler::InputTask"); |
| 168 } | 175 } |
| 169 | 176 |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 181 | 188 |
| 182 void Scheduler::postIpcTask(const TraceLocation& location, const Task& task) | 189 void Scheduler::postIpcTask(const TraceLocation& location, const Task& task) |
| 183 { | 190 { |
| 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 | 191 // 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. | 192 // 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")); | 193 m_mainThread->postTask(new MainThreadPendingTaskRunner(task, location, "Sche duler::IpcTask")); |
| 187 } | 194 } |
| 188 | 195 |
| 189 void Scheduler::postIdleTask(const TraceLocation& location, const IdleTask& idle Task) | 196 void Scheduler::postIdleTask(const TraceLocation& location, const IdleTask& idle Task) |
| 190 { | 197 { |
| 191 scheduleIdleTask(location, idleTask); | 198 postIdleTaskInternal(location, idleTask, "Scheduler::IdleTask"); |
| 199 } | |
| 200 | |
| 201 bool Scheduler::maybePostMainThreadPendingIdleTask() | |
| 202 { | |
| 203 ASSERT(isMainThread()); | |
| 204 TRACE_EVENT0("blink", "Scheduler::maybePostMainThreadPendingIdleTask"); | |
| 205 if (canRunIdleTask()) { | |
| 206 Locker<Mutex> lock(m_pendingIdleTasksMutex); | |
| 207 if (!m_pendingIdleTasks.isEmpty()) { | |
| 208 m_mainThread->postTask(new MainThreadPendingIdleTaskRunner()); | |
| 209 return true; | |
| 210 } | |
| 211 } | |
| 212 return false; | |
| 192 } | 213 } |
| 193 | 214 |
| 194 void Scheduler::tickSharedTimer() | 215 void Scheduler::tickSharedTimer() |
| 195 { | 216 { |
| 196 TRACE_EVENT0("blink", "Scheduler::tickSharedTimer"); | 217 TRACE_EVENT0("blink", "Scheduler::tickSharedTimer"); |
| 197 m_sharedTimerFunction(); | 218 m_sharedTimerFunction(); |
| 198 } | 219 } |
| 199 | 220 |
| 200 void Scheduler::updatePolicy() | 221 void Scheduler::updatePolicy() |
| 201 { | 222 { |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 235 return false; | 256 return false; |
| 236 | 257 |
| 237 // This method is expected to be run on the main thread, but the high priori ty tasks will be posted by | 258 // 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 | 259 // 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 | 260 // ThreadTimers::sharedTimerFiredInternal so we decided to use atomics + bar rier loads here which |
| 240 // should be cheaper. | 261 // should be cheaper. |
| 241 // NOTE it's possible the barrier read is overkill here, since delayed yield ing isn't a big deal. | 262 // 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; | 263 return acquireLoad(&m_highPriorityTaskCount) != 0; |
| 243 } | 264 } |
| 244 | 265 |
| 266 bool Scheduler::maybeRunPendingIdleTask() | |
| 267 { | |
| 268 ASSERT(isMainThread()); | |
| 269 if (!canRunIdleTask()) | |
| 270 return false; | |
| 271 | |
| 272 takeFirstPendingIdleTask()->run(); | |
| 273 return true; | |
| 274 } | |
| 275 | |
| 276 PassOwnPtr<internal::TracedIdleTask> Scheduler::takeFirstPendingIdleTask() | |
| 277 { | |
| 278 Locker<Mutex> lock(m_pendingIdleTasksMutex); | |
| 279 ASSERT(!m_pendingIdleTasks.isEmpty()); | |
| 280 return m_pendingIdleTasks.takeFirst(); | |
| 281 } | |
| 282 | |
| 283 double Scheduler::currentFrameDeadlineForIdleTasks() const | |
| 284 { | |
| 285 ASSERT(isMainThread()); | |
| 286 // TODO: Make idle time more fine-grain chunks when in Compositor priority. | |
| 287 return m_estimatedNextBeginFrameSeconds; | |
| 288 } | |
| 289 | |
| 290 bool Scheduler::canRunIdleTask() const | |
| 291 { | |
| 292 ASSERT(isMainThread()); | |
| 293 return m_currentFrameCommitted | |
| 294 && !shouldYieldForHighPriorityWork() | |
| 295 && (m_estimatedNextBeginFrameSeconds > Platform::current()->monotonicall yIncreasingTime()); | |
| 296 } | |
| 297 | |
| 245 Scheduler::SchedulerPolicy Scheduler::schedulerPolicy() const | 298 Scheduler::SchedulerPolicy Scheduler::schedulerPolicy() const |
| 246 { | 299 { |
| 247 ASSERT(isMainThread()); | 300 ASSERT(isMainThread()); |
| 248 // It's important not to miss the transition from normal to low latency mode , otherwise we're likely to | 301 // 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 | 302 // 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. | 303 // need either a lock or a memory barrier, and the memory barrier is probabl y cheaper. |
| 251 return static_cast<SchedulerPolicy>(acquireLoad(&m_schedulerPolicy)); | 304 return static_cast<SchedulerPolicy>(acquireLoad(&m_schedulerPolicy)); |
| 252 } | 305 } |
| 253 | 306 |
| 254 void Scheduler::enterSchedulerPolicy(SchedulerPolicy schedulerPolicy) | 307 void Scheduler::enterSchedulerPolicy(SchedulerPolicy schedulerPolicy) |
| 255 { | 308 { |
| 256 Locker<Mutex> lock(m_policyStateMutex); | 309 Locker<Mutex> lock(m_policyStateMutex); |
| 257 enterSchedulerPolicyLocked(schedulerPolicy); | 310 enterSchedulerPolicyLocked(schedulerPolicy); |
| 258 } | 311 } |
| 259 | 312 |
| 260 void Scheduler::enterSchedulerPolicyLocked(SchedulerPolicy schedulerPolicy) | 313 void Scheduler::enterSchedulerPolicyLocked(SchedulerPolicy schedulerPolicy) |
| 261 { | 314 { |
| 262 ASSERT(m_policyStateMutex.locked()); | 315 ASSERT(m_policyStateMutex.locked()); |
| 263 if (schedulerPolicy == CompositorPriority) | 316 if (schedulerPolicy == CompositorPriority) |
| 264 m_compositorPriorityPolicyEndTimeSeconds = Platform::current()->monotoni callyIncreasingTime() + kLowSchedulerPolicyAfterTouchTimeSeconds; | 317 m_compositorPriorityPolicyEndTimeSeconds = Platform::current()->monotoni callyIncreasingTime() + kLowSchedulerPolicyAfterTouchTimeSeconds; |
| 265 | 318 |
| 266 releaseStore(&m_schedulerPolicy, schedulerPolicy); | 319 releaseStore(&m_schedulerPolicy, schedulerPolicy); |
| 267 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), "SchedulerPolic y", schedulerPolicy); | 320 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), "SchedulerPolic y", schedulerPolicy); |
| 268 } | 321 } |
| 269 | 322 |
| 270 } // namespace blink | 323 } // namespace blink |
| OLD | NEW |