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

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

Issue 540373002: Add support for Low Priorirty tasks. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Maybe fix linker issue Created 6 years, 3 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
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"
11 #include "platform/TraceEvent.h" 11 #include "platform/TraceEvent.h"
12 #include "public/platform/Platform.h" 12 #include "public/platform/Platform.h"
13 #include "public/platform/WebBeginFrameArgs.h"
13 #include "wtf/MainThread.h" 14 #include "wtf/MainThread.h"
14 #include "wtf/ThreadingPrimitives.h" 15 #include "wtf/ThreadingPrimitives.h"
15 16
16 17
17 namespace blink { 18 namespace blink {
18 19
20 // Pending low prioirty tasks have a maximum run time of 20ms per invocation of runPendingLowPriorityTasks.
21 const double Scheduler::s_maximumLowPrioirtyTaskExecutionTimeSeconds = 0.02;
22
19 namespace { 23 namespace {
20 24
21 // Can be created from any thread. 25 // Can be created from any thread.
22 // Note if the scheduler gets shutdown, this may be run after. 26 // Note if the scheduler gets shutdown, this may be run after.
23 class MainThreadIdleTaskAdapter : public WebThread::Task { 27 class MainThreadIdleTaskAdapter : public WebThread::Task {
24 public: 28 public:
25 MainThreadIdleTaskAdapter(const Scheduler::IdleTask& idleTask, double allott edTimeMs, const TraceLocation& location) 29 MainThreadIdleTaskAdapter(const Scheduler::IdleTask& idleTask, double allott edTimeMs, const TraceLocation& location)
26 : m_idleTask(idleTask) 30 : m_idleTask(idleTask)
27 , m_allottedTimeMs(allottedTimeMs) 31 , m_allottedTimeMs(allottedTimeMs)
28 , m_location(location) 32 , m_location(location)
(...skipping 27 matching lines...) Expand all
56 } 60 }
57 61
58 // WebThread::Task implementation. 62 // WebThread::Task implementation.
59 virtual void run() OVERRIDE 63 virtual void run() OVERRIDE
60 { 64 {
61 Scheduler* scheduler = Scheduler::shared(); 65 Scheduler* scheduler = Scheduler::shared();
62 // FIXME: This check should't be necessary, tasks should not outlive bli nk. 66 // FIXME: This check should't be necessary, tasks should not outlive bli nk.
63 ASSERT(scheduler); 67 ASSERT(scheduler);
64 if (!scheduler) 68 if (!scheduler)
65 return; 69 return;
66 scheduler->swapQueuesRunPendingTasksAndAllowHighPriorityTaskRunnerPostin g(); 70 scheduler->runPendingHighPriorityTasksAndAllowTaskRunnerPosting();
67 } 71 }
68 }; 72 };
69 73
70 74
71 // Can be created from any thread. 75 // Can be created from any thread.
72 // Note if the scheduler gets shutdown, this may be run after. 76 // Note if the scheduler gets shutdown, this may be run after.
73 class Scheduler::MainThreadPendingTaskRunner : public WebThread::Task { 77 class Scheduler::MainThreadPendingTaskRunner : public WebThread::Task {
74 public: 78 public:
75 MainThreadPendingTaskRunner( 79 MainThreadPendingTaskRunner(
76 const Scheduler::Task& task, const TraceLocation& location) 80 const Scheduler::Task& task, const TraceLocation& location)
77 : m_task(task, location) 81 : m_task(task, location)
78 { 82 {
79 ASSERT(Scheduler::shared()); 83 ASSERT(Scheduler::shared());
80 } 84 }
81 85
82 // WebThread::Task implementation. 86 // WebThread::Task implementation.
83 virtual void run() OVERRIDE 87 virtual void run() OVERRIDE
84 { 88 {
85 Scheduler* scheduler = Scheduler::shared(); 89 Scheduler* scheduler = Scheduler::shared();
86 // FIXME: This check should't be necessary, tasks should not outlive bli nk. 90 // FIXME: This check should't be necessary, tasks should not outlive bli nk.
87 ASSERT(scheduler); 91 ASSERT(scheduler);
88 if (scheduler) 92 if (scheduler)
89 Scheduler::shared()->swapQueuesAndRunPendingTasks(); 93 Scheduler::shared()->runPendingHighPrioirtyTasks();
90 m_task.run(); 94 m_task.run();
91 } 95 }
92 96
93 Scheduler::TracedTask m_task; 97 Scheduler::TracedTask m_task;
94 }; 98 };
95 99
100 class Scheduler::MainThreadPendingLowPriorityTaskRunner : public WebThread::Task {
101 public:
102 virtual void run() OVERRIDE
103 {
104 Scheduler* scheduler = Scheduler::shared();
105 // FIXME: This check should't be necessary, tasks should not outlive bli nk.
106 ASSERT(scheduler);
107 if (!scheduler)
108 return;
109 scheduler->runPendingLowPriorityTasks();
110 }
111 };
112
96 Scheduler* Scheduler::s_sharedScheduler = nullptr; 113 Scheduler* Scheduler::s_sharedScheduler = nullptr;
97 114
98 void Scheduler::initializeOnMainThread() 115 void Scheduler::initializeOnMainThread()
99 { 116 {
100 s_sharedScheduler = new Scheduler(); 117 s_sharedScheduler = new Scheduler();
101 } 118 }
102 119
103 void Scheduler::shutdown() 120 void Scheduler::shutdown()
104 { 121 {
105 delete s_sharedScheduler; 122 delete s_sharedScheduler;
106 s_sharedScheduler = nullptr; 123 s_sharedScheduler = nullptr;
107 } 124 }
108 125
109 Scheduler* Scheduler::shared() 126 Scheduler* Scheduler::shared()
110 { 127 {
111 return s_sharedScheduler; 128 return s_sharedScheduler;
112 } 129 }
113 130
114 Scheduler::Scheduler() 131 Scheduler::Scheduler()
115 : m_sharedTimerFunction(nullptr) 132 : m_sharedTimerFunction(nullptr)
116 , m_mainThread(blink::Platform::current()->currentThread()) 133 , m_mainThread(blink::Platform::current()->currentThread())
134 , m_compositorStart(0.0)
135 , m_compositorDeadline(0.0)
136 , m_compositorInterval(0.0)
117 , m_highPriorityTaskCount(0) 137 , m_highPriorityTaskCount(0)
118 , m_highPriorityTaskRunnerPosted(false) 138 , m_activeLowPrioirtyQueue(nullptr)
119 { 139 {
140 m_mutexProtected.m_highPriorityTaskRunnerPosted = false;
141 m_mutexProtected.m_lowPriorityTaskRunnerPosted = false;
120 } 142 }
121 143
122 Scheduler::~Scheduler() 144 Scheduler::~Scheduler()
123 { 145 {
124 while (hasPendingHighPriorityWork()) { 146 while (hasPendingHighPriorityWork()) {
125 swapQueuesAndRunPendingTasks(); 147 runPendingHighPrioirtyTasks();
126 } 148 }
127 } 149 }
128 150
129 void Scheduler::willBeginFrame(const WebBeginFrameArgs& args) 151 void Scheduler::willBeginFrame(const WebBeginFrameArgs& args)
130 { 152 {
131 // TODO: Use frame deadline and interval to schedule idle tasks. 153 ASSERT(isMainThread());
154
155 m_compositorStart = args.lastFrameTimeMonotonic;
156 m_compositorDeadline = args.deadline;
157 m_compositorInterval = args.interval;
132 } 158 }
133 159
134 void Scheduler::didCommitFrameToCompositor() 160 void Scheduler::didCommitFrameToCompositor()
135 { 161 {
136 // TODO: Trigger the frame deadline immediately. 162 // TODO: Trigger the frame deadline immediately.
137 } 163 }
138 164
139 void Scheduler::scheduleIdleTask(const TraceLocation& location, const IdleTask& idleTask) 165 void Scheduler::scheduleIdleTask(const TraceLocation& location, const IdleTask& idleTask)
140 { 166 {
141 // TODO: send a real allottedTime here. 167 // TODO: send a real allottedTime here.
142 m_mainThread->postTask(new MainThreadIdleTaskAdapter(idleTask, 0, location)) ; 168 m_mainThread->postTask(new MainThreadIdleTaskAdapter(idleTask, 0, location)) ;
143 } 169 }
144 170
145 void Scheduler::postTask(const TraceLocation& location, const Task& task) 171 void Scheduler::postTask(const TraceLocation& location, const Task& task)
146 { 172 {
147 m_mainThread->postTask(new MainThreadPendingTaskRunner(task, location)); 173 m_mainThread->postTask(new MainThreadPendingTaskRunner(task, location));
148 } 174 }
149 175
150 void Scheduler::postInputTask(const TraceLocation& location, const Task& task) 176 void Scheduler::postInputTask(const TraceLocation& location, const Task& task)
151 { 177 {
152 Locker<Mutex> lock(m_pendingTasksMutex); 178 Locker<Mutex> lock(m_pendingTasksMutex);
153 m_pendingHighPriorityTasks.append(TracedTask(task, location)); 179 m_mutexProtected.m_pendingHighPriorityTasks.append(TracedTask(task, location ));
154 atomicIncrement(&m_highPriorityTaskCount); 180 atomicIncrement(&m_highPriorityTaskCount);
181 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), "PendingHighPri orityTasks", m_highPriorityTaskCount);
155 maybePostMainThreadPendingHighPriorityTaskRunner(); 182 maybePostMainThreadPendingHighPriorityTaskRunner();
156 } 183 }
157 184
158 void Scheduler::postCompositorTask(const TraceLocation& location, const Task& ta sk) 185 void Scheduler::postCompositorTask(const TraceLocation& location, const Task& ta sk)
159 { 186 {
160 Locker<Mutex> lock(m_pendingTasksMutex); 187 Locker<Mutex> lock(m_pendingTasksMutex);
161 m_pendingHighPriorityTasks.append(TracedTask(task, location)); 188 m_mutexProtected.m_pendingHighPriorityTasks.append(TracedTask(task, location ));
162 atomicIncrement(&m_highPriorityTaskCount); 189 atomicIncrement(&m_highPriorityTaskCount);
190 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), "PendingHighPri orityTasks", m_highPriorityTaskCount);
163 maybePostMainThreadPendingHighPriorityTaskRunner(); 191 maybePostMainThreadPendingHighPriorityTaskRunner();
164 } 192 }
165 193
194 void Scheduler::postIpcTask(const TraceLocation& location, const Task& task)
195 {
196 Locker<Mutex> lock(m_pendingTasksMutex);
197 m_mutexProtected.m_pendingLowPriorityTasks.append(TracedTask(task, location) );
198 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), "PendingLowPrio rityTasks",
199 m_mutexProtected.m_pendingLowPriorityTasks.allQueuesSize());
200 maybePostMainThreadPendingLowPriorityTaskRunner(Platform::current()->monoton icallyIncreasingTime());
201 }
202
166 void Scheduler::maybePostMainThreadPendingHighPriorityTaskRunner() 203 void Scheduler::maybePostMainThreadPendingHighPriorityTaskRunner()
167 { 204 {
168 ASSERT(m_pendingTasksMutex.locked()); 205 ASSERT(m_pendingTasksMutex.locked());
169 if (m_highPriorityTaskRunnerPosted) 206 if (m_mutexProtected.m_highPriorityTaskRunnerPosted)
170 return; 207 return;
171 m_mainThread->postTask(new MainThreadPendingHighPriorityTaskRunner()); 208 m_mainThread->postTask(new MainThreadPendingHighPriorityTaskRunner());
172 m_highPriorityTaskRunnerPosted = true; 209 m_mutexProtected.m_highPriorityTaskRunnerPosted = true;
210 }
211
212 double Scheduler::nextPredictedCompositorStart()
213 {
214 return nextPredictedCompositorStartInternal(Platform::current()->monotonical lyIncreasingTime());
215 }
216
217 double Scheduler::nextPredictedCompositorDeadline()
218 {
219 return nextPredictedCompositorDeadlineInternal(Platform::current()->monotoni callyIncreasingTime());
220 }
221
222 double Scheduler::nextPredictedCompositorStartInternal(double currentTime)
223 {
224 if (currentTime < m_compositorStart)
225 return m_compositorStart;
226
227 double interval = m_compositorInterval;
228 if (interval == 0.0)
229 return 0.0;
230
231 double numIntervals = ceil((currentTime - m_compositorStart) / interval);
232 return m_compositorStart + interval * numIntervals;
233 }
234
235 double Scheduler::nextPredictedCompositorDeadlineInternal(double currentTime)
236 {
237 if (currentTime < m_compositorDeadline)
238 return m_compositorDeadline;
239
240 double interval = m_compositorInterval;
241 if (interval == 0.0)
242 return 0.0;
243
244 double numIntervals = ceil((currentTime - m_compositorDeadline) / interval);
245 return m_compositorDeadline + interval * numIntervals;
246 }
247
248 void Scheduler::maybePostMainThreadPendingLowPriorityTaskRunner(double currentTi me)
249 {
250 ASSERT(m_pendingTasksMutex.locked());
251 if (m_mutexProtected.m_lowPriorityTaskRunnerPosted)
252 return;
253
254 // MainThreadPendingLowPriorityTaskRunner should run after the compositor wo rk is expected to have finished so that
255 // it's less likely to be preempted by a high priority task.
256 double delaySec = nextPredictedCompositorDeadlineInternal(currentTime) - cur rentTime;
257 long long delayMs = static_cast<long long>(delaySec * 1000.0);
258 m_mainThread->postDelayedTask(new MainThreadPendingLowPriorityTaskRunner(), delayMs);
259 m_mutexProtected.m_lowPriorityTaskRunnerPosted = true;
173 } 260 }
174 261
175 void Scheduler::postIdleTask(const TraceLocation& location, const IdleTask& idle Task) 262 void Scheduler::postIdleTask(const TraceLocation& location, const IdleTask& idle Task)
176 { 263 {
177 scheduleIdleTask(location, idleTask); 264 scheduleIdleTask(location, idleTask);
178 } 265 }
179 266
180 void Scheduler::tickSharedTimer() 267 void Scheduler::tickSharedTimer()
181 { 268 {
182 TRACE_EVENT0("blink", "Scheduler::tickSharedTimer"); 269 TRACE_EVENT0("blink", "Scheduler::tickSharedTimer");
183 270
184 // Run any high priority tasks that are queued up, otherwise the blink timer s will yield immediately. 271 // Run any high priority tasks that are queued up, otherwise the blink timer s will yield immediately.
185 bool workDone = swapQueuesAndRunPendingTasks(); 272 bool workDone = runPendingHighPrioirtyTasks();
186 m_sharedTimerFunction(); 273 m_sharedTimerFunction();
187 274
188 // The blink timers may have just yielded, so run any high priority tasks th at where queued up 275 // 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. 276 // while the blink timers were executing.
190 if (!workDone) 277 if (!workDone)
191 swapQueuesAndRunPendingTasks(); 278 runPendingHighPrioirtyTasks();
192 } 279 }
193 280
194 bool Scheduler::swapQueuesAndRunPendingTasks() 281 bool Scheduler::runPendingHighPrioirtyTasks()
195 { 282 {
196 ASSERT(isMainThread()); 283 ASSERT(isMainThread());
197 284
198 // These locks guard against another thread posting input or compositor task s while we swap the buffers. 285 // 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. 286 // One the buffers have been swapped we can safely access the returned deque without having to lock.
200 m_pendingTasksMutex.lock(); 287 m_pendingTasksMutex.lock();
201 Deque<TracedTask>& highPriorityTasks = m_pendingHighPriorityTasks.swapBuffer s(); 288 Deque<TracedTask>& highPriorityTasks = m_mutexProtected.m_pendingHighPriorit yTasks.swapBuffers();
202 m_pendingTasksMutex.unlock(); 289 m_pendingTasksMutex.unlock();
203 return executeHighPriorityTasks(highPriorityTasks); 290 return executeHighPriorityTasks(highPriorityTasks);
204 } 291 }
205 292
206 void Scheduler::swapQueuesRunPendingTasksAndAllowHighPriorityTaskRunnerPosting() 293 void Scheduler::runPendingHighPriorityTasksAndAllowTaskRunnerPosting()
207 { 294 {
208 ASSERT(isMainThread()); 295 ASSERT(isMainThread());
209 296
210 // These locks guard against another thread posting input or compositor task s while we swap the buffers. 297 // These locks guard against another thread posting input or compositor task s while we swap the buffers.
211 // One the buffers have been swapped we can safely access the returned deque without having to lock. 298 // One the buffers have been swapped we can safely access the returned deque without having to lock.
212 m_pendingTasksMutex.lock(); 299 m_pendingTasksMutex.lock();
213 Deque<TracedTask>& highPriorityTasks = m_pendingHighPriorityTasks.swapBuffer s(); 300 Deque<TracedTask>& highPriorityTasks = m_mutexProtected.m_pendingHighPriorit yTasks.swapBuffers();
214 m_highPriorityTaskRunnerPosted = false; 301 m_mutexProtected.m_highPriorityTaskRunnerPosted = false;
215 m_pendingTasksMutex.unlock(); 302 m_pendingTasksMutex.unlock();
216 executeHighPriorityTasks(highPriorityTasks); 303 executeHighPriorityTasks(highPriorityTasks);
217 } 304 }
218 305
219 bool Scheduler::executeHighPriorityTasks(Deque<TracedTask>& highPriorityTasks) 306 bool Scheduler::executeHighPriorityTasks(Deque<TracedTask>& highPriorityTasks)
220 { 307 {
221 TRACE_EVENT0("blink", "Scheduler::executeHighPriorityTasks"); 308 TRACE_EVENT0("blink", "Scheduler::executeHighPriorityTasks");
222 int highPriorityTasksExecuted = 0; 309 int highPriorityTasksExecuted = 0;
223 while (!highPriorityTasks.isEmpty()) { 310 while (!highPriorityTasks.isEmpty()) {
224 highPriorityTasks.takeFirst().run(); 311 highPriorityTasks.takeFirst().run();
225 highPriorityTasksExecuted++; 312 highPriorityTasksExecuted++;
226 } 313 }
227 314
228 int highPriorityTaskCount = atomicSubtract(&m_highPriorityTaskCount, highPri orityTasksExecuted); 315 int highPriorityTaskCount = atomicSubtract(&m_highPriorityTaskCount, highPri orityTasksExecuted);
229 ASSERT_UNUSED(highPriorityTaskCount, highPriorityTaskCount >= 0); 316 ASSERT_UNUSED(highPriorityTaskCount, highPriorityTaskCount >= 0);
317 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), "PendingHighPri orityTasks", m_highPriorityTaskCount);
230 return highPriorityTasksExecuted > 0; 318 return highPriorityTasksExecuted > 0;
231 } 319 }
232 320
321 void Scheduler::reloadEmptyLowPrioirtyQueue()
322 {
323 if (m_activeLowPrioirtyQueue && !m_activeLowPrioirtyQueue->isEmpty())
324 return;
325
326 Locker<Mutex> lock(m_pendingTasksMutex);
327 m_activeLowPrioirtyQueue = &m_mutexProtected.m_pendingLowPriorityTasks.swapB uffers();
328 }
329
330 void Scheduler::runPendingLowPriorityTasks()
331 {
332 TRACE_EVENT0("blink", "Scheduler::runPendingLowPriorityTasks");
333 m_pendingTasksMutex.lock();
334 m_mutexProtected.m_lowPriorityTaskRunnerPosted = false;
335 m_pendingTasksMutex.unlock();
336
337 double startTime = Platform::current()->monotonicallyIncreasingTime();
338 double endTime = startTime + s_maximumLowPrioirtyTaskExecutionTimeSeconds;
339
340 for (;;) {
341 reloadEmptyLowPrioirtyQueue();
342 if (m_activeLowPrioirtyQueue->isEmpty() || hasPendingHighPriorityWork())
343 break;
344 m_activeLowPrioirtyQueue->takeFirst().run();
345
346 if (Platform::current()->monotonicallyIncreasingTime() >= endTime)
347 break;
348 }
349
350 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), "PendingLowPrio rityTasks",
351 m_mutexProtected.m_pendingLowPriorityTasks.allQueuesSize());
352
353 if (!m_activeLowPrioirtyQueue->isEmpty())
354 maybePostMainThreadPendingLowPriorityTaskRunner(Platform::current()->mon otonicallyIncreasingTime());
355 }
356
233 void Scheduler::sharedTimerAdapter() 357 void Scheduler::sharedTimerAdapter()
234 { 358 {
235 shared()->tickSharedTimer(); 359 shared()->tickSharedTimer();
236 } 360 }
237 361
238 void Scheduler::setSharedTimerFiredFunction(void (*function)()) 362 void Scheduler::setSharedTimerFiredFunction(void (*function)())
239 { 363 {
240 m_sharedTimerFunction = function; 364 m_sharedTimerFunction = function;
241 blink::Platform::current()->setSharedTimerFiredFunction(function ? &Schedule r::sharedTimerAdapter : nullptr); 365 blink::Platform::current()->setSharedTimerFiredFunction(function ? &Schedule r::sharedTimerAdapter : nullptr);
242 } 366 }
(...skipping 25 matching lines...) Expand all
268 392
269 void Scheduler::TracedTask::run() 393 void Scheduler::TracedTask::run()
270 { 394 {
271 TRACE_EVENT2("blink", "TracedTask::run", 395 TRACE_EVENT2("blink", "TracedTask::run",
272 "src_file", m_location.fileName(), 396 "src_file", m_location.fileName(),
273 "src_func", m_location.functionName()); 397 "src_func", m_location.functionName());
274 m_task(); 398 m_task();
275 } 399 }
276 400
277 } // namespace blink 401 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698