Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(154)

Side by Side Diff: Source/platform/scheduler/Scheduler.cpp

Issue 621363002: scheduler: Post high priority tasks directly to the message loop (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Test tweak. Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « Source/platform/scheduler/Scheduler.h ('k') | Source/platform/scheduler/SchedulerTest.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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"
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
44 double m_allottedTimeMs; 44 double m_allottedTimeMs;
45 TraceLocation m_location; 45 TraceLocation m_location;
46 }; 46 };
47 47
48 } // namespace 48 } // namespace
49 49
50 // Typically only created from compositor or render threads. 50 // Typically only created from compositor or render threads.
51 // Note if the scheduler gets shutdown, this may be run after. 51 // Note if the scheduler gets shutdown, this may be run after.
52 class Scheduler::MainThreadPendingHighPriorityTaskRunner : public WebThread::Tas k { 52 class Scheduler::MainThreadPendingHighPriorityTaskRunner : public WebThread::Tas k {
53 public: 53 public:
54 MainThreadPendingHighPriorityTaskRunner() 54 MainThreadPendingHighPriorityTaskRunner(
55 const Scheduler::Task& task, const TraceLocation& location, const char* traceName)
56 : m_task(task, location, traceName)
55 { 57 {
56 ASSERT(Scheduler::shared()); 58 ASSERT(Scheduler::shared());
57 } 59 }
58 60
59 // WebThread::Task implementation. 61 // WebThread::Task implementation.
60 virtual void run() OVERRIDE 62 virtual void run() OVERRIDE
61 { 63 {
62 Scheduler* scheduler = Scheduler::shared(); 64 m_task.run();
63 // FIXME: This check should't be necessary, tasks should not outlive bli nk. 65 if (Scheduler* scheduler = Scheduler::shared()) {
64 ASSERT(scheduler); 66 scheduler->updatePolicy();
65 if (!scheduler) 67 scheduler->didRunHighPriorityTask();
66 return; 68 }
67 // NOTE we must unconditionally execute high priority tasks here, since if we're not in CompositorPriority
68 // mode, then this is the only place where high priority tasks will be e xecuted.
69 scheduler->swapQueuesRunPendingTasksAndAllowHighPriorityTaskRunnerPostin g();
70 } 69 }
70
71 private:
72 TracedTask m_task;
71 }; 73 };
72 74
73
74 // Can be created from any thread. 75 // Can be created from any thread.
75 // Note if the scheduler gets shutdown, this may be run after. 76 // Note if the scheduler gets shutdown, this may be run after.
76 class Scheduler::MainThreadPendingTaskRunner : public WebThread::Task { 77 class Scheduler::MainThreadPendingTaskRunner : public WebThread::Task {
77 public: 78 public:
78 MainThreadPendingTaskRunner( 79 MainThreadPendingTaskRunner(
79 const Scheduler::Task& task, const TraceLocation& location, const char* traceName) 80 const Scheduler::Task& task, const TraceLocation& location, const char* traceName)
80 : m_task(task, location, traceName) 81 : m_task(task, location, traceName)
81 { 82 {
82 ASSERT(Scheduler::shared()); 83 ASSERT(Scheduler::shared());
83 } 84 }
84 85
85 // WebThread::Task implementation. 86 // WebThread::Task implementation.
86 virtual void run() OVERRIDE 87 virtual void run() OVERRIDE
87 { 88 {
88 Scheduler* scheduler = Scheduler::shared();
89 // FIXME: This check should't be necessary, tasks should not outlive bli nk.
90 ASSERT(scheduler);
91 if (scheduler)
92 Scheduler::shared()->runPendingHighPriorityTasksIfInCompositorPriori ty();
93 m_task.run(); 89 m_task.run();
90 if (Scheduler* scheduler = Scheduler::shared()) {
91 scheduler->updatePolicy();
92 }
94 } 93 }
95 94
96 TracedTask m_task; 95 TracedTask m_task;
97 }; 96 };
98 97
99 Scheduler* Scheduler::s_sharedScheduler = nullptr; 98 Scheduler* Scheduler::s_sharedScheduler = nullptr;
100 99
101 void Scheduler::initializeOnMainThread() 100 void Scheduler::initializeOnMainThread()
102 { 101 {
103 s_sharedScheduler = new Scheduler(); 102 s_sharedScheduler = new Scheduler();
104 } 103 }
105 104
106 void Scheduler::shutdown() 105 void Scheduler::shutdown()
107 { 106 {
108 delete s_sharedScheduler; 107 delete s_sharedScheduler;
109 s_sharedScheduler = nullptr; 108 s_sharedScheduler = nullptr;
110 } 109 }
111 110
112 Scheduler* Scheduler::shared() 111 Scheduler* Scheduler::shared()
113 { 112 {
114 return s_sharedScheduler; 113 return s_sharedScheduler;
115 } 114 }
116 115
117 Scheduler::Scheduler() 116 Scheduler::Scheduler()
118 : m_sharedTimerFunction(nullptr) 117 : m_sharedTimerFunction(nullptr)
119 , m_mainThread(blink::Platform::current()->currentThread()) 118 , m_mainThread(blink::Platform::current()->currentThread())
120 , m_compositorPriorityPolicyEndTimeSeconds(0)
121 , m_highPriorityTaskCount(0) 119 , m_highPriorityTaskCount(0)
122 , m_highPriorityTaskRunnerPosted(false) 120 , m_highPriorityTaskRunnerPosted(false)
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 while (hasPendingHighPriorityWork()) {
130 swapQueuesAndRunPendingTasks();
131 }
132 } 128 }
133 129
134 void Scheduler::willBeginFrame(const WebBeginFrameArgs& args) 130 void Scheduler::willBeginFrame(const WebBeginFrameArgs& args)
135 { 131 {
136 // TODO: Use frame deadline and interval to schedule idle tasks. 132 // TODO: Use frame deadline and interval to schedule idle tasks.
137 } 133 }
138 134
139 void Scheduler::didCommitFrameToCompositor() 135 void Scheduler::didCommitFrameToCompositor()
140 { 136 {
141 // TODO: Trigger the frame deadline immediately. 137 // TODO: Trigger the frame deadline immediately.
142 } 138 }
143 139
144 void Scheduler::scheduleIdleTask(const TraceLocation& location, const IdleTask& idleTask) 140 void Scheduler::scheduleIdleTask(const TraceLocation& location, const IdleTask& idleTask)
145 { 141 {
146 // TODO: send a real allottedTime here. 142 // TODO: send a real allottedTime here.
147 m_mainThread->postTask(new MainThreadIdleTaskAdapter(idleTask, 0, location)) ; 143 m_mainThread->postTask(new MainThreadIdleTaskAdapter(idleTask, 0, location)) ;
148 } 144 }
149 145
150 void Scheduler::postHighPriorityTaskInternal(const TraceLocation& location, cons t Task& task, const char* traceName) 146 void Scheduler::postHighPriorityTaskInternal(const TraceLocation& location, cons t Task& task, const char* traceName)
151 { 147 {
152 Locker<Mutex> lock(m_pendingTasksMutex); 148 m_mainThread->postTask(new MainThreadPendingHighPriorityTaskRunner(task, loc ation, traceName));
153
154 m_pendingHighPriorityTasks.append(TracedTask(task, location, traceName));
155 atomicIncrement(&m_highPriorityTaskCount); 149 atomicIncrement(&m_highPriorityTaskCount);
156 maybePostMainThreadPendingHighPriorityTaskRunner();
157 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), "PendingHighPri orityTasks", m_highPriorityTaskCount); 150 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), "PendingHighPri orityTasks", m_highPriorityTaskCount);
158 } 151 }
159 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
160 void Scheduler::postTask(const TraceLocation& location, const Task& task) 159 void Scheduler::postTask(const TraceLocation& location, const Task& task)
161 { 160 {
162 m_mainThread->postTask(new MainThreadPendingTaskRunner(task, location, "Sche duler::MainThreadTask")); 161 m_mainThread->postTask(new MainThreadPendingTaskRunner(task, location, "Sche duler::MainThreadTask"));
163 } 162 }
164 163
165 void Scheduler::postInputTask(const TraceLocation& location, const Task& task) 164 void Scheduler::postInputTask(const TraceLocation& location, const Task& task)
166 { 165 {
167 postHighPriorityTaskInternal(location, task, "Scheduler::InputTask"); 166 postHighPriorityTaskInternal(location, task, "Scheduler::InputTask");
168 } 167 }
169 168
170 void Scheduler::didReceiveInputEvent() 169 void Scheduler::didReceiveInputEvent()
171 { 170 {
172 enterSchedulerPolicy(CompositorPriority); 171 enterSchedulerPolicy(CompositorPriority);
173 } 172 }
174 173
175 void Scheduler::postCompositorTask(const TraceLocation& location, const Task& ta sk) 174 void Scheduler::postCompositorTask(const TraceLocation& location, const Task& ta sk)
176 { 175 {
177 postHighPriorityTaskInternal(location, task, "Scheduler::CompositorTask"); 176 postHighPriorityTaskInternal(location, task, "Scheduler::CompositorTask");
178 } 177 }
179 178
180 void Scheduler::postIpcTask(const TraceLocation& location, const Task& task) 179 void Scheduler::postIpcTask(const TraceLocation& location, const Task& task)
181 { 180 {
182 // 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 181 // 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
183 // time to process. These need refactoring but we need to add some infrastru cture to identify them. 182 // time to process. These need refactoring but we need to add some infrastru cture to identify them.
184 m_mainThread->postTask(new MainThreadPendingTaskRunner(task, location, "Sche duler::IpcTask")); 183 m_mainThread->postTask(new MainThreadPendingTaskRunner(task, location, "Sche duler::IpcTask"));
185 } 184 }
186 185
187 void Scheduler::maybePostMainThreadPendingHighPriorityTaskRunner()
188 {
189 ASSERT(m_pendingTasksMutex.locked());
190 if (m_highPriorityTaskRunnerPosted)
191 return;
192 m_mainThread->postTask(new MainThreadPendingHighPriorityTaskRunner());
193 m_highPriorityTaskRunnerPosted = true;
194 }
195
196 void Scheduler::postIdleTask(const TraceLocation& location, const IdleTask& idle Task) 186 void Scheduler::postIdleTask(const TraceLocation& location, const IdleTask& idle Task)
197 { 187 {
198 scheduleIdleTask(location, idleTask); 188 scheduleIdleTask(location, idleTask);
199 } 189 }
200 190
201 void Scheduler::tickSharedTimer() 191 void Scheduler::tickSharedTimer()
202 { 192 {
203 TRACE_EVENT0("blink", "Scheduler::tickSharedTimer"); 193 TRACE_EVENT0("blink", "Scheduler::tickSharedTimer");
204
205 // Run any high priority tasks that are queued up, otherwise the blink timer s will yield immediately.
206 bool workDone = runPendingHighPriorityTasksIfInCompositorPriority();
207 m_sharedTimerFunction(); 194 m_sharedTimerFunction();
208
209 // The blink timers may have just yielded, so run any high priority tasks th at where queued up
210 // while the blink timers were executing.
211 if (!workDone)
212 runPendingHighPriorityTasksIfInCompositorPriority();
213 } 195 }
214 196
215 bool Scheduler::runPendingHighPriorityTasksIfInCompositorPriority() 197 void Scheduler::updatePolicy()
216 { 198 {
217 ASSERT(isMainThread()); 199 ASSERT(isMainThread());
218 if (schedulerPolicy() != CompositorPriority) 200 Locker<Mutex> lock(m_policyStateMutex);
219 return false;
220
221 return swapQueuesAndRunPendingTasks();
222 }
223
224 bool Scheduler::swapQueuesAndRunPendingTasks()
225 {
226 ASSERT(isMainThread());
227
228 // These locks guard against another thread posting input or compositor task s while we swap the buffers.
229 // One the buffers have been swapped we can safely access the returned deque without having to lock.
230 m_pendingTasksMutex.lock();
231 Deque<TracedTask>& highPriorityTasks = m_pendingHighPriorityTasks.swapBuffer s();
232 maybeEnterNormalSchedulerPolicy();
233 m_pendingTasksMutex.unlock();
234 return executeHighPriorityTasks(highPriorityTasks);
235 }
236
237 void Scheduler::swapQueuesRunPendingTasksAndAllowHighPriorityTaskRunnerPosting()
238 {
239 ASSERT(isMainThread());
240
241 // These locks guard against another thread posting input or compositor task s while we swap the buffers.
242 // One the buffers have been swapped we can safely access the returned deque without having to lock.
243 m_pendingTasksMutex.lock();
244 Deque<TracedTask>& highPriorityTasks = m_pendingHighPriorityTasks.swapBuffer s();
245 m_highPriorityTaskRunnerPosted = false;
246 maybeEnterNormalSchedulerPolicy();
247 m_pendingTasksMutex.unlock();
248 executeHighPriorityTasks(highPriorityTasks);
249 }
250
251 void Scheduler::maybeEnterNormalSchedulerPolicy()
252 {
253 ASSERT(isMainThread());
254 ASSERT(m_pendingTasksMutex.locked());
255 201
256 // Go back to the normal scheduler policy if enough time has elapsed. 202 // Go back to the normal scheduler policy if enough time has elapsed.
257 if (schedulerPolicy() == CompositorPriority && Platform::current()->monotoni callyIncreasingTime() > m_compositorPriorityPolicyEndTimeSeconds) 203 if (schedulerPolicy() == CompositorPriority && Platform::current()->monotoni callyIncreasingTime() > m_compositorPriorityPolicyEndTimeSeconds)
258 enterSchedulerPolicyLocked(Normal); 204 enterSchedulerPolicyLocked(Normal);
259 } 205 }
260 206
261 bool Scheduler::executeHighPriorityTasks(Deque<TracedTask>& highPriorityTasks)
262 {
263 TRACE_EVENT0("blink", "Scheduler::executeHighPriorityTasks");
264 int highPriorityTasksExecuted = 0;
265 while (!highPriorityTasks.isEmpty()) {
266 highPriorityTasks.takeFirst().run();
267 highPriorityTasksExecuted++;
268 }
269
270 int highPriorityTaskCount = atomicSubtract(&m_highPriorityTaskCount, highPri orityTasksExecuted);
271 ASSERT_UNUSED(highPriorityTaskCount, highPriorityTaskCount >= 0);
272 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), "PendingHighPri orityTasks", m_highPriorityTaskCount);
273 return highPriorityTasksExecuted > 0;
274 }
275
276 void Scheduler::sharedTimerAdapter() 207 void Scheduler::sharedTimerAdapter()
277 { 208 {
278 shared()->tickSharedTimer(); 209 shared()->tickSharedTimer();
279 } 210 }
280 211
281 void Scheduler::setSharedTimerFiredFunction(void (*function)()) 212 void Scheduler::setSharedTimerFiredFunction(void (*function)())
282 { 213 {
283 m_sharedTimerFunction = function; 214 m_sharedTimerFunction = function;
284 blink::Platform::current()->setSharedTimerFiredFunction(function ? &Schedule r::sharedTimerAdapter : nullptr); 215 blink::Platform::current()->setSharedTimerFiredFunction(function ? &Schedule r::sharedTimerAdapter : nullptr);
285 } 216 }
286 217
287 void Scheduler::setSharedTimerFireInterval(double interval) 218 void Scheduler::setSharedTimerFireInterval(double interval)
288 { 219 {
289 blink::Platform::current()->setSharedTimerFireInterval(interval); 220 blink::Platform::current()->setSharedTimerFireInterval(interval);
290 } 221 }
291 222
292 void Scheduler::stopSharedTimer() 223 void Scheduler::stopSharedTimer()
293 { 224 {
294 blink::Platform::current()->stopSharedTimer(); 225 blink::Platform::current()->stopSharedTimer();
295 } 226 }
296 227
297 bool Scheduler::shouldYieldForHighPriorityWork() const 228 bool Scheduler::shouldYieldForHighPriorityWork() const
298 { 229 {
299 // It's only worthwhile yielding in CompositorPriority mode. 230 // It's only worthwhile yielding in CompositorPriority mode.
300 if (schedulerPolicy() != CompositorPriority) 231 if (schedulerPolicy() != CompositorPriority)
301 return false; 232 return false;
302 233
303 return hasPendingHighPriorityWork();
304 }
305
306 bool Scheduler::hasPendingHighPriorityWork() const
307 {
308 // This method is expected to be run on the main thread, but the high priori ty tasks will be posted by 234 // This method is expected to be run on the main thread, but the high priori ty tasks will be posted by
309 // other threads. We could use locks here, but this function is (sometimes) called a lot by 235 // other threads. We could use locks here, but this function is (sometimes) called a lot by
310 // ThreadTimers::sharedTimerFiredInternal so we decided to use atomics + bar rier loads here which 236 // ThreadTimers::sharedTimerFiredInternal so we decided to use atomics + bar rier loads here which
311 // should be cheaper. 237 // should be cheaper.
312 // NOTE it's possible the barrier read is overkill here, since delayed yield ing isn't a big deal. 238 // NOTE it's possible the barrier read is overkill here, since delayed yield ing isn't a big deal.
313 return acquireLoad(&m_highPriorityTaskCount) != 0; 239 return acquireLoad(&m_highPriorityTaskCount) != 0;
314 } 240 }
315 241
316 Scheduler::SchedulerPolicy Scheduler::schedulerPolicy() const 242 Scheduler::SchedulerPolicy Scheduler::schedulerPolicy() const
317 { 243 {
318 ASSERT(isMainThread()); 244 ASSERT(isMainThread());
319 // It's important not to miss the transition from normal to low latency mode , otherwise we're likely to 245 // It's important not to miss the transition from normal to low latency mode , otherwise we're likely to
320 // delay the processing of input tasks. Since that transition is triggered b y a different thread, we 246 // delay the processing of input tasks. Since that transition is triggered b y a different thread, we
321 // need either a lock or a memory barrier, and the memory barrier is probabl y cheaper. 247 // need either a lock or a memory barrier, and the memory barrier is probabl y cheaper.
322 return static_cast<SchedulerPolicy>(acquireLoad(&m_schedulerPolicy)); 248 return static_cast<SchedulerPolicy>(acquireLoad(&m_schedulerPolicy));
323 } 249 }
324 250
325 void Scheduler::enterSchedulerPolicy(SchedulerPolicy schedulerPolicy) 251 void Scheduler::enterSchedulerPolicy(SchedulerPolicy schedulerPolicy)
326 { 252 {
327 Locker<Mutex> lock(m_pendingTasksMutex); 253 Locker<Mutex> lock(m_policyStateMutex);
328 enterSchedulerPolicyLocked(schedulerPolicy); 254 enterSchedulerPolicyLocked(schedulerPolicy);
329 } 255 }
330 256
331 void Scheduler::enterSchedulerPolicyLocked(SchedulerPolicy schedulerPolicy) 257 void Scheduler::enterSchedulerPolicyLocked(SchedulerPolicy schedulerPolicy)
332 { 258 {
333 ASSERT(m_pendingTasksMutex.locked()); 259 ASSERT(m_policyStateMutex.locked());
334 if (schedulerPolicy == CompositorPriority) 260 if (schedulerPolicy == CompositorPriority)
335 m_compositorPriorityPolicyEndTimeSeconds = Platform::current()->monotoni callyIncreasingTime() + kLowSchedulerPolicyAfterTouchTimeSeconds; 261 m_compositorPriorityPolicyEndTimeSeconds = Platform::current()->monotoni callyIncreasingTime() + kLowSchedulerPolicyAfterTouchTimeSeconds;
336 262
337 releaseStore(&m_schedulerPolicy, schedulerPolicy); 263 releaseStore(&m_schedulerPolicy, schedulerPolicy);
338 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), "SchedulerPolic y", schedulerPolicy); 264 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), "SchedulerPolic y", schedulerPolicy);
339 } 265 }
340 266
341 } // namespace blink 267 } // namespace blink
OLDNEW
« no previous file with comments | « Source/platform/scheduler/Scheduler.h ('k') | Source/platform/scheduler/SchedulerTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698