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

Side by Side Diff: Source/core/workers/WorkerThreadTest.cpp

Issue 1130413003: Schedule garbage collection on worker threads using idle tasks (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 5 years, 7 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
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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 "core/workers/WorkerThread.h" 6 #include "core/workers/WorkerThread.h"
7 7
8 #include "core/inspector/ConsoleMessage.h" 8 #include "core/inspector/ConsoleMessage.h"
9 #include "core/workers/WorkerReportingProxy.h" 9 #include "core/workers/WorkerReportingProxy.h"
10 #include "core/workers/WorkerThreadStartupData.h" 10 #include "core/workers/WorkerThreadStartupData.h"
11 #include "public/platform/WebScheduler.h"
11 #include "wtf/ThreadingPrimitives.h" 12 #include "wtf/ThreadingPrimitives.h"
12 #include <gmock/gmock.h> 13 #include <gmock/gmock.h>
13 #include <gtest/gtest.h> 14 #include <gtest/gtest.h>
14 15
15 using testing::_; 16 using testing::_;
16 using testing::Invoke; 17 using testing::Invoke;
17 using testing::Return; 18 using testing::Return;
18 using testing::Mock; 19 using testing::Mock;
19 20
20 namespace blink { 21 namespace blink {
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
94 } 95 }
95 96
96 ~WorkerThreadForTest() override { } 97 ~WorkerThreadForTest() override { }
97 98
98 // WorkerThread implementation: 99 // WorkerThread implementation:
99 WebThreadSupportingGC& backingThread() override 100 WebThreadSupportingGC& backingThread() override
100 { 101 {
101 return *m_thread; 102 return *m_thread;
102 } 103 }
103 104
105 MOCK_METHOD1(doIdleGc, bool(double deadlineSeconds));
106
104 PassRefPtrWillBeRawPtr<WorkerGlobalScope> createWorkerGlobalScope(PassOwnPtr <WorkerThreadStartupData> startupData) override 107 PassRefPtrWillBeRawPtr<WorkerGlobalScope> createWorkerGlobalScope(PassOwnPtr <WorkerThreadStartupData> startupData) override
105 { 108 {
106 return adoptRefWillBeNoop(new FakeWorkerGlobalScope(startupData->m_scrip tURL, startupData->m_userAgent, this, startupData->m_starterOrigin, startupData- >m_workerClients.release())); 109 return adoptRefWillBeNoop(new FakeWorkerGlobalScope(startupData->m_scrip tURL, startupData->m_userAgent, this, startupData->m_starterOrigin, startupData- >m_workerClients.release()));
107 } 110 }
108 111
109 private: 112 private:
110 OwnPtr<WebThreadSupportingGC> m_thread; 113 OwnPtr<WebThreadSupportingGC> m_thread;
111 }; 114 };
112 115
116 class WakeupTask : public WebThread::Task {
117 public:
118 WakeupTask() { }
119
120 ~WakeupTask() override { }
121
122 void run() override { }
123 };
124
125 class PostDelayedWakeupTask : public WebThread::Task {
126 public:
127 PostDelayedWakeupTask(WebScheduler* scheduler, long long delay) : m_schedule r(scheduler), m_delay(delay) { }
128
129 ~PostDelayedWakeupTask() override { }
130
131 void run() override
132 {
133 m_scheduler->postTimerTask(FROM_HERE, new WakeupTask(), m_delay);
134 }
135
136 WebScheduler* m_scheduler; // NOT OWNED
137 long long m_delay;
138 };
139
113 class SignalTask : public WebThread::Task { 140 class SignalTask : public WebThread::Task {
114 public: 141 public:
115 SignalTask(ThreadCondition* completion, Mutex* mutex) : m_completion(complet ion), m_mutex(mutex) { } 142 SignalTask(ThreadCondition* completion, Mutex* mutex) : m_completion(complet ion), m_mutex(mutex) { }
116 143
117 ~SignalTask() override { } 144 ~SignalTask() override { }
118 145
119 void run() override 146 void run() override
120 { 147 {
121 WTF::Locker<Mutex> lock(*m_mutex); 148 WTF::Locker<Mutex> lock(*m_mutex);
122 m_completion->signal(); 149 m_completion->signal();
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
165 192
166 m_workerThread->start(); 193 m_workerThread->start();
167 m_workerThread->backingThread().postTask(FROM_HERE, new SignalTask(&comp lete, &mutex)); 194 m_workerThread->backingThread().postTask(FROM_HERE, new SignalTask(&comp lete, &mutex));
168 195
169 { 196 {
170 WTF::Locker<Mutex> lock(mutex); 197 WTF::Locker<Mutex> lock(mutex);
171 complete.wait(mutex); 198 complete.wait(mutex);
172 } 199 }
173 } 200 }
174 201
202 void postWakeUpTask(long long waitMs)
203 {
204 WebScheduler* scheduler = m_workerThread->backingThread().platformThread ().scheduler();
205
206 // The idle task will get posted on an after wake up queue, so we need a nother task
207 // posted at the right time to wake the system up. We don't know the ri ght delay here
208 // since the thread can take a variable length of time to be responsive, however this
209 // isn't a problem when posting a delayed task from within a task on the worker thread.
210 scheduler->postLoadingTask(FROM_HERE, new PostDelayedWakeupTask(schedule r, waitMs));
211 }
212
175 protected: 213 protected:
176 void ExpectWorkerLifetimeReportingCalls() 214 void ExpectWorkerLifetimeReportingCalls()
177 { 215 {
178 EXPECT_CALL(*m_mockWorkerReportingProxy, workerGlobalScopeStarted(_)).Ti mes(1); 216 EXPECT_CALL(*m_mockWorkerReportingProxy, workerGlobalScopeStarted(_)).Ti mes(1);
179 EXPECT_CALL(*m_mockWorkerReportingProxy, didEvaluateWorkerScript(true)). Times(1); 217 EXPECT_CALL(*m_mockWorkerReportingProxy, didEvaluateWorkerScript(true)). Times(1);
180 EXPECT_CALL(*m_mockWorkerReportingProxy, workerThreadTerminated()).Times (1); 218 EXPECT_CALL(*m_mockWorkerReportingProxy, workerThreadTerminated()).Times (1);
181 EXPECT_CALL(*m_mockWorkerReportingProxy, willDestroyWorkerGlobalScope()) .Times(1); 219 EXPECT_CALL(*m_mockWorkerReportingProxy, willDestroyWorkerGlobalScope()) .Times(1);
182 } 220 }
183 221
184 RefPtr<SecurityOrigin> m_securityOrigin; 222 RefPtr<SecurityOrigin> m_securityOrigin;
185 OwnPtr<MockWorkerLoaderProxyProvider> m_mockWorkerLoaderProxyProvider; 223 OwnPtr<MockWorkerLoaderProxyProvider> m_mockWorkerLoaderProxyProvider;
186 OwnPtr<MockWorkerReportingProxy> m_mockWorkerReportingProxy; 224 OwnPtr<MockWorkerReportingProxy> m_mockWorkerReportingProxy;
187 RefPtr<WorkerThreadForTest> m_workerThread; 225 RefPtr<WorkerThreadForTest> m_workerThread;
188 }; 226 };
189 227
190 TEST_F(WorkerThreadTest, StartAndStop) 228 TEST_F(WorkerThreadTest, StartAndStop)
191 { 229 {
192 startAndWaitForInit(); 230 startAndWaitForInit();
193 m_workerThread->terminateAndWait(); 231 m_workerThread->terminateAndWait();
194 } 232 }
195 233
234 TEST_F(WorkerThreadTest, GcOccursWhileIdle)
235 {
236 ThreadCondition gcDone;
237 Mutex mutex;
238
239 ON_CALL(*m_workerThread, doIdleGc(_)).WillByDefault(Invoke(
240 [&gcDone, &mutex](double)
241 {
242 WTF::Locker<Mutex> lock(mutex);
243 gcDone.signal();
244 return false;
245 }));
246
247 EXPECT_CALL(*m_workerThread, doIdleGc(_)).Times(1);
248
249 startAndWaitForInit();
250 postWakeUpTask(310ul); // 10ms after the quiescent period ends.
251
252 {
253 WTF::Locker<Mutex> lock(mutex);
254 gcDone.wait(mutex);
255 }
256
257 m_workerThread->terminateAndWait();
258 };
259
260 class RepeatingTask : public WebThread::Task {
261 public:
262 RepeatingTask(WebScheduler* scheduler, ThreadCondition* completion, Mutex* m utex)
263 : RepeatingTask(scheduler, completion, mutex, 0) { }
264
265 ~RepeatingTask() override { }
266
267 void run() override
268 {
269 m_taskCount++;
270 if (m_taskCount == 10) {
271 WTF::Locker<Mutex> lock(*m_mutex);
272 m_completion->signal();
273 }
274
275 m_scheduler->postTimerTask(
276 FROM_HERE, new RepeatingTask(m_scheduler, m_completion, m_mutex, m_t askCount), 50ul);
277 m_scheduler->postLoadingTask(FROM_HERE, new WakeupTask());
278
279 }
280
281 private:
282 RepeatingTask(WebScheduler* scheduler, ThreadCondition* completion, Mutex* m utex, int taskCount)
283 : m_scheduler(scheduler)
284 , m_completion(completion)
285 , m_mutex(mutex)
286 , m_taskCount(taskCount)
287 { }
288
289 WebScheduler* m_scheduler; // NOT OWNED
290 ThreadCondition* m_completion;
291 Mutex* m_mutex;
292 int m_taskCount;
293 };
294
295 TEST_F(WorkerThreadTest, GcDoesNotOccurIfGapBetweenDelayedTasksIsTooSmall)
296 {
297 ThreadCondition completion;
298 Mutex mutex;
299
300 EXPECT_CALL(*m_workerThread, doIdleGc(_)).Times(0);
301
302 startAndWaitForInit();
303
304 WebScheduler* scheduler = m_workerThread->backingThread().platformThread().s cheduler();
305
306 // Post a repeating task that should prevent any GC from happening.
307 scheduler->postLoadingTask(FROM_HERE, new RepeatingTask(scheduler, &completi on, &mutex));
308
309 {
310 WTF::Locker<Mutex> lock(mutex);
311 completion.wait(mutex);
312 }
313
314 // Make sure doIdleGc has not been called by this stage.
315 Mock::VerifyAndClearExpectations(m_workerThread.get());
316
317 m_workerThread->terminateAndWait();
318 }
319
320 TEST_F(WorkerThreadTest, LongGcDeadline_NoFutureTasks)
321 {
322 ThreadCondition gcDone;
323 Mutex mutex;
324 double deadlineLength = 0;
325
326 ON_CALL(*m_workerThread, doIdleGc(_)).WillByDefault(Invoke(
327 [&gcDone, &mutex, &deadlineLength](double deadline)
328 {
329 WTF::Locker<Mutex> lock(mutex);
330 gcDone.signal();
331 deadlineLength = deadline -Platform::current()->monotonicallyIncreas ingTime();
332 return false;
333 }));
334
335 EXPECT_CALL(*m_workerThread, doIdleGc(_)).Times(1);
336
337 startAndWaitForInit();
338 postWakeUpTask(310ul);
339
340 {
341 WTF::Locker<Mutex> lock(mutex);
342 gcDone.wait(mutex);
343
344 // The deadline should be close to 1s in duration if there are no tasks that need to run soon.
345 EXPECT_GT(deadlineLength, 0.9);
346 }
347
348 m_workerThread->terminateAndWait();
349 }
350
351 TEST_F(WorkerThreadTest, LongGcDeadline_NextTaskAfterIdlePeriod)
352 {
353 ThreadCondition gcDone;
354 Mutex mutex;
355 double deadlineLength = 0;
356
357 ON_CALL(*m_workerThread, doIdleGc(_)).WillByDefault(Invoke(
358 [&gcDone, &mutex, &deadlineLength](double deadline)
359 {
360 WTF::Locker<Mutex> lock(mutex);
361 gcDone.signal();
362 deadlineLength = deadline -Platform::current()->monotonicallyIncreas ingTime();
363 return false;
364 }));
365
366 EXPECT_CALL(*m_workerThread, doIdleGc(_)).Times(1);
367
368 startAndWaitForInit();
369 postWakeUpTask(310ul);
370 postWakeUpTask(675ul); // Task that runs shortly after the 50ms idle period ends.
371
372 {
373 WTF::Locker<Mutex> lock(mutex);
374 gcDone.wait(mutex);
375
376 // The worker thread calls canExceedIdleDeadlineIfRequired which only co nsiders if
377 // there are any delayed tasks scheduled for the current long idle perio d. Since the
378 // next task is in the following idle period, a long gc deadline is allo wed.
379 EXPECT_GT(deadlineLength, 0.9);
380 }
381
382 m_workerThread->terminateAndWait();
383 }
384
385 TEST_F(WorkerThreadTest, ShortGcDeadline)
386 {
387 ThreadCondition gcDone;
388 Mutex mutex;
389 double deadlineLength = 0;
390
391 ON_CALL(*m_workerThread, doIdleGc(_)).WillByDefault(Invoke(
392 [&gcDone, &mutex, &deadlineLength](double deadline)
393 {
394 WTF::Locker<Mutex> lock(mutex);
395 gcDone.signal();
396 deadlineLength = deadline - Platform::current()->monotonicallyIncrea singTime();
397 return false;
398 }));
399
400 EXPECT_CALL(*m_workerThread, doIdleGc(_)).Times(1);
401
402 startAndWaitForInit();
403 postWakeUpTask(310ul);
404 postWakeUpTask(625ul); // Task that runs during the idle period.
405
406 {
407 WTF::Locker<Mutex> lock(mutex);
408 gcDone.wait(mutex);
409
410 // The deadline should be < 50ms if there's a task that needs to run dur ing the idle period.
411 EXPECT_LT(deadlineLength, 0.025);
412 }
413
414 m_workerThread->terminateAndWait();
415 }
416
196 } // namespace blink 417 } // namespace blink
OLDNEW
« Source/core/workers/WorkerThread.cpp ('K') | « Source/core/workers/WorkerThread.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698