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/Task.h" | 9 #include "platform/Task.h" |
10 #include "platform/ThreadTimers.h" | 10 #include "platform/ThreadTimers.h" |
11 #include "platform/TraceEvent.h" | 11 #include "platform/TraceEvent.h" |
12 #include "public/platform/Platform.h" | 12 #include "public/platform/Platform.h" |
13 #include "wtf/MainThread.h" | 13 #include "wtf/MainThread.h" |
14 #include "wtf/ThreadingPrimitives.h" | 14 #include "wtf/ThreadingPrimitives.h" |
15 | 15 |
16 | 16 |
17 namespace blink { | 17 namespace blink { |
18 | 18 |
19 double Scheduler::s_lowLatencyModeAfterTouchTimeSeconds = 0.1; | |
20 | |
19 namespace { | 21 namespace { |
20 | 22 |
21 // Can be created from any thread. | 23 // Can be created from any thread. |
22 // Note if the scheduler gets shutdown, this may be run after. | 24 // Note if the scheduler gets shutdown, this may be run after. |
23 class MainThreadIdleTaskAdapter : public WebThread::Task { | 25 class MainThreadIdleTaskAdapter : public WebThread::Task { |
24 public: | 26 public: |
25 MainThreadIdleTaskAdapter(const Scheduler::IdleTask& idleTask, double allott edTimeMs, const TraceLocation& location) | 27 MainThreadIdleTaskAdapter(const Scheduler::IdleTask& idleTask, double allott edTimeMs, const TraceLocation& location) |
26 : m_idleTask(idleTask) | 28 : m_idleTask(idleTask) |
27 , m_allottedTimeMs(allottedTimeMs) | 29 , m_allottedTimeMs(allottedTimeMs) |
28 , m_location(location) | 30 , m_location(location) |
(...skipping 27 matching lines...) Expand all Loading... | |
56 } | 58 } |
57 | 59 |
58 // WebThread::Task implementation. | 60 // WebThread::Task implementation. |
59 virtual void run() OVERRIDE | 61 virtual void run() OVERRIDE |
60 { | 62 { |
61 Scheduler* scheduler = Scheduler::shared(); | 63 Scheduler* scheduler = Scheduler::shared(); |
62 // FIXME: This check should't be necessary, tasks should not outlive bli nk. | 64 // FIXME: This check should't be necessary, tasks should not outlive bli nk. |
63 ASSERT(scheduler); | 65 ASSERT(scheduler); |
64 if (!scheduler) | 66 if (!scheduler) |
65 return; | 67 return; |
68 // NOTE if we're not in low latency mode, this is the only place they wi ll actually get executed. | |
Sami
2014/09/10 16:00:38
nit: reword? (it's not clear what |they| is referr
alexclarke
2014/09/10 17:35:36
Done.
| |
66 scheduler->swapQueuesRunPendingTasksAndAllowHighPriorityTaskRunnerPostin g(); | 69 scheduler->swapQueuesRunPendingTasksAndAllowHighPriorityTaskRunnerPostin g(); |
67 } | 70 } |
68 }; | 71 }; |
69 | 72 |
70 | 73 |
71 // Can be created from any thread. | 74 // Can be created from any thread. |
72 // Note if the scheduler gets shutdown, this may be run after. | 75 // Note if the scheduler gets shutdown, this may be run after. |
73 class Scheduler::MainThreadPendingTaskRunner : public WebThread::Task { | 76 class Scheduler::MainThreadPendingTaskRunner : public WebThread::Task { |
74 public: | 77 public: |
75 MainThreadPendingTaskRunner( | 78 MainThreadPendingTaskRunner( |
76 const Scheduler::Task& task, const TraceLocation& location) | 79 const Scheduler::Task& task, const TraceLocation& location) |
77 : m_task(task, location) | 80 : m_task(task, location) |
78 { | 81 { |
79 ASSERT(Scheduler::shared()); | 82 ASSERT(Scheduler::shared()); |
80 } | 83 } |
81 | 84 |
82 // WebThread::Task implementation. | 85 // WebThread::Task implementation. |
83 virtual void run() OVERRIDE | 86 virtual void run() OVERRIDE |
84 { | 87 { |
85 Scheduler* scheduler = Scheduler::shared(); | 88 Scheduler* scheduler = Scheduler::shared(); |
86 // FIXME: This check should't be necessary, tasks should not outlive bli nk. | 89 // FIXME: This check should't be necessary, tasks should not outlive bli nk. |
87 ASSERT(scheduler); | 90 ASSERT(scheduler); |
88 if (scheduler) | 91 if (scheduler) |
89 Scheduler::shared()->swapQueuesAndRunPendingTasks(); | 92 Scheduler::shared()->runPendingHighPrioirtyTasksIfInLowLatencyMode() ; |
90 m_task.run(); | 93 m_task.run(); |
91 } | 94 } |
92 | 95 |
93 Scheduler::TracedTask m_task; | 96 Scheduler::TracedTask m_task; |
94 }; | 97 }; |
95 | 98 |
96 Scheduler* Scheduler::s_sharedScheduler = nullptr; | 99 Scheduler* Scheduler::s_sharedScheduler = nullptr; |
97 | 100 |
98 void Scheduler::initializeOnMainThread() | 101 void Scheduler::initializeOnMainThread() |
99 { | 102 { |
100 s_sharedScheduler = new Scheduler(); | 103 s_sharedScheduler = new Scheduler(); |
101 } | 104 } |
102 | 105 |
103 void Scheduler::shutdown() | 106 void Scheduler::shutdown() |
104 { | 107 { |
105 delete s_sharedScheduler; | 108 delete s_sharedScheduler; |
106 s_sharedScheduler = nullptr; | 109 s_sharedScheduler = nullptr; |
107 } | 110 } |
108 | 111 |
109 Scheduler* Scheduler::shared() | 112 Scheduler* Scheduler::shared() |
110 { | 113 { |
111 return s_sharedScheduler; | 114 return s_sharedScheduler; |
112 } | 115 } |
113 | 116 |
114 Scheduler::Scheduler() | 117 Scheduler::Scheduler() |
115 : m_sharedTimerFunction(nullptr) | 118 : m_sharedTimerFunction(nullptr) |
116 , m_mainThread(blink::Platform::current()->currentThread()) | 119 , m_mainThread(blink::Platform::current()->currentThread()) |
117 , m_highPriorityTaskCount(0) | 120 , m_highPriorityTaskCount(0) |
118 , m_highPriorityTaskRunnerPosted(false) | 121 , m_highPriorityTaskRunnerPosted(false) |
122 , m_latencyMode(Normal) | |
123 , m_lowLatencyModeEndTimeSeconds(0) | |
119 { | 124 { |
120 } | 125 } |
121 | 126 |
122 Scheduler::~Scheduler() | 127 Scheduler::~Scheduler() |
123 { | 128 { |
124 while (hasPendingHighPriorityWork()) { | 129 while (hasPendingHighPriorityWork()) { |
125 swapQueuesAndRunPendingTasks(); | 130 swapQueuesAndRunPendingTasks(); |
126 } | 131 } |
127 } | 132 } |
128 | 133 |
(...skipping 14 matching lines...) Expand all Loading... | |
143 } | 148 } |
144 | 149 |
145 void Scheduler::postTask(const TraceLocation& location, const Task& task) | 150 void Scheduler::postTask(const TraceLocation& location, const Task& task) |
146 { | 151 { |
147 m_mainThread->postTask(new MainThreadPendingTaskRunner(task, location)); | 152 m_mainThread->postTask(new MainThreadPendingTaskRunner(task, location)); |
148 } | 153 } |
149 | 154 |
150 void Scheduler::postInputTask(const TraceLocation& location, const Task& task) | 155 void Scheduler::postInputTask(const TraceLocation& location, const Task& task) |
151 { | 156 { |
152 Locker<Mutex> lock(m_pendingTasksMutex); | 157 Locker<Mutex> lock(m_pendingTasksMutex); |
158 setLatencyMode(LowLatency); | |
Sami
2014/09/10 16:00:38
Could you leave out this call so we'll only do thi
alexclarke
2014/09/10 17:35:36
Done.
| |
153 m_pendingHighPriorityTasks.append(TracedTask(task, location)); | 159 m_pendingHighPriorityTasks.append(TracedTask(task, location)); |
154 atomicIncrement(&m_highPriorityTaskCount); | 160 atomicIncrement(&m_highPriorityTaskCount); |
155 maybePostMainThreadPendingHighPriorityTaskRunner(); | 161 maybePostMainThreadPendingHighPriorityTaskRunner(); |
162 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), "PendingHighPri orityTasks", m_highPriorityTaskCount); | |
156 } | 163 } |
157 | 164 |
158 void Scheduler::postCompositorTask(const TraceLocation& location, const Task& ta sk) | 165 void Scheduler::postCompositorTask(const TraceLocation& location, const Task& ta sk) |
159 { | 166 { |
160 Locker<Mutex> lock(m_pendingTasksMutex); | 167 Locker<Mutex> lock(m_pendingTasksMutex); |
161 m_pendingHighPriorityTasks.append(TracedTask(task, location)); | 168 m_pendingHighPriorityTasks.append(TracedTask(task, location)); |
162 atomicIncrement(&m_highPriorityTaskCount); | 169 atomicIncrement(&m_highPriorityTaskCount); |
163 maybePostMainThreadPendingHighPriorityTaskRunner(); | 170 maybePostMainThreadPendingHighPriorityTaskRunner(); |
171 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), "PendingHighPri orityTasks", m_highPriorityTaskCount); | |
164 } | 172 } |
165 | 173 |
166 void Scheduler::maybePostMainThreadPendingHighPriorityTaskRunner() | 174 void Scheduler::maybePostMainThreadPendingHighPriorityTaskRunner() |
167 { | 175 { |
168 ASSERT(m_pendingTasksMutex.locked()); | 176 ASSERT(m_pendingTasksMutex.locked()); |
169 if (m_highPriorityTaskRunnerPosted) | 177 if (m_highPriorityTaskRunnerPosted) |
170 return; | 178 return; |
171 m_mainThread->postTask(new MainThreadPendingHighPriorityTaskRunner()); | 179 m_mainThread->postTask(new MainThreadPendingHighPriorityTaskRunner()); |
172 m_highPriorityTaskRunnerPosted = true; | 180 m_highPriorityTaskRunnerPosted = true; |
173 } | 181 } |
174 | 182 |
175 void Scheduler::postIdleTask(const TraceLocation& location, const IdleTask& idle Task) | 183 void Scheduler::postIdleTask(const TraceLocation& location, const IdleTask& idle Task) |
176 { | 184 { |
177 scheduleIdleTask(location, idleTask); | 185 scheduleIdleTask(location, idleTask); |
178 } | 186 } |
179 | 187 |
180 void Scheduler::tickSharedTimer() | 188 void Scheduler::tickSharedTimer() |
181 { | 189 { |
182 TRACE_EVENT0("blink", "Scheduler::tickSharedTimer"); | 190 TRACE_EVENT0("blink", "Scheduler::tickSharedTimer"); |
183 | 191 |
184 // Run any high priority tasks that are queued up, otherwise the blink timer s will yield immediately. | 192 // Run any high priority tasks that are queued up, otherwise the blink timer s will yield immediately. |
185 bool workDone = swapQueuesAndRunPendingTasks(); | 193 bool workDone = runPendingHighPrioirtyTasksIfInLowLatencyMode(); |
186 m_sharedTimerFunction(); | 194 m_sharedTimerFunction(); |
187 | 195 |
188 // The blink timers may have just yielded, so run any high priority tasks th at where queued up | 196 // The blink timers may have just yielded, so run any high priority tasks th at where queued up |
189 // while the blink timers were executing. | 197 // while the blink timers were executing. |
190 if (!workDone) | 198 if (!workDone) |
191 swapQueuesAndRunPendingTasks(); | 199 runPendingHighPrioirtyTasksIfInLowLatencyMode(); |
200 } | |
201 | |
202 bool Scheduler::runPendingHighPrioirtyTasksIfInLowLatencyMode() | |
203 { | |
204 if (latencyMode() != LowLatency) | |
Sami
2014/09/10 16:00:38
ASSERT(isMainThread());
alexclarke
2014/09/10 17:35:37
Done.
| |
205 return false; | |
206 | |
207 return swapQueuesAndRunPendingTasks(); | |
192 } | 208 } |
193 | 209 |
194 bool Scheduler::swapQueuesAndRunPendingTasks() | 210 bool Scheduler::swapQueuesAndRunPendingTasks() |
195 { | 211 { |
196 ASSERT(isMainThread()); | 212 ASSERT(isMainThread()); |
197 | 213 |
198 // These locks guard against another thread posting input or compositor task s while we swap the buffers. | 214 // These locks guard against another thread posting input or compositor task s while we swap the buffers. |
199 // One the buffers have been swapped we can safely access the returned deque without having to lock. | 215 // One the buffers have been swapped we can safely access the returned deque without having to lock. |
200 m_pendingTasksMutex.lock(); | 216 m_pendingTasksMutex.lock(); |
201 Deque<TracedTask>& highPriorityTasks = m_pendingHighPriorityTasks.swapBuffer s(); | 217 Deque<TracedTask>& highPriorityTasks = m_pendingHighPriorityTasks.swapBuffer s(); |
(...skipping 18 matching lines...) Expand all Loading... | |
220 { | 236 { |
221 TRACE_EVENT0("blink", "Scheduler::executeHighPriorityTasks"); | 237 TRACE_EVENT0("blink", "Scheduler::executeHighPriorityTasks"); |
222 int highPriorityTasksExecuted = 0; | 238 int highPriorityTasksExecuted = 0; |
223 while (!highPriorityTasks.isEmpty()) { | 239 while (!highPriorityTasks.isEmpty()) { |
224 highPriorityTasks.takeFirst().run(); | 240 highPriorityTasks.takeFirst().run(); |
225 highPriorityTasksExecuted++; | 241 highPriorityTasksExecuted++; |
226 } | 242 } |
227 | 243 |
228 int highPriorityTaskCount = atomicSubtract(&m_highPriorityTaskCount, highPri orityTasksExecuted); | 244 int highPriorityTaskCount = atomicSubtract(&m_highPriorityTaskCount, highPri orityTasksExecuted); |
229 ASSERT_UNUSED(highPriorityTaskCount, highPriorityTaskCount >= 0); | 245 ASSERT_UNUSED(highPriorityTaskCount, highPriorityTaskCount >= 0); |
246 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), "PendingHighPri orityTasks", m_highPriorityTaskCount); | |
247 | |
248 // Go back to normal latency mode if enough time has elapsed. | |
249 if (latencyMode() == LowLatency && Platform::current()->monotonicallyIncreas ingTime() > m_lowLatencyModeEndTimeSeconds) | |
250 setLatencyMode(Normal); | |
230 return highPriorityTasksExecuted > 0; | 251 return highPriorityTasksExecuted > 0; |
231 } | 252 } |
232 | 253 |
233 void Scheduler::sharedTimerAdapter() | 254 void Scheduler::sharedTimerAdapter() |
234 { | 255 { |
235 shared()->tickSharedTimer(); | 256 shared()->tickSharedTimer(); |
236 } | 257 } |
237 | 258 |
238 void Scheduler::setSharedTimerFiredFunction(void (*function)()) | 259 void Scheduler::setSharedTimerFiredFunction(void (*function)()) |
239 { | 260 { |
240 m_sharedTimerFunction = function; | 261 m_sharedTimerFunction = function; |
241 blink::Platform::current()->setSharedTimerFiredFunction(function ? &Schedule r::sharedTimerAdapter : nullptr); | 262 blink::Platform::current()->setSharedTimerFiredFunction(function ? &Schedule r::sharedTimerAdapter : nullptr); |
242 } | 263 } |
243 | 264 |
244 void Scheduler::setSharedTimerFireInterval(double interval) | 265 void Scheduler::setSharedTimerFireInterval(double interval) |
245 { | 266 { |
246 blink::Platform::current()->setSharedTimerFireInterval(interval); | 267 blink::Platform::current()->setSharedTimerFireInterval(interval); |
247 } | 268 } |
248 | 269 |
249 void Scheduler::stopSharedTimer() | 270 void Scheduler::stopSharedTimer() |
250 { | 271 { |
251 blink::Platform::current()->stopSharedTimer(); | 272 blink::Platform::current()->stopSharedTimer(); |
252 } | 273 } |
253 | 274 |
254 bool Scheduler::shouldYieldForHighPriorityWork() const | 275 bool Scheduler::shouldYieldForHighPriorityWork() const |
255 { | 276 { |
277 if (latencyMode() == Normal) | |
278 return false; | |
279 | |
256 return hasPendingHighPriorityWork(); | 280 return hasPendingHighPriorityWork(); |
257 } | 281 } |
258 | 282 |
259 bool Scheduler::hasPendingHighPriorityWork() const | 283 bool Scheduler::hasPendingHighPriorityWork() const |
260 { | 284 { |
261 // This method is expected to be run on the main thread, but the high priori ty tasks will be posted by | 285 // This method is expected to be run on the main thread, but the high priori ty tasks will be posted by |
262 // other threads. We could use locks here, but this function is (sometimes) called a lot by | 286 // other threads. We could use locks here, but this function is (sometimes) called a lot by |
263 // ThreadTimers::sharedTimerFiredInternal so we decided to use atomics + bar rier loads here which | 287 // ThreadTimers::sharedTimerFiredInternal so we decided to use atomics + bar rier loads here which |
264 // should be cheaper. | 288 // should be cheaper. |
265 // NOTE it's possible the barrier read is overkill here, since delayed yield ing isn't a big deal. | 289 // NOTE it's possible the barrier read is overkill here, since delayed yield ing isn't a big deal. |
266 return acquireLoad(&m_highPriorityTaskCount) != 0; | 290 return acquireLoad(&m_highPriorityTaskCount) != 0; |
267 } | 291 } |
268 | 292 |
293 Scheduler::LatencyMode Scheduler::latencyMode() const | |
294 { | |
295 ASSERT(isMainThread()); | |
296 return static_cast<LatencyMode>(acquireLoad(&m_latencyMode)); | |
297 } | |
298 | |
299 void Scheduler::setLatencyMode(LatencyMode latencyMode) | |
300 { | |
301 if (latencyMode == LowLatency) | |
302 m_lowLatencyModeEndTimeSeconds = Platform::current()->monotonicallyIncre asingTime() + s_lowLatencyModeAfterTouchTimeSeconds; | |
303 | |
304 releaseStore(&m_latencyMode, latencyMode); | |
305 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), "LatencyMode", latencyMode); | |
306 } | |
307 | |
269 void Scheduler::TracedTask::run() | 308 void Scheduler::TracedTask::run() |
270 { | 309 { |
271 TRACE_EVENT2("blink", "TracedTask::run", | 310 TRACE_EVENT2("blink", "TracedTask::run", |
272 "src_file", m_location.fileName(), | 311 "src_file", m_location.fileName(), |
273 "src_func", m_location.functionName()); | 312 "src_func", m_location.functionName()); |
274 m_task(); | 313 m_task(); |
275 } | 314 } |
276 | 315 |
277 } // namespace blink | 316 } // namespace blink |
OLD | NEW |