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 |