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

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

Issue 559973003: Adds the concept of Policies to the Blink Scheduler (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Change the test time funcstions to be non-static 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
« 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"
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 namespace { 19 namespace {
20 20
21 // The time we should stay in CompositorPriority mode for, after a touch event.
22 double kLowSchedulerPolicyAfterTouchTimeSeconds = 0.1;
23
21 // Can be created from any thread. 24 // Can be created from any thread.
22 // Note if the scheduler gets shutdown, this may be run after. 25 // Note if the scheduler gets shutdown, this may be run after.
23 class MainThreadIdleTaskAdapter : public WebThread::Task { 26 class MainThreadIdleTaskAdapter : public WebThread::Task {
24 public: 27 public:
25 MainThreadIdleTaskAdapter(const Scheduler::IdleTask& idleTask, double allott edTimeMs, const TraceLocation& location) 28 MainThreadIdleTaskAdapter(const Scheduler::IdleTask& idleTask, double allott edTimeMs, const TraceLocation& location)
26 : m_idleTask(idleTask) 29 : m_idleTask(idleTask)
27 , m_allottedTimeMs(allottedTimeMs) 30 , m_allottedTimeMs(allottedTimeMs)
28 , m_location(location) 31 , m_location(location)
29 { 32 {
30 } 33 }
(...skipping 25 matching lines...) Expand all
56 } 59 }
57 60
58 // WebThread::Task implementation. 61 // WebThread::Task implementation.
59 virtual void run() OVERRIDE 62 virtual void run() OVERRIDE
60 { 63 {
61 Scheduler* scheduler = Scheduler::shared(); 64 Scheduler* scheduler = Scheduler::shared();
62 // FIXME: This check should't be necessary, tasks should not outlive bli nk. 65 // FIXME: This check should't be necessary, tasks should not outlive bli nk.
63 ASSERT(scheduler); 66 ASSERT(scheduler);
64 if (!scheduler) 67 if (!scheduler)
65 return; 68 return;
69 // NOTE we must unconditionally execute high priority tasks here, since if we're not in CompositorPriority
70 // mode, then this is the only place where high priority tasks will be e xecuted.
66 scheduler->swapQueuesRunPendingTasksAndAllowHighPriorityTaskRunnerPostin g(); 71 scheduler->swapQueuesRunPendingTasksAndAllowHighPriorityTaskRunnerPostin g();
67 } 72 }
68 }; 73 };
69 74
70 75
71 // Can be created from any thread. 76 // Can be created from any thread.
72 // Note if the scheduler gets shutdown, this may be run after. 77 // Note if the scheduler gets shutdown, this may be run after.
73 class Scheduler::MainThreadPendingTaskRunner : public WebThread::Task { 78 class Scheduler::MainThreadPendingTaskRunner : public WebThread::Task {
74 public: 79 public:
75 MainThreadPendingTaskRunner( 80 MainThreadPendingTaskRunner(
76 const Scheduler::Task& task, const TraceLocation& location) 81 const Scheduler::Task& task, const TraceLocation& location)
77 : m_task(task, location) 82 : m_task(task, location)
78 { 83 {
79 ASSERT(Scheduler::shared()); 84 ASSERT(Scheduler::shared());
80 } 85 }
81 86
82 // WebThread::Task implementation. 87 // WebThread::Task implementation.
83 virtual void run() OVERRIDE 88 virtual void run() OVERRIDE
84 { 89 {
85 Scheduler* scheduler = Scheduler::shared(); 90 Scheduler* scheduler = Scheduler::shared();
86 // FIXME: This check should't be necessary, tasks should not outlive bli nk. 91 // FIXME: This check should't be necessary, tasks should not outlive bli nk.
87 ASSERT(scheduler); 92 ASSERT(scheduler);
88 if (scheduler) 93 if (scheduler)
89 Scheduler::shared()->swapQueuesAndRunPendingTasks(); 94 Scheduler::shared()->runPendingHighPriorityTasksIfInCompositorPriori ty();
90 m_task.run(); 95 m_task.run();
91 } 96 }
92 97
93 Scheduler::TracedTask m_task; 98 Scheduler::TracedTask m_task;
94 }; 99 };
95 100
96 Scheduler* Scheduler::s_sharedScheduler = nullptr; 101 Scheduler* Scheduler::s_sharedScheduler = nullptr;
97 102
98 void Scheduler::initializeOnMainThread() 103 void Scheduler::initializeOnMainThread()
99 { 104 {
100 s_sharedScheduler = new Scheduler(); 105 s_sharedScheduler = new Scheduler();
101 } 106 }
102 107
103 void Scheduler::shutdown() 108 void Scheduler::shutdown()
104 { 109 {
105 delete s_sharedScheduler; 110 delete s_sharedScheduler;
106 s_sharedScheduler = nullptr; 111 s_sharedScheduler = nullptr;
107 } 112 }
108 113
109 Scheduler* Scheduler::shared() 114 Scheduler* Scheduler::shared()
110 { 115 {
111 return s_sharedScheduler; 116 return s_sharedScheduler;
112 } 117 }
113 118
114 Scheduler::Scheduler() 119 Scheduler::Scheduler()
115 : m_sharedTimerFunction(nullptr) 120 : m_sharedTimerFunction(nullptr)
116 , m_mainThread(blink::Platform::current()->currentThread()) 121 , m_mainThread(blink::Platform::current()->currentThread())
122 , m_compositorPriorityPolicyEndTimeSeconds(0)
117 , m_highPriorityTaskCount(0) 123 , m_highPriorityTaskCount(0)
118 , m_highPriorityTaskRunnerPosted(false) 124 , m_highPriorityTaskRunnerPosted(false)
125 , m_schedulerPolicy(Normal)
119 { 126 {
120 } 127 }
121 128
122 Scheduler::~Scheduler() 129 Scheduler::~Scheduler()
123 { 130 {
124 while (hasPendingHighPriorityWork()) { 131 while (hasPendingHighPriorityWork()) {
125 swapQueuesAndRunPendingTasks(); 132 swapQueuesAndRunPendingTasks();
126 } 133 }
127 } 134 }
128 135
(...skipping 17 matching lines...) Expand all
146 { 153 {
147 m_mainThread->postTask(new MainThreadPendingTaskRunner(task, location)); 154 m_mainThread->postTask(new MainThreadPendingTaskRunner(task, location));
148 } 155 }
149 156
150 void Scheduler::postInputTask(const TraceLocation& location, const Task& task) 157 void Scheduler::postInputTask(const TraceLocation& location, const Task& task)
151 { 158 {
152 Locker<Mutex> lock(m_pendingTasksMutex); 159 Locker<Mutex> lock(m_pendingTasksMutex);
153 m_pendingHighPriorityTasks.append(TracedTask(task, location)); 160 m_pendingHighPriorityTasks.append(TracedTask(task, location));
154 atomicIncrement(&m_highPriorityTaskCount); 161 atomicIncrement(&m_highPriorityTaskCount);
155 maybePostMainThreadPendingHighPriorityTaskRunner(); 162 maybePostMainThreadPendingHighPriorityTaskRunner();
163 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), "PendingHighPri orityTasks", m_highPriorityTaskCount);
156 } 164 }
157 165
158 void Scheduler::postCompositorTask(const TraceLocation& location, const Task& ta sk) 166 void Scheduler::postCompositorTask(const TraceLocation& location, const Task& ta sk)
159 { 167 {
160 Locker<Mutex> lock(m_pendingTasksMutex); 168 Locker<Mutex> lock(m_pendingTasksMutex);
161 m_pendingHighPriorityTasks.append(TracedTask(task, location)); 169 m_pendingHighPriorityTasks.append(TracedTask(task, location));
162 atomicIncrement(&m_highPriorityTaskCount); 170 atomicIncrement(&m_highPriorityTaskCount);
163 maybePostMainThreadPendingHighPriorityTaskRunner(); 171 maybePostMainThreadPendingHighPriorityTaskRunner();
172 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), "PendingHighPri orityTasks", m_highPriorityTaskCount);
164 } 173 }
165 174
166 void Scheduler::maybePostMainThreadPendingHighPriorityTaskRunner() 175 void Scheduler::maybePostMainThreadPendingHighPriorityTaskRunner()
167 { 176 {
168 ASSERT(m_pendingTasksMutex.locked()); 177 ASSERT(m_pendingTasksMutex.locked());
169 if (m_highPriorityTaskRunnerPosted) 178 if (m_highPriorityTaskRunnerPosted)
170 return; 179 return;
171 m_mainThread->postTask(new MainThreadPendingHighPriorityTaskRunner()); 180 m_mainThread->postTask(new MainThreadPendingHighPriorityTaskRunner());
172 m_highPriorityTaskRunnerPosted = true; 181 m_highPriorityTaskRunnerPosted = true;
173 } 182 }
174 183
175 void Scheduler::postIdleTask(const TraceLocation& location, const IdleTask& idle Task) 184 void Scheduler::postIdleTask(const TraceLocation& location, const IdleTask& idle Task)
176 { 185 {
177 scheduleIdleTask(location, idleTask); 186 scheduleIdleTask(location, idleTask);
178 } 187 }
179 188
180 void Scheduler::tickSharedTimer() 189 void Scheduler::tickSharedTimer()
181 { 190 {
182 TRACE_EVENT0("blink", "Scheduler::tickSharedTimer"); 191 TRACE_EVENT0("blink", "Scheduler::tickSharedTimer");
183 192
184 // Run any high priority tasks that are queued up, otherwise the blink timer s will yield immediately. 193 // Run any high priority tasks that are queued up, otherwise the blink timer s will yield immediately.
185 bool workDone = swapQueuesAndRunPendingTasks(); 194 bool workDone = runPendingHighPriorityTasksIfInCompositorPriority();
186 m_sharedTimerFunction(); 195 m_sharedTimerFunction();
187 196
188 // The blink timers may have just yielded, so run any high priority tasks th at where queued up 197 // 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. 198 // while the blink timers were executing.
190 if (!workDone) 199 if (!workDone)
191 swapQueuesAndRunPendingTasks(); 200 runPendingHighPriorityTasksIfInCompositorPriority();
201 }
202
203 bool Scheduler::runPendingHighPriorityTasksIfInCompositorPriority()
204 {
205 ASSERT(isMainThread());
206 if (schedulerPolicy() != CompositorPriority)
207 return false;
208
209 return swapQueuesAndRunPendingTasks();
192 } 210 }
193 211
194 bool Scheduler::swapQueuesAndRunPendingTasks() 212 bool Scheduler::swapQueuesAndRunPendingTasks()
195 { 213 {
196 ASSERT(isMainThread()); 214 ASSERT(isMainThread());
197 215
198 // These locks guard against another thread posting input or compositor task s while we swap the buffers. 216 // 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. 217 // One the buffers have been swapped we can safely access the returned deque without having to lock.
200 m_pendingTasksMutex.lock(); 218 m_pendingTasksMutex.lock();
201 Deque<TracedTask>& highPriorityTasks = m_pendingHighPriorityTasks.swapBuffer s(); 219 Deque<TracedTask>& highPriorityTasks = m_pendingHighPriorityTasks.swapBuffer s();
220 maybeEnterNormalSchedulerPolicy();
202 m_pendingTasksMutex.unlock(); 221 m_pendingTasksMutex.unlock();
203 return executeHighPriorityTasks(highPriorityTasks); 222 return executeHighPriorityTasks(highPriorityTasks);
204 } 223 }
205 224
206 void Scheduler::swapQueuesRunPendingTasksAndAllowHighPriorityTaskRunnerPosting() 225 void Scheduler::swapQueuesRunPendingTasksAndAllowHighPriorityTaskRunnerPosting()
207 { 226 {
208 ASSERT(isMainThread()); 227 ASSERT(isMainThread());
209 228
210 // These locks guard against another thread posting input or compositor task s while we swap the buffers. 229 // 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. 230 // One the buffers have been swapped we can safely access the returned deque without having to lock.
212 m_pendingTasksMutex.lock(); 231 m_pendingTasksMutex.lock();
213 Deque<TracedTask>& highPriorityTasks = m_pendingHighPriorityTasks.swapBuffer s(); 232 Deque<TracedTask>& highPriorityTasks = m_pendingHighPriorityTasks.swapBuffer s();
214 m_highPriorityTaskRunnerPosted = false; 233 m_highPriorityTaskRunnerPosted = false;
234 maybeEnterNormalSchedulerPolicy();
215 m_pendingTasksMutex.unlock(); 235 m_pendingTasksMutex.unlock();
216 executeHighPriorityTasks(highPriorityTasks); 236 executeHighPriorityTasks(highPriorityTasks);
217 } 237 }
218 238
239 void Scheduler::maybeEnterNormalSchedulerPolicy()
240 {
241 ASSERT(isMainThread());
242 ASSERT(m_pendingTasksMutex.locked());
243
244 // Go back to the normal scheduler policy if enough time has elapsed.
245 if (schedulerPolicy() == CompositorPriority && Platform::current()->monotoni callyIncreasingTime() > m_compositorPriorityPolicyEndTimeSeconds)
246 enterSchedulerPolicyLocked(Normal);
247 }
248
219 bool Scheduler::executeHighPriorityTasks(Deque<TracedTask>& highPriorityTasks) 249 bool Scheduler::executeHighPriorityTasks(Deque<TracedTask>& highPriorityTasks)
220 { 250 {
221 TRACE_EVENT0("blink", "Scheduler::executeHighPriorityTasks"); 251 TRACE_EVENT0("blink", "Scheduler::executeHighPriorityTasks");
222 int highPriorityTasksExecuted = 0; 252 int highPriorityTasksExecuted = 0;
223 while (!highPriorityTasks.isEmpty()) { 253 while (!highPriorityTasks.isEmpty()) {
224 highPriorityTasks.takeFirst().run(); 254 highPriorityTasks.takeFirst().run();
225 highPriorityTasksExecuted++; 255 highPriorityTasksExecuted++;
226 } 256 }
227 257
228 int highPriorityTaskCount = atomicSubtract(&m_highPriorityTaskCount, highPri orityTasksExecuted); 258 int highPriorityTaskCount = atomicSubtract(&m_highPriorityTaskCount, highPri orityTasksExecuted);
229 ASSERT_UNUSED(highPriorityTaskCount, highPriorityTaskCount >= 0); 259 ASSERT_UNUSED(highPriorityTaskCount, highPriorityTaskCount >= 0);
260 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), "PendingHighPri orityTasks", m_highPriorityTaskCount);
230 return highPriorityTasksExecuted > 0; 261 return highPriorityTasksExecuted > 0;
231 } 262 }
232 263
233 void Scheduler::sharedTimerAdapter() 264 void Scheduler::sharedTimerAdapter()
234 { 265 {
235 shared()->tickSharedTimer(); 266 shared()->tickSharedTimer();
236 } 267 }
237 268
238 void Scheduler::setSharedTimerFiredFunction(void (*function)()) 269 void Scheduler::setSharedTimerFiredFunction(void (*function)())
239 { 270 {
240 m_sharedTimerFunction = function; 271 m_sharedTimerFunction = function;
241 blink::Platform::current()->setSharedTimerFiredFunction(function ? &Schedule r::sharedTimerAdapter : nullptr); 272 blink::Platform::current()->setSharedTimerFiredFunction(function ? &Schedule r::sharedTimerAdapter : nullptr);
242 } 273 }
243 274
244 void Scheduler::setSharedTimerFireInterval(double interval) 275 void Scheduler::setSharedTimerFireInterval(double interval)
245 { 276 {
246 blink::Platform::current()->setSharedTimerFireInterval(interval); 277 blink::Platform::current()->setSharedTimerFireInterval(interval);
247 } 278 }
248 279
249 void Scheduler::stopSharedTimer() 280 void Scheduler::stopSharedTimer()
250 { 281 {
251 blink::Platform::current()->stopSharedTimer(); 282 blink::Platform::current()->stopSharedTimer();
252 } 283 }
253 284
254 bool Scheduler::shouldYieldForHighPriorityWork() const 285 bool Scheduler::shouldYieldForHighPriorityWork() const
255 { 286 {
287 // It's only worthwhile yielding in CompositorPriority mode.
288 if (schedulerPolicy() != CompositorPriority)
289 return false;
290
256 return hasPendingHighPriorityWork(); 291 return hasPendingHighPriorityWork();
257 } 292 }
258 293
259 bool Scheduler::hasPendingHighPriorityWork() const 294 bool Scheduler::hasPendingHighPriorityWork() const
260 { 295 {
261 // This method is expected to be run on the main thread, but the high priori ty tasks will be posted by 296 // 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 297 // 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 298 // ThreadTimers::sharedTimerFiredInternal so we decided to use atomics + bar rier loads here which
264 // should be cheaper. 299 // should be cheaper.
265 // NOTE it's possible the barrier read is overkill here, since delayed yield ing isn't a big deal. 300 // 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; 301 return acquireLoad(&m_highPriorityTaskCount) != 0;
267 } 302 }
268 303
304 Scheduler::SchedulerPolicy Scheduler::schedulerPolicy() const
305 {
306 ASSERT(isMainThread());
307 // It's important not to miss the transition from normal to low latency mode , otherwise we're likely to
308 // delay the processing of input tasks. Since that transition is triggered b y a different thread, we
309 // need either a lock or a memory barrier, and the memory barrier is probabl y cheaper.
310 return static_cast<SchedulerPolicy>(acquireLoad(&m_schedulerPolicy));
311 }
312
313 void Scheduler::enterSchedulerPolicy(SchedulerPolicy schedulerPolicy)
314 {
315 Locker<Mutex> lock(m_pendingTasksMutex);
316 enterSchedulerPolicyLocked(schedulerPolicy);
317 }
318
319 void Scheduler::enterSchedulerPolicyLocked(SchedulerPolicy schedulerPolicy)
320 {
321 ASSERT(m_pendingTasksMutex.locked());
322 if (schedulerPolicy == CompositorPriority)
323 m_compositorPriorityPolicyEndTimeSeconds = Platform::current()->monotoni callyIncreasingTime() + kLowSchedulerPolicyAfterTouchTimeSeconds;
324
325 releaseStore(&m_schedulerPolicy, schedulerPolicy);
326 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), "SchedulerPolic y", schedulerPolicy);
327 }
328
269 void Scheduler::TracedTask::run() 329 void Scheduler::TracedTask::run()
270 { 330 {
271 TRACE_EVENT2("blink", "TracedTask::run", 331 TRACE_EVENT2("blink", "TracedTask::run",
272 "src_file", m_location.fileName(), 332 "src_file", m_location.fileName(),
273 "src_func", m_location.functionName()); 333 "src_func", m_location.functionName());
274 m_task(); 334 m_task();
275 } 335 }
276 336
277 } // namespace blink 337 } // 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