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

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

Issue 595023002: Implement idle task scheduling. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Move to OwnPtr 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/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
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
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
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