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

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: Respoding to more feedback 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 public:
20 explicit MainThreadTaskAdapter(const TraceLocation& location, const Schedule r::Task& task)
21 : m_location(location)
22 , m_task(task)
23 {
24 }
25
26 // WebThread::Task implementation.
27 virtual void run() OVERRIDE
28 {
29 TRACE_EVENT2("blink", "MainThreadTaskAdapter::run",
30 "src_file", m_location.fileName(),
31 "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 { 19 class MainThreadIdleTaskAdapter : public blink::WebThread::Task {
41 public: 20 public:
42 MainThreadIdleTaskAdapter(const Scheduler::IdleTask& idleTask, double allott edTimeMs) 21 MainThreadIdleTaskAdapter(const Scheduler::IdleTask& idleTask, double allott edTimeMs)
43 : m_idleTask(idleTask) 22 : m_idleTask(idleTask)
44 , m_allottedTimeMs(allottedTimeMs) 23 , m_allottedTimeMs(allottedTimeMs)
eseidel 2014/08/07 17:18:15 Thank you for including the type in the name. :)
Sami 2014/08/07 18:22:21 +1, I wouldn't object to a clone of base/time.h's
alexclarke 2014/08/08 13:32:23 I also think that's a good idea, but lets do it in
alexclarke 2014/08/08 13:32:23 Acknowledged.
45 { 24 {
46 } 25 }
47 26
48 // WebThread::Task implementation. 27 // WebThread::Task implementation.
49 virtual void run() OVERRIDE 28 virtual void run() OVERRIDE
50 { 29 {
51 TRACE_EVENT1("blink", "MainThreadIdleTaskAdapter::run", "allottedTime", m_allottedTimeMs); 30 TRACE_EVENT1("blink", "MainThreadIdleTaskAdapter::run", "allottedTime", m_allottedTimeMs);
52 m_idleTask(m_allottedTimeMs); 31 m_idleTask(m_allottedTimeMs);
53 } 32 }
54 33
55 private: 34 private:
56 Scheduler::IdleTask m_idleTask; 35 Scheduler::IdleTask m_idleTask;
57 double m_allottedTimeMs; 36 double m_allottedTimeMs;
58 }; 37 };
59 38
60 } 39 } // namespace
40
41 class Scheduler::MainThreadPendingTaskRunner : public blink::WebThread::Task {
42 public:
43 explicit MainThreadPendingTaskRunner(Scheduler* scheduler)
44 : m_scheduler(scheduler)
45 {
46 atomicIncrement(&m_scheduler->m_mainThreadTaskRunnerCount);
47 }
48
49 ~MainThreadPendingTaskRunner()
50 {
51 atomicDecrement(&m_scheduler->m_mainThreadTaskRunnerCount);
52 }
53
54 // WebThread::Task implementation.
55 virtual void run() OVERRIDE
56 {
57 Scheduler::shared()->runPendingTasks();
58 }
59
60 Scheduler* m_scheduler; // Not owned.
61 };
61 62
62 Scheduler* Scheduler::s_sharedScheduler = nullptr; 63 Scheduler* Scheduler::s_sharedScheduler = nullptr;
63 64
64 void Scheduler::initializeOnMainThread() 65 void Scheduler::initializeOnMainThread()
65 { 66 {
66 s_sharedScheduler = new Scheduler(); 67 s_sharedScheduler = new Scheduler();
67 } 68 }
68 69
69 void Scheduler::shutdown() 70 void Scheduler::shutdown()
70 { 71 {
71 delete s_sharedScheduler; 72 delete s_sharedScheduler;
72 s_sharedScheduler = nullptr; 73 s_sharedScheduler = nullptr;
73 } 74 }
74 75
75 Scheduler* Scheduler::shared() 76 Scheduler* Scheduler::shared()
76 { 77 {
77 return s_sharedScheduler; 78 return s_sharedScheduler;
78 } 79 }
79 80
80 Scheduler::Scheduler() 81 Scheduler::Scheduler()
81 : m_mainThread(blink::Platform::current()->currentThread()) 82 : m_mainThread(blink::Platform::current()->currentThread())
82 , m_sharedTimerFunction(nullptr) 83 , m_sharedTimerFunction(nullptr)
84 , m_mainThreadTaskRunnerCount(0)
83 { 85 {
84 } 86 }
85 87
86 Scheduler::~Scheduler() 88 Scheduler::~Scheduler()
87 { 89 {
88 } 90 // We need to flush all posted tasks before exiting.
89 91 while (!m_pendingLowPriorityTasks.isEmpty())
90 void Scheduler::scheduleTask(const TraceLocation& location, const Task& task) 92 runPendingTasks();
91 {
92 m_mainThread->postTask(new MainThreadTaskAdapter(location, task));
93 } 93 }
94 94
95 void Scheduler::scheduleIdleTask(const IdleTask& idleTask) 95 void Scheduler::scheduleIdleTask(const IdleTask& idleTask)
96 { 96 {
97 // TODO: send a real allottedTime here. 97 // TODO: send a real allottedTime here.
98 m_mainThread->postTask(new MainThreadIdleTaskAdapter(idleTask, 0)); 98 m_mainThread->postTask(new MainThreadIdleTaskAdapter(idleTask, 0));
99 } 99 }
100 100
101 void Scheduler::postTask(const TraceLocation& location, const Task& task) 101 void Scheduler::postTask(const TraceLocation& location, const Task& task)
102 { 102 {
103 scheduleTask(location, task); 103 m_pendingLowPriorityTasks.append(TracedTask(task, location));
104 maybePostMainThreadPendingTaskRunner();
104 } 105 }
105 106
106 void Scheduler::postInputTask(const TraceLocation& location, const Task& task) 107 void Scheduler::postInputTask(const TraceLocation& location, const Task& task)
107 { 108 {
108 scheduleTask(location, task); 109 m_pendingInputTasks.append(TracedTask(task, location));
110 maybePostMainThreadPendingTaskRunner();
109 } 111 }
110 112
111 void Scheduler::postCompositorTask(const TraceLocation& location, const Task& ta sk) 113 void Scheduler::postCompositorTask(const TraceLocation& location, const Task& ta sk)
112 { 114 {
113 scheduleTask(location, task); 115 m_pendingCompositorTasks.append(TracedTask(task, location));
116 maybePostMainThreadPendingTaskRunner();
114 } 117 }
115 118
116 void Scheduler::postIdleTask(const IdleTask& idleTask) 119 void Scheduler::postIdleTask(const IdleTask& idleTask)
117 { 120 {
118 scheduleIdleTask(idleTask); 121 scheduleIdleTask(idleTask);
119 } 122 }
120 123
121 void Scheduler::tickSharedTimer() 124 void Scheduler::tickSharedTimer()
122 { 125 {
123 TRACE_EVENT0("blink", "Scheduler::tickSharedTimer"); 126 TRACE_EVENT0("blink", "Scheduler::tickSharedTimer");
127
128 runHighPriorityTasks();
124 m_sharedTimerFunction(); 129 m_sharedTimerFunction();
130 runHighPriorityTasks();
131 }
132
133 void Scheduler::runPendingTasks()
134 {
135 TRACE_EVENT0("blink", "Scheduler::runPendingTasks");
136
137 // Execute high priority tasks first.
138 runHighPriorityTasks();
139
140 if (!m_pendingLowPriorityTasks.runFirstTaskIfNotEmpty())
141 return;
142
143 // To avoid staving main loop tasks that don't (yet?) go through the schedul er, we only
144 // execute one low priority task rather than all of them.
145 if (!m_pendingLowPriorityTasks.isEmpty())
146 m_mainThread->postTask(new MainThreadPendingTaskRunner(this));
147 }
148
149 void Scheduler::runHighPriorityTasks()
150 {
151 TRACE_EVENT0("blink", "Scheduler::runHighPriorityTasks");
152
153 for (;;) {
154 if (m_pendingInputTasks.runFirstTaskIfNotEmpty())
155 continue;
156
157 if (!m_pendingCompositorTasks.runFirstTaskIfNotEmpty())
158 break;
159 }
160 }
161
162 void Scheduler::maybePostMainThreadPendingTaskRunner()
163 {
164 if (acquireLoad(&m_mainThreadTaskRunnerCount))
165 return;
166
167 // Note this can potentially cause a sequence of MainThreadPendingTaskRunner s to get posted
168 // if there are multiple low priority tasks to run.
169 m_mainThread->postTask(new MainThreadPendingTaskRunner(this));
125 } 170 }
126 171
127 void Scheduler::sharedTimerAdapter() 172 void Scheduler::sharedTimerAdapter()
128 { 173 {
129 shared()->tickSharedTimer(); 174 shared()->tickSharedTimer();
130 } 175 }
131 176
132 void Scheduler::setSharedTimerFiredFunction(void (*function)()) 177 void Scheduler::setSharedTimerFiredFunction(void (*function)())
133 { 178 {
134 m_sharedTimerFunction = function; 179 m_sharedTimerFunction = function;
135 blink::Platform::current()->setSharedTimerFiredFunction(function ? &Schedule r::sharedTimerAdapter : nullptr); 180 blink::Platform::current()->setSharedTimerFiredFunction(function ? &Schedule r::sharedTimerAdapter : nullptr);
136 } 181 }
137 182
138 void Scheduler::setSharedTimerFireInterval(double interval) 183 void Scheduler::setSharedTimerFireInterval(double interval)
139 { 184 {
140 blink::Platform::current()->setSharedTimerFireInterval(interval); 185 blink::Platform::current()->setSharedTimerFireInterval(interval);
141 } 186 }
142 187
143 void Scheduler::stopSharedTimer() 188 void Scheduler::stopSharedTimer()
144 { 189 {
145 blink::Platform::current()->stopSharedTimer(); 190 blink::Platform::current()->stopSharedTimer();
146 } 191 }
147 192
148 bool Scheduler::shouldYieldForHighPriorityWork() 193 bool Scheduler::shouldYieldForHighPriorityWork()
149 { 194 {
150 return false; 195 return !m_pendingInputTasks.isEmpty() || !m_pendingCompositorTasks.isEmpty() ;
196 }
197
198 void Scheduler::TracedTask::run()
199 {
200 TRACE_EVENT2("blink", "TracedTask::run",
201 "src_file", m_location.fileName(),
202 "src_func", m_location.functionName());
203 m_task();
204 }
205
206 void Scheduler::LockingTracedTaskDeque::append(const TracedTask& value)
207 {
208 Locker<Mutex> lock(m_mutex);
209 m_queue.append(value);
210 }
211
212 bool Scheduler::LockingTracedTaskDeque::isEmpty()
213 {
214 Locker<Mutex> lock(m_mutex);
215 return m_queue.isEmpty();
216 }
217
218 bool Scheduler::LockingTracedTaskDeque::runFirstTaskIfNotEmpty()
219 {
220 m_mutex.lock();
221 if (m_queue.isEmpty()) {
222 m_mutex.unlock();
223 return false;
224 }
225 TracedTask task = m_queue.takeFirst();
226 m_mutex.unlock();
227
228 task.run();
229 return true;
151 } 230 }
152 231
153 } // namespace blink 232 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698