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

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: Fixed some names 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 "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())
117 , m_highPriorityTaskCount(0) 122 , m_highPriorityTaskCount(0)
118 , m_highPriorityTaskRunnerPosted(false) 123 , m_highPriorityTaskRunnerPosted(false)
124 , m_schedulerPolicy(Normal)
125 , m_compositorPriorityPolicyEndTimeSeconds(0)
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(m_pendingTasksMutex.locked());
Sami 2014/09/11 11:32:18 Also add ASSERT(isMainThread());
alexclarke 2014/09/11 11:52:05 Done.
242
243 // Go back to the normal scheduler policy if enough time has elapsed.
244 if (schedulerPolicy() == CompositorPriority && Platform::current()->monotoni callyIncreasingTime() > m_compositorPriorityPolicyEndTimeSeconds)
245 enterSchedulerPolicy(Normal);
246 }
247
219 bool Scheduler::executeHighPriorityTasks(Deque<TracedTask>& highPriorityTasks) 248 bool Scheduler::executeHighPriorityTasks(Deque<TracedTask>& highPriorityTasks)
220 { 249 {
221 TRACE_EVENT0("blink", "Scheduler::executeHighPriorityTasks"); 250 TRACE_EVENT0("blink", "Scheduler::executeHighPriorityTasks");
222 int highPriorityTasksExecuted = 0; 251 int highPriorityTasksExecuted = 0;
223 while (!highPriorityTasks.isEmpty()) { 252 while (!highPriorityTasks.isEmpty()) {
224 highPriorityTasks.takeFirst().run(); 253 highPriorityTasks.takeFirst().run();
225 highPriorityTasksExecuted++; 254 highPriorityTasksExecuted++;
226 } 255 }
227 256
228 int highPriorityTaskCount = atomicSubtract(&m_highPriorityTaskCount, highPri orityTasksExecuted); 257 int highPriorityTaskCount = atomicSubtract(&m_highPriorityTaskCount, highPri orityTasksExecuted);
229 ASSERT_UNUSED(highPriorityTaskCount, highPriorityTaskCount >= 0); 258 ASSERT_UNUSED(highPriorityTaskCount, highPriorityTaskCount >= 0);
259 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), "PendingHighPri orityTasks", m_highPriorityTaskCount);
230 return highPriorityTasksExecuted > 0; 260 return highPriorityTasksExecuted > 0;
231 } 261 }
232 262
233 void Scheduler::sharedTimerAdapter() 263 void Scheduler::sharedTimerAdapter()
234 { 264 {
235 shared()->tickSharedTimer(); 265 shared()->tickSharedTimer();
236 } 266 }
237 267
238 void Scheduler::setSharedTimerFiredFunction(void (*function)()) 268 void Scheduler::setSharedTimerFiredFunction(void (*function)())
239 { 269 {
240 m_sharedTimerFunction = function; 270 m_sharedTimerFunction = function;
241 blink::Platform::current()->setSharedTimerFiredFunction(function ? &Schedule r::sharedTimerAdapter : nullptr); 271 blink::Platform::current()->setSharedTimerFiredFunction(function ? &Schedule r::sharedTimerAdapter : nullptr);
242 } 272 }
243 273
244 void Scheduler::setSharedTimerFireInterval(double interval) 274 void Scheduler::setSharedTimerFireInterval(double interval)
245 { 275 {
246 blink::Platform::current()->setSharedTimerFireInterval(interval); 276 blink::Platform::current()->setSharedTimerFireInterval(interval);
247 } 277 }
248 278
249 void Scheduler::stopSharedTimer() 279 void Scheduler::stopSharedTimer()
250 { 280 {
251 blink::Platform::current()->stopSharedTimer(); 281 blink::Platform::current()->stopSharedTimer();
252 } 282 }
253 283
254 bool Scheduler::shouldYieldForHighPriorityWork() const 284 bool Scheduler::shouldYieldForHighPriorityWork() const
255 { 285 {
286 // It's only worthwhile yielding in CompositorPriority mode.
287 if (schedulerPolicy() != CompositorPriority)
288 return false;
289
256 return hasPendingHighPriorityWork(); 290 return hasPendingHighPriorityWork();
257 } 291 }
258 292
259 bool Scheduler::hasPendingHighPriorityWork() const 293 bool Scheduler::hasPendingHighPriorityWork() const
260 { 294 {
261 // This method is expected to be run on the main thread, but the high priori ty tasks will be posted by 295 // 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 296 // 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 297 // ThreadTimers::sharedTimerFiredInternal so we decided to use atomics + bar rier loads here which
264 // should be cheaper. 298 // should be cheaper.
265 // NOTE it's possible the barrier read is overkill here, since delayed yield ing isn't a big deal. 299 // 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; 300 return acquireLoad(&m_highPriorityTaskCount) != 0;
267 } 301 }
268 302
303 Scheduler::SchedulerPolicy Scheduler::schedulerPolicy() const
304 {
305 ASSERT(isMainThread());
306 // It's important not to miss the transition from normal to low latency mode , otherwise we're likely to
307 // delay the processing of input tasks. Since that transition is triggered b y a different thread, we
308 // need either a lock or a memory barrier, and the memory barrier is probabl y cheaper.
309 return static_cast<SchedulerPolicy>(acquireLoad(&m_schedulerPolicy));
310 }
311
312 void Scheduler::enterSchedulerPolicy(SchedulerPolicy SchedulerPolicy)
Sami 2014/09/11 11:32:18 scheduler shouldn't be capitalized here.
alexclarke 2014/09/11 11:52:05 Done.
313 {
314 if (SchedulerPolicy == CompositorPriority)
315 m_compositorPriorityPolicyEndTimeSeconds = Platform::current()->monotoni callyIncreasingTime() + kLowSchedulerPolicyAfterTouchTimeSeconds;
Sami 2014/09/11 11:32:18 We need to grab m_pendingTasksMutex here, right?
alexclarke 2014/09/11 11:52:04 Done.
316
317 releaseStore(&m_schedulerPolicy, SchedulerPolicy);
318 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), "SchedulerPolic y", SchedulerPolicy);
319 }
320
269 void Scheduler::TracedTask::run() 321 void Scheduler::TracedTask::run()
270 { 322 {
271 TRACE_EVENT2("blink", "TracedTask::run", 323 TRACE_EVENT2("blink", "TracedTask::run",
272 "src_file", m_location.fileName(), 324 "src_file", m_location.fileName(),
273 "src_func", m_location.functionName()); 325 "src_func", m_location.functionName());
274 m_task(); 326 m_task();
275 } 327 }
276 328
277 } // namespace blink 329 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698