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

Unified 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: Rebased. 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 side-by-side diff with in-line comments
Download patch
Index: Source/core/workers/WorkerThreadTest.cpp
diff --git a/Source/core/workers/WorkerThreadTest.cpp b/Source/core/workers/WorkerThreadTest.cpp
index 5f9270a37db506064d5faf65a6e05adbe42f0fea..b070b123daa6c205a86efaba85ad9880adde6477 100644
--- a/Source/core/workers/WorkerThreadTest.cpp
+++ b/Source/core/workers/WorkerThreadTest.cpp
@@ -9,6 +9,7 @@
#include "core/workers/WorkerReportingProxy.h"
#include "core/workers/WorkerThreadStartupData.h"
#include "platform/NotImplemented.h"
+#include "public/platform/WebScheduler.h"
#include "public/platform/WebWaitableEvent.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -97,6 +98,8 @@ public:
return *m_thread;
}
+ MOCK_METHOD1(doIdleGc, bool(double deadlineSeconds));
+
PassRefPtrWillBeRawPtr<WorkerGlobalScope> createWorkerGlobalScope(PassOwnPtr<WorkerThreadStartupData> startupData) override
{
return adoptRefWillBeNoop(new FakeWorkerGlobalScope(startupData->m_scriptURL, startupData->m_userAgent, this, startupData->m_starterOrigin, startupData->m_workerClients.release()));
@@ -106,6 +109,30 @@ private:
OwnPtr<WebThreadSupportingGC> m_thread;
};
+class WakeupTask : public WebThread::Task {
+public:
+ WakeupTask() { }
+
+ ~WakeupTask() override { }
+
+ void run() override { }
+};
+
+class PostDelayedWakeupTask : public WebThread::Task {
+public:
+ PostDelayedWakeupTask(WebScheduler* scheduler, long long delay) : m_scheduler(scheduler), m_delay(delay) { }
+
+ ~PostDelayedWakeupTask() override { }
+
+ void run() override
+ {
+ m_scheduler->postTimerTask(FROM_HERE, new WakeupTask(), m_delay);
+ }
+
+ WebScheduler* m_scheduler; // Not owned.
+ long long m_delay;
+};
+
class SignalTask : public WebThread::Task {
public:
SignalTask(WebWaitableEvent* completionEvent) : m_completionEvent(completionEvent) { }
@@ -161,6 +188,17 @@ public:
completionEvent->wait();
}
+ void postWakeUpTask(long long waitMs)
+ {
+ WebScheduler* scheduler = m_workerThread->backingThread().platformThread().scheduler();
+
+ // The idle task will get posted on an after wake up queue, so we need another task
+ // posted at the right time to wake the system up. We don't know the right delay here
+ // since the thread can take a variable length of time to be responsive, however this
+ // isn't a problem when posting a delayed task from within a task on the worker thread.
+ scheduler->postLoadingTask(FROM_HERE, new PostDelayedWakeupTask(scheduler, waitMs));
+ }
+
protected:
void ExpectWorkerLifetimeReportingCalls()
{
@@ -182,4 +220,158 @@ TEST_F(WorkerThreadTest, StartAndStop)
m_workerThread->terminateAndWait();
}
+TEST_F(WorkerThreadTest, GcOccursWhileIdle)
+{
+ OwnPtr<WebWaitableEvent> gcDone = adoptPtr(Platform::current()->createWaitableEvent());
+
+ ON_CALL(*m_workerThread, doIdleGc(_)).WillByDefault(Invoke(
+ [&gcDone](double)
+ {
+ gcDone->signal();
+ return false;
+ }));
+
+ EXPECT_CALL(*m_workerThread, doIdleGc(_)).Times(1);
+
+ startAndWaitForInit();
+ postWakeUpTask(310ul); // 10ms after the quiescent period ends.
+
+ gcDone->wait();
+ m_workerThread->terminateAndWait();
+};
+
+class RepeatingTask : public WebThread::Task {
+public:
+ RepeatingTask(WebScheduler* scheduler, WebWaitableEvent* completion)
+ : RepeatingTask(scheduler, completion, 0) { }
+
+ ~RepeatingTask() override { }
+
+ void run() override
+ {
+ m_taskCount++;
+ if (m_taskCount == 10)
+ m_completion->signal();
+
+ m_scheduler->postTimerTask(
+ FROM_HERE, new RepeatingTask(m_scheduler, m_completion, m_taskCount), 50ul);
+ m_scheduler->postLoadingTask(FROM_HERE, new WakeupTask());
+
+ }
+
+private:
+ RepeatingTask(WebScheduler* scheduler, WebWaitableEvent* completion, int taskCount)
+ : m_scheduler(scheduler)
+ , m_completion(completion)
+ , m_taskCount(taskCount)
+ { }
+
+ WebScheduler* m_scheduler; // Not owned.
+ WebWaitableEvent* m_completion;
+ int m_taskCount;
+};
+
+TEST_F(WorkerThreadTest, GcDoesNotOccurIfGapBetweenDelayedTasksIsTooSmall)
+{
+ OwnPtr<WebWaitableEvent> completion = adoptPtr(Platform::current()->createWaitableEvent());
+
+ EXPECT_CALL(*m_workerThread, doIdleGc(_)).Times(0);
+
+ startAndWaitForInit();
+
+ WebScheduler* scheduler = m_workerThread->backingThread().platformThread().scheduler();
+
+ // Post a repeating task that should prevent any GC from happening.
+ scheduler->postLoadingTask(FROM_HERE, new RepeatingTask(scheduler, completion.get()));
+
+ completion->wait();
+
+ // Make sure doIdleGc has not been called by this stage.
+ Mock::VerifyAndClearExpectations(m_workerThread.get());
+
+ m_workerThread->terminateAndWait();
+}
+
+TEST_F(WorkerThreadTest, LongGcDeadline_NoFutureTasks)
+{
+ OwnPtr<WebWaitableEvent> gcDone = adoptPtr(Platform::current()->createWaitableEvent());
+ double deadlineLength = 0;
+
+ ON_CALL(*m_workerThread, doIdleGc(_)).WillByDefault(Invoke(
+ [&gcDone, &deadlineLength](double deadline)
+ {
+ gcDone->signal();
+ deadlineLength = deadline -Platform::current()->monotonicallyIncreasingTime();
+ return false;
+ }));
+
+ EXPECT_CALL(*m_workerThread, doIdleGc(_)).Times(1);
+
+ startAndWaitForInit();
+ postWakeUpTask(310ul);
+
+ gcDone->wait();
+
+ // The deadline should be close to 1s in duration if there are no tasks that need to run soon.
+ EXPECT_GT(deadlineLength, 0.9);
+
+ m_workerThread->terminateAndWait();
+}
+
+TEST_F(WorkerThreadTest, LongGcDeadline_NextTaskAfterIdlePeriod)
+{
+ OwnPtr<WebWaitableEvent> gcDone = adoptPtr(Platform::current()->createWaitableEvent());
+ double deadlineLength = 0;
+
+ ON_CALL(*m_workerThread, doIdleGc(_)).WillByDefault(Invoke(
+ [&gcDone, &deadlineLength](double deadline)
+ {
+ gcDone->signal();
+ deadlineLength = deadline -Platform::current()->monotonicallyIncreasingTime();
+ return false;
+ }));
+
+ EXPECT_CALL(*m_workerThread, doIdleGc(_)).Times(1);
+
+ startAndWaitForInit();
+ postWakeUpTask(310ul);
+ postWakeUpTask(675ul); // Task that runs shortly after the 50ms idle period ends.
+
+ gcDone->wait();
+
+ // The worker thread calls canExceedIdleDeadlineIfRequired which only considers if
+ // there are any delayed tasks scheduled for the current long idle period. Since the
+ // next task is in the following idle period, a long gc deadline is allowed.
+ EXPECT_GT(deadlineLength, 0.9);
+
+ m_workerThread->terminateAndWait();
+}
+
+TEST_F(WorkerThreadTest, ShortGcDeadline)
+{
+ OwnPtr<WebWaitableEvent> gcDone = adoptPtr(Platform::current()->createWaitableEvent());
+ double deadlineLength = 0;
+
+ ON_CALL(*m_workerThread, doIdleGc(_)).WillByDefault(Invoke(
+ [&gcDone, &deadlineLength](double deadline)
+ {
+ gcDone->signal();
+ deadlineLength = deadline - Platform::current()->monotonicallyIncreasingTime();
+ return false;
+ }));
+
+ EXPECT_CALL(*m_workerThread, doIdleGc(_)).Times(1);
+
+ startAndWaitForInit();
+ postWakeUpTask(310ul);
+ postWakeUpTask(625ul); // Task that runs during the idle period.
+
+ gcDone->wait();
+
+ // The deadline should be < 50ms if there's a task that needs to run during the idle period.
+ EXPECT_LT(deadlineLength, 0.025);
+
+ m_workerThread->terminateAndWait();
+}
+
} // namespace blink
« 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