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

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

Issue 439923006: Prioritizing input and compositor tasks in the blink scheduler. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Adding wtf/DoubleBufferedDeque.h to git Created 6 years, 4 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/Task.h" 9 #include "platform/Task.h"
10 #include "platform/ThreadTimers.h"
9 #include "platform/TraceEvent.h" 11 #include "platform/TraceEvent.h"
10 #include "platform/TraceLocation.h"
11 #include "public/platform/Platform.h" 12 #include "public/platform/Platform.h"
12 #include "public/platform/WebThread.h" 13 #include "wtf/ThreadingPrimitives.h"
13 14
14 namespace blink { 15 namespace blink {
15 16
16 namespace { 17 namespace {
17 18
18 class MainThreadTaskAdapter : public blink::WebThread::Task { 19 class MainThreadIdleTaskAdapter : public WebThread::Task {
eseidel 2014/08/11 17:02:36 Might add a comment to note that this can be creat
alexclarke 2014/08/12 11:37:02 Done.
19 public: 20 public:
20 explicit MainThreadTaskAdapter(const TraceLocation& location, const Schedule r::Task& task) 21 MainThreadIdleTaskAdapter(const Scheduler::IdleTask& idleTask, double allott edTimeMs, const TraceLocation& location)
21 : m_location(location) 22 : m_idleTask(idleTask)
22 , m_task(task) 23 , m_allottedTimeMs(allottedTimeMs)
eseidel 2014/08/11 17:02:36 Might have called this timeout or maxDuration, but
alexclarke 2014/08/12 11:37:02 Acknowledged.
24 , m_location(location)
23 { 25 {
eseidel 2014/08/11 17:02:36 If this can't be created from any thread, we shoul
alexclarke 2014/08/12 11:37:02 It can be called from any thread.
24 } 26 }
25 27
26 // WebThread::Task implementation. 28 // WebThread::Task implementation.
27 virtual void run() OVERRIDE 29 virtual void run() OVERRIDE
28 { 30 {
29 TRACE_EVENT2("blink", "MainThreadTaskAdapter::run", 31 TRACE_EVENT2("blink", "MainThreadIdleTaskAdapter::run",
30 "src_file", m_location.fileName(), 32 "src_file", m_location.fileName(),
31 "src_func", m_location.functionName()); 33 "src_func", m_location.functionName());
32 m_task();
33 }
34
35 private:
36 const TraceLocation m_location;
37 Scheduler::Task m_task;
38 };
39
40 class MainThreadIdleTaskAdapter : public blink::WebThread::Task {
41 public:
42 MainThreadIdleTaskAdapter(const Scheduler::IdleTask& idleTask, double allott edTimeMs)
43 : m_idleTask(idleTask)
44 , m_allottedTimeMs(allottedTimeMs)
45 {
46 }
47
48 // WebThread::Task implementation.
49 virtual void run() OVERRIDE
50 {
51 TRACE_EVENT1("blink", "MainThreadIdleTaskAdapter::run", "allottedTime", m_allottedTimeMs);
52 m_idleTask(m_allottedTimeMs); 34 m_idleTask(m_allottedTimeMs);
53 } 35 }
54 36
55 private: 37 private:
56 Scheduler::IdleTask m_idleTask; 38 Scheduler::IdleTask m_idleTask;
57 double m_allottedTimeMs; 39 double m_allottedTimeMs;
40 TraceLocation m_location;
58 }; 41 };
59 42
60 } 43 } // namespace
44
45 class Scheduler::MainThreadPendingHighPriorityTaskRunner : public WebThread::Tas k {
46 public:
47 MainThreadPendingHighPriorityTaskRunner()
48 {
49 ASSERT(Scheduler::shared());
50 Scheduler::shared()->incrementMainThreadTaskRunnerCount();
51 }
52
53 ~MainThreadPendingHighPriorityTaskRunner()
54 {
55 Scheduler* scheduler = Scheduler::shared();
56 if (!scheduler)
57 return;
58 Scheduler::shared()->decrementMainThreadTaskRunnerCount();
59 }
60
61 // WebThread::Task implementation.
62 virtual void run() OVERRIDE
63 {
64 Scheduler* scheduler = Scheduler::shared();
eseidel 2014/08/11 17:02:36 When can this happen? This feels like it should b
alexclarke 2014/08/12 11:37:02 Because a posted MainThreadPendingHighPriorityTask
65 if (!scheduler)
66 return;
67 scheduler->runHighPriorityTasks();
68 }
69 };
70
71 class Scheduler::MainThreadPendingTaskRunner : public WebThread::Task {
72 public:
73 MainThreadPendingTaskRunner(
74 const Scheduler::Task& task, const TraceLocation& location)
75 : m_task(task)
76 , m_location(location)
77 {
78 ASSERT(Scheduler::shared());
79 Scheduler::shared()->incrementMainThreadTaskRunnerCount();
80 }
81
82 ~MainThreadPendingTaskRunner()
83 {
84 Scheduler* scheduler = Scheduler::shared();
85 if (!scheduler)
eseidel 2014/08/11 17:02:36 Feels like we should flush the tasks before shut-d
alexclarke 2014/08/12 11:37:03 We flush what we can (high priority tasks) but sin
86 return;
87 Scheduler::shared()->decrementMainThreadTaskRunnerCount();
88 }
89
90 // WebThread::Task implementation.
91 virtual void run() OVERRIDE
92 {
93 TRACE_EVENT2("blink", "MainThreadPendingTaskRunner::run",
eseidel 2014/08/11 17:02:36 Currious there is a trace here but not the other?
alexclarke 2014/08/12 11:37:02 Because Scheduler::TracedTask::run() does that for
94 "src_file", m_location.fileName(),
95 "src_func", m_location.functionName());
96 Scheduler* scheduler = Scheduler::shared();
97 if (scheduler)
98 Scheduler::shared()->runHighPriorityTasks();
99 m_task();
eseidel 2014/08/11 17:02:36 Why would we want to run this if !scheduler?
alexclarke 2014/08/12 11:37:02 Because this is the existing behaviour but we've a
100 }
101
102 Scheduler::Task m_task;
103 TraceLocation m_location;
104 };
61 105
62 Scheduler* Scheduler::s_sharedScheduler = nullptr; 106 Scheduler* Scheduler::s_sharedScheduler = nullptr;
63 107
64 void Scheduler::initializeOnMainThread() 108 void Scheduler::initializeOnMainThread()
65 { 109 {
66 s_sharedScheduler = new Scheduler(); 110 s_sharedScheduler = new Scheduler();
67 } 111 }
68 112
69 void Scheduler::shutdown() 113 void Scheduler::shutdown()
70 { 114 {
71 delete s_sharedScheduler; 115 delete s_sharedScheduler;
72 s_sharedScheduler = nullptr; 116 s_sharedScheduler = nullptr;
73 } 117 }
74 118
75 Scheduler* Scheduler::shared() 119 Scheduler* Scheduler::shared()
76 { 120 {
77 return s_sharedScheduler; 121 return s_sharedScheduler;
78 } 122 }
79 123
80 Scheduler::Scheduler() 124 Scheduler::Scheduler()
81 : m_mainThread(blink::Platform::current()->currentThread()) 125 : m_mainThread(blink::Platform::current()->currentThread())
82 , m_sharedTimerFunction(nullptr) 126 , m_sharedTimerFunction(nullptr)
127 , m_mainThreadTaskRunnerCount(0)
128 , m_highPriotityTaskCount(0)
83 { 129 {
84 } 130 }
85 131
86 Scheduler::~Scheduler() 132 Scheduler::~Scheduler()
87 { 133 {
134 while (shouldYieldForHighPriorityWork()) {
135 runHighPriorityTasks();
136 }
88 } 137 }
89 138
90 void Scheduler::scheduleTask(const TraceLocation& location, const Task& task) 139 void Scheduler::scheduleIdleTask(const TraceLocation& location, const IdleTask& idleTask)
91 {
92 m_mainThread->postTask(new MainThreadTaskAdapter(location, task));
93 }
94
95 void Scheduler::scheduleIdleTask(const IdleTask& idleTask)
96 { 140 {
97 // TODO: send a real allottedTime here. 141 // TODO: send a real allottedTime here.
98 m_mainThread->postTask(new MainThreadIdleTaskAdapter(idleTask, 0)); 142 m_mainThread->postTask(new MainThreadIdleTaskAdapter(idleTask, 0, location)) ;
99 } 143 }
100 144
101 void Scheduler::postTask(const TraceLocation& location, const Task& task) 145 void Scheduler::postTask(const TraceLocation& location, const Task& task)
102 { 146 {
103 scheduleTask(location, task); 147 m_mainThread->postTask(new MainThreadPendingTaskRunner(task, location));
104 } 148 }
105 149
106 void Scheduler::postInputTask(const TraceLocation& location, const Task& task) 150 void Scheduler::postInputTask(const TraceLocation& location, const Task& task)
107 { 151 {
108 scheduleTask(location, task); 152 Locker<Mutex> lock(m_pendingTasksMutex);
153 m_pendingInputTasks.append(TracedTask(task, location));
154 atomicIncrement(&m_highPriotityTaskCount);
155 maybePostMainThreadPendingHighPriorityTaskRunner();
109 } 156 }
110 157
111 void Scheduler::postCompositorTask(const TraceLocation& location, const Task& ta sk) 158 void Scheduler::postCompositorTask(const TraceLocation& location, const Task& ta sk)
112 { 159 {
113 scheduleTask(location, task); 160 Locker<Mutex> lock(m_pendingTasksMutex);
161 m_pendingCompositorTasks.append(TracedTask(task, location));
162 atomicIncrement(&m_highPriotityTaskCount);
163 maybePostMainThreadPendingHighPriorityTaskRunner();
114 } 164 }
115 165
116 void Scheduler::postIdleTask(const IdleTask& idleTask) 166 void Scheduler::postIdleTask(const TraceLocation& location, const IdleTask& idle Task)
117 { 167 {
118 scheduleIdleTask(idleTask); 168 scheduleIdleTask(location, idleTask);
119 } 169 }
120 170
121 void Scheduler::tickSharedTimer() 171 void Scheduler::tickSharedTimer()
122 { 172 {
123 TRACE_EVENT0("blink", "Scheduler::tickSharedTimer"); 173 TRACE_EVENT0("blink", "Scheduler::tickSharedTimer");
174
175 // Run any high priority tasks that are queued up, otherwise the blink timer s will yield immediately.
176 runHighPriorityTasks();
124 m_sharedTimerFunction(); 177 m_sharedTimerFunction();
178
179 // The blink timers may have just yielded, so run any high priority tasks th at where queued up
180 // while the blink timers were executing.
181 runHighPriorityTasks();
182 }
183
184 void Scheduler::runHighPriorityTasks()
185 {
186 TRACE_EVENT0("blink", "Scheduler::runHighPriorityTasks");
187
188 m_pendingTasksMutex.lock();
189 Deque<TracedTask>& inputTasks = m_pendingInputTasks.swapBuffers();
eseidel 2014/08/11 17:02:36 This is kinda neat.
alexclarke 2014/08/12 11:37:02 Acknowledged.
190 Deque<TracedTask>& compositorTasks = m_pendingCompositorTasks.swapBuffers();
191 m_pendingTasksMutex.unlock();
192
193 for (;;) {
194 if (!inputTasks.isEmpty()) {
195 inputTasks.takeFirst().run();
196 atomicDecrement(&m_highPriotityTaskCount);
197 continue;
198 }
199
200 if (compositorTasks.isEmpty())
201 break;
202 compositorTasks.takeFirst().run();
203 atomicDecrement(&m_highPriotityTaskCount);
204 }
205 }
206
207 void Scheduler::incrementMainThreadTaskRunnerCount()
208 {
209 atomicIncrement(&m_mainThreadTaskRunnerCount);
210 }
211
212 void Scheduler::decrementMainThreadTaskRunnerCount()
213 {
214 atomicDecrement(&m_mainThreadTaskRunnerCount);
215 }
216
217 void Scheduler::maybePostMainThreadPendingHighPriorityTaskRunner()
218 {
219 // Only post a task if there isn't a task already in flight.
220 if (acquireLoad(&m_mainThreadTaskRunnerCount))
221 return;
222
223 m_mainThread->postTask(new MainThreadPendingHighPriorityTaskRunner());
125 } 224 }
126 225
127 void Scheduler::sharedTimerAdapter() 226 void Scheduler::sharedTimerAdapter()
128 { 227 {
129 shared()->tickSharedTimer(); 228 shared()->tickSharedTimer();
130 } 229 }
131 230
132 void Scheduler::setSharedTimerFiredFunction(void (*function)()) 231 void Scheduler::setSharedTimerFiredFunction(void (*function)())
133 { 232 {
134 m_sharedTimerFunction = function; 233 m_sharedTimerFunction = function;
135 blink::Platform::current()->setSharedTimerFiredFunction(function ? &Schedule r::sharedTimerAdapter : nullptr); 234 blink::Platform::current()->setSharedTimerFiredFunction(function ? &Schedule r::sharedTimerAdapter : nullptr);
136 } 235 }
137 236
138 void Scheduler::setSharedTimerFireInterval(double interval) 237 void Scheduler::setSharedTimerFireInterval(double interval)
139 { 238 {
140 blink::Platform::current()->setSharedTimerFireInterval(interval); 239 blink::Platform::current()->setSharedTimerFireInterval(interval);
141 } 240 }
142 241
143 void Scheduler::stopSharedTimer() 242 void Scheduler::stopSharedTimer()
144 { 243 {
145 blink::Platform::current()->stopSharedTimer(); 244 blink::Platform::current()->stopSharedTimer();
146 } 245 }
147 246
148 bool Scheduler::shouldYieldForHighPriorityWork() 247 bool Scheduler::shouldYieldForHighPriorityWork()
149 { 248 {
150 return false; 249 return acquireLoad(&m_highPriotityTaskCount) != 0;
eseidel 2014/08/11 17:02:36 Is it concerning that this is being called often?
alexclarke 2014/08/12 11:37:02 Ultimately if we refactor all the blink timers we
250 }
251
252 void Scheduler::TracedTask::run()
253 {
254 TRACE_EVENT2("blink", "TracedTask::run",
255 "src_file", m_location.fileName(),
256 "src_func", m_location.functionName());
257 m_task();
151 } 258 }
152 259
153 } // namespace blink 260 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698