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

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 a missing #include 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
« 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/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/MainThread.h"
14 #include "wtf/ThreadingPrimitives.h"
15
13 16
14 namespace blink { 17 namespace blink {
15 18
16 namespace { 19 namespace {
17 20
18 class MainThreadTaskAdapter : public blink::WebThread::Task { 21 // Can be created from any thread.
22 // Note if the scheduler gets shutdown, this may be run after.
23 class MainThreadIdleTaskAdapter : public WebThread::Task {
19 public: 24 public:
20 explicit MainThreadTaskAdapter(const TraceLocation& location, const Schedule r::Task& task) 25 MainThreadIdleTaskAdapter(const Scheduler::IdleTask& idleTask, double allott edTimeMs, const TraceLocation& location)
21 : m_location(location) 26 : m_idleTask(idleTask)
22 , m_task(task) 27 , m_allottedTimeMs(allottedTimeMs)
28 , m_location(location)
23 { 29 {
24 } 30 }
25 31
26 // WebThread::Task implementation. 32 // WebThread::Task implementation.
27 virtual void run() OVERRIDE 33 virtual void run() OVERRIDE
28 { 34 {
29 TRACE_EVENT2("blink", "MainThreadTaskAdapter::run", 35 TRACE_EVENT2("blink", "MainThreadIdleTaskAdapter::run",
30 "src_file", m_location.fileName(), 36 "src_file", m_location.fileName(),
31 "src_func", m_location.functionName()); 37 "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); 38 m_idleTask(m_allottedTimeMs);
53 } 39 }
54 40
55 private: 41 private:
56 Scheduler::IdleTask m_idleTask; 42 Scheduler::IdleTask m_idleTask;
57 double m_allottedTimeMs; 43 double m_allottedTimeMs;
44 TraceLocation m_location;
58 }; 45 };
59 46
60 } 47 } // namespace
48
49 // Typically only created from compositor or render threads.
50 // Note if the scheduler gets shutdown, this may be run after.
51 class Scheduler::MainThreadPendingHighPriorityTaskRunner : public WebThread::Tas k {
52 public:
53 MainThreadPendingHighPriorityTaskRunner()
54 {
55 ASSERT(Scheduler::shared());
56 }
57
58 // WebThread::Task implementation.
59 virtual void run() OVERRIDE
60 {
61 Scheduler* scheduler = Scheduler::shared();
62 // FIXME: This check should't be necessary, tasks should not outlive bli nk.
63 ASSERT(scheduler);
64 if (!scheduler)
65 return;
66 scheduler->runHighPriorityTasks();
67 }
68 };
69
70
71 // Can be created from any thread.
72 // Note if the scheduler gets shutdown, this may be run after.
73 class Scheduler::MainThreadPendingTaskRunner : public WebThread::Task {
74 public:
75 MainThreadPendingTaskRunner(
76 const Scheduler::Task& task, const TraceLocation& location)
77 : m_task(task, location)
78 {
79 ASSERT(Scheduler::shared());
80 }
81
82 // WebThread::Task implementation.
83 virtual void run() OVERRIDE
84 {
85 Scheduler* scheduler = Scheduler::shared();
86 // FIXME: This check should't be necessary, tasks should not outlive bli nk.
87 ASSERT(scheduler);
88 if (scheduler)
89 Scheduler::shared()->runHighPriorityTasks();
90 m_task.run();
91 }
92
93 Scheduler::TracedTask m_task;
94 };
61 95
62 Scheduler* Scheduler::s_sharedScheduler = nullptr; 96 Scheduler* Scheduler::s_sharedScheduler = nullptr;
63 97
64 void Scheduler::initializeOnMainThread() 98 void Scheduler::initializeOnMainThread()
65 { 99 {
66 s_sharedScheduler = new Scheduler(); 100 s_sharedScheduler = new Scheduler();
67 } 101 }
68 102
69 void Scheduler::shutdown() 103 void Scheduler::shutdown()
70 { 104 {
71 delete s_sharedScheduler; 105 delete s_sharedScheduler;
72 s_sharedScheduler = nullptr; 106 s_sharedScheduler = nullptr;
73 } 107 }
74 108
75 Scheduler* Scheduler::shared() 109 Scheduler* Scheduler::shared()
76 { 110 {
77 return s_sharedScheduler; 111 return s_sharedScheduler;
78 } 112 }
79 113
80 Scheduler::Scheduler() 114 Scheduler::Scheduler()
81 : m_mainThread(blink::Platform::current()->currentThread()) 115 : m_sharedTimerFunction(nullptr)
82 , m_sharedTimerFunction(nullptr) 116 , m_mainThread(blink::Platform::current()->currentThread())
117 , m_highPriorityTaskCount(0)
83 { 118 {
84 } 119 }
85 120
86 Scheduler::~Scheduler() 121 Scheduler::~Scheduler()
87 { 122 {
123 while (hasPendingHighPriorityWork()) {
124 runHighPriorityTasks();
125 }
88 } 126 }
89 127
90 void Scheduler::scheduleTask(const TraceLocation& location, const Task& task) 128 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 { 129 {
97 // TODO: send a real allottedTime here. 130 // TODO: send a real allottedTime here.
98 m_mainThread->postTask(new MainThreadIdleTaskAdapter(idleTask, 0)); 131 m_mainThread->postTask(new MainThreadIdleTaskAdapter(idleTask, 0, location)) ;
99 } 132 }
100 133
101 void Scheduler::postTask(const TraceLocation& location, const Task& task) 134 void Scheduler::postTask(const TraceLocation& location, const Task& task)
102 { 135 {
103 scheduleTask(location, task); 136 m_mainThread->postTask(new MainThreadPendingTaskRunner(task, location));
104 } 137 }
105 138
106 void Scheduler::postInputTask(const TraceLocation& location, const Task& task) 139 void Scheduler::postInputTask(const TraceLocation& location, const Task& task)
107 { 140 {
108 scheduleTask(location, task); 141 Locker<Mutex> lock(m_pendingTasksMutex);
142 m_pendingInputTasks.append(TracedTask(task, location));
143 atomicIncrement(&m_highPriorityTaskCount);
144 m_mainThread->postTask(new MainThreadPendingHighPriorityTaskRunner());
109 } 145 }
110 146
111 void Scheduler::postCompositorTask(const TraceLocation& location, const Task& ta sk) 147 void Scheduler::postCompositorTask(const TraceLocation& location, const Task& ta sk)
112 { 148 {
113 scheduleTask(location, task); 149 Locker<Mutex> lock(m_pendingTasksMutex);
150 m_pendingCompositorTasks.append(TracedTask(task, location));
151 atomicIncrement(&m_highPriorityTaskCount);
152 m_mainThread->postTask(new MainThreadPendingHighPriorityTaskRunner());
114 } 153 }
115 154
116 void Scheduler::postIdleTask(const IdleTask& idleTask) 155 void Scheduler::postIdleTask(const TraceLocation& location, const IdleTask& idle Task)
117 { 156 {
118 scheduleIdleTask(idleTask); 157 scheduleIdleTask(location, idleTask);
119 } 158 }
120 159
121 void Scheduler::tickSharedTimer() 160 void Scheduler::tickSharedTimer()
122 { 161 {
123 TRACE_EVENT0("blink", "Scheduler::tickSharedTimer"); 162 TRACE_EVENT0("blink", "Scheduler::tickSharedTimer");
163
164 // Run any high priority tasks that are queued up, otherwise the blink timer s will yield immediately.
165 runHighPriorityTasks();
124 m_sharedTimerFunction(); 166 m_sharedTimerFunction();
167
168 // The blink timers may have just yielded, so run any high priority tasks th at where queued up
169 // while the blink timers were executing.
170 runHighPriorityTasks();
171 }
172
173 void Scheduler::runHighPriorityTasks()
174 {
175 ASSERT(isMainThread());
176 TRACE_EVENT0("blink", "Scheduler::runHighPriorityTasks");
177
178 // These locks guard against another thread posting input or compositor task s while we swap the buffers.
179 // One the buffers have been swapped we can safely access the returned deque without having to lock.
180 m_pendingTasksMutex.lock();
181 Deque<TracedTask>& inputTasks = m_pendingInputTasks.swapBuffers();
182 Deque<TracedTask>& compositorTasks = m_pendingCompositorTasks.swapBuffers();
183 m_pendingTasksMutex.unlock();
184
185 int highPriorityTasksExecuted = 0;
186 while (!inputTasks.isEmpty()) {
187 inputTasks.takeFirst().run();
188 highPriorityTasksExecuted++;
189 }
190
191 while (!compositorTasks.isEmpty()) {
192 compositorTasks.takeFirst().run();
193 highPriorityTasksExecuted++;
194 }
195
196 int highPriorityTaskCount = atomicSubtract(&m_highPriorityTaskCount, highPri orityTasksExecuted);
197 ASSERT_UNUSED(highPriorityTaskCount, highPriorityTaskCount >= 0);
125 } 198 }
126 199
127 void Scheduler::sharedTimerAdapter() 200 void Scheduler::sharedTimerAdapter()
128 { 201 {
129 shared()->tickSharedTimer(); 202 shared()->tickSharedTimer();
130 } 203 }
131 204
132 void Scheduler::setSharedTimerFiredFunction(void (*function)()) 205 void Scheduler::setSharedTimerFiredFunction(void (*function)())
133 { 206 {
134 m_sharedTimerFunction = function; 207 m_sharedTimerFunction = function;
135 blink::Platform::current()->setSharedTimerFiredFunction(function ? &Schedule r::sharedTimerAdapter : nullptr); 208 blink::Platform::current()->setSharedTimerFiredFunction(function ? &Schedule r::sharedTimerAdapter : nullptr);
136 } 209 }
137 210
138 void Scheduler::setSharedTimerFireInterval(double interval) 211 void Scheduler::setSharedTimerFireInterval(double interval)
139 { 212 {
140 blink::Platform::current()->setSharedTimerFireInterval(interval); 213 blink::Platform::current()->setSharedTimerFireInterval(interval);
141 } 214 }
142 215
143 void Scheduler::stopSharedTimer() 216 void Scheduler::stopSharedTimer()
144 { 217 {
145 blink::Platform::current()->stopSharedTimer(); 218 blink::Platform::current()->stopSharedTimer();
146 } 219 }
147 220
148 bool Scheduler::shouldYieldForHighPriorityWork() 221 bool Scheduler::shouldYieldForHighPriorityWork() const
149 { 222 {
150 return false; 223 return hasPendingHighPriorityWork();
224 }
225
226 bool Scheduler::hasPendingHighPriorityWork() const
227 {
228 // This method is expected to be run on the main thread, but the high priori ty tasks will be posted by
229 // other threads. We could use locks here, but this function is (sometimes) called a lot by
230 // ThreadTimers::sharedTimerFiredInternal so we decided to use atomics + bar rier loads here which
231 // should be cheaper.
232 // NOTE it's possible the barrier read is overkill here, since delayed yield ing isn't a big deal.
233 return acquireLoad(&m_highPriorityTaskCount) != 0;
234 }
235
236 void Scheduler::TracedTask::run()
237 {
238 TRACE_EVENT2("blink", "TracedTask::run",
239 "src_file", m_location.fileName(),
240 "src_func", m_location.functionName());
241 m_task();
151 } 242 }
152 243
153 } // namespace blink 244 } // 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