| Index: Source/platform/scheduler/Scheduler.cpp
|
| diff --git a/Source/platform/scheduler/Scheduler.cpp b/Source/platform/scheduler/Scheduler.cpp
|
| index 4a447721f58921b8fe0500568ed583f76288b5c8..0460c36fd96a8c1b6da6681f52315c8eb7918aef 100644
|
| --- a/Source/platform/scheduler/Scheduler.cpp
|
| +++ b/Source/platform/scheduler/Scheduler.cpp
|
| @@ -10,12 +10,16 @@
|
| #include "platform/ThreadTimers.h"
|
| #include "platform/TraceEvent.h"
|
| #include "public/platform/Platform.h"
|
| +#include "public/platform/WebBeginFrameArgs.h"
|
| #include "wtf/MainThread.h"
|
| #include "wtf/ThreadingPrimitives.h"
|
|
|
|
|
| namespace blink {
|
|
|
| +// Pending low prioirty tasks have a maximum run time of 20ms per invocation of runPendingLowPriorityTasks.
|
| +const double Scheduler::s_maximumLowPrioirtyTaskExecutionTimeSeconds = 0.02;
|
| +
|
| namespace {
|
|
|
| // Can be created from any thread.
|
| @@ -63,7 +67,7 @@ public:
|
| ASSERT(scheduler);
|
| if (!scheduler)
|
| return;
|
| - scheduler->swapQueuesRunPendingTasksAndAllowHighPriorityTaskRunnerPosting();
|
| + scheduler->runPendingHighPriorityTasksAndAllowTaskRunnerPosting();
|
| }
|
| };
|
|
|
| @@ -86,13 +90,26 @@ public:
|
| // FIXME: This check should't be necessary, tasks should not outlive blink.
|
| ASSERT(scheduler);
|
| if (scheduler)
|
| - Scheduler::shared()->swapQueuesAndRunPendingTasks();
|
| + Scheduler::shared()->runPendingHighPrioirtyTasks();
|
| m_task.run();
|
| }
|
|
|
| Scheduler::TracedTask m_task;
|
| };
|
|
|
| +class Scheduler::MainThreadPendingLowPriorityTaskRunner : public WebThread::Task {
|
| +public:
|
| + virtual void run() OVERRIDE
|
| + {
|
| + Scheduler* scheduler = Scheduler::shared();
|
| + // FIXME: This check should't be necessary, tasks should not outlive blink.
|
| + ASSERT(scheduler);
|
| + if (!scheduler)
|
| + return;
|
| + scheduler->runPendingLowPriorityTasks();
|
| + }
|
| +};
|
| +
|
| Scheduler* Scheduler::s_sharedScheduler = nullptr;
|
|
|
| void Scheduler::initializeOnMainThread()
|
| @@ -114,21 +131,30 @@ Scheduler* Scheduler::shared()
|
| Scheduler::Scheduler()
|
| : m_sharedTimerFunction(nullptr)
|
| , m_mainThread(blink::Platform::current()->currentThread())
|
| + , m_compositorStart(0.0)
|
| + , m_compositorDeadline(0.0)
|
| + , m_compositorInterval(0.0)
|
| , m_highPriorityTaskCount(0)
|
| - , m_highPriorityTaskRunnerPosted(false)
|
| + , m_activeLowPrioirtyQueue(nullptr)
|
| {
|
| + m_mutexProtected.m_highPriorityTaskRunnerPosted = false;
|
| + m_mutexProtected.m_lowPriorityTaskRunnerPosted = false;
|
| }
|
|
|
| Scheduler::~Scheduler()
|
| {
|
| while (hasPendingHighPriorityWork()) {
|
| - swapQueuesAndRunPendingTasks();
|
| + runPendingHighPrioirtyTasks();
|
| }
|
| }
|
|
|
| void Scheduler::willBeginFrame(const WebBeginFrameArgs& args)
|
| {
|
| - // TODO: Use frame deadline and interval to schedule idle tasks.
|
| + ASSERT(isMainThread());
|
| +
|
| + m_compositorStart = args.lastFrameTimeMonotonic;
|
| + m_compositorDeadline = args.deadline;
|
| + m_compositorInterval = args.interval;
|
| }
|
|
|
| void Scheduler::didCommitFrameToCompositor()
|
| @@ -150,26 +176,87 @@ void Scheduler::postTask(const TraceLocation& location, const Task& task)
|
| void Scheduler::postInputTask(const TraceLocation& location, const Task& task)
|
| {
|
| Locker<Mutex> lock(m_pendingTasksMutex);
|
| - m_pendingHighPriorityTasks.append(TracedTask(task, location));
|
| + m_mutexProtected.m_pendingHighPriorityTasks.append(TracedTask(task, location));
|
| atomicIncrement(&m_highPriorityTaskCount);
|
| + TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), "PendingHighPriorityTasks", m_highPriorityTaskCount);
|
| maybePostMainThreadPendingHighPriorityTaskRunner();
|
| }
|
|
|
| void Scheduler::postCompositorTask(const TraceLocation& location, const Task& task)
|
| {
|
| Locker<Mutex> lock(m_pendingTasksMutex);
|
| - m_pendingHighPriorityTasks.append(TracedTask(task, location));
|
| + m_mutexProtected.m_pendingHighPriorityTasks.append(TracedTask(task, location));
|
| atomicIncrement(&m_highPriorityTaskCount);
|
| + TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), "PendingHighPriorityTasks", m_highPriorityTaskCount);
|
| maybePostMainThreadPendingHighPriorityTaskRunner();
|
| }
|
|
|
| +void Scheduler::postIpcTask(const TraceLocation& location, const Task& task)
|
| +{
|
| + Locker<Mutex> lock(m_pendingTasksMutex);
|
| + m_mutexProtected.m_pendingLowPriorityTasks.append(TracedTask(task, location));
|
| + TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), "PendingLowPriorityTasks",
|
| + m_mutexProtected.m_pendingLowPriorityTasks.allQueuesSize());
|
| + maybePostMainThreadPendingLowPriorityTaskRunner(Platform::current()->monotonicallyIncreasingTime());
|
| +}
|
| +
|
| void Scheduler::maybePostMainThreadPendingHighPriorityTaskRunner()
|
| {
|
| ASSERT(m_pendingTasksMutex.locked());
|
| - if (m_highPriorityTaskRunnerPosted)
|
| + if (m_mutexProtected.m_highPriorityTaskRunnerPosted)
|
| return;
|
| m_mainThread->postTask(new MainThreadPendingHighPriorityTaskRunner());
|
| - m_highPriorityTaskRunnerPosted = true;
|
| + m_mutexProtected.m_highPriorityTaskRunnerPosted = true;
|
| +}
|
| +
|
| +double Scheduler::nextPredictedCompositorStart()
|
| +{
|
| + return nextPredictedCompositorStartInternal(Platform::current()->monotonicallyIncreasingTime());
|
| +}
|
| +
|
| +double Scheduler::nextPredictedCompositorDeadline()
|
| +{
|
| + return nextPredictedCompositorDeadlineInternal(Platform::current()->monotonicallyIncreasingTime());
|
| +}
|
| +
|
| +double Scheduler::nextPredictedCompositorStartInternal(double currentTime)
|
| +{
|
| + if (currentTime < m_compositorStart)
|
| + return m_compositorStart;
|
| +
|
| + double interval = m_compositorInterval;
|
| + if (interval == 0.0)
|
| + return 0.0;
|
| +
|
| + double numIntervals = ceil((currentTime - m_compositorStart) / interval);
|
| + return m_compositorStart + interval * numIntervals;
|
| +}
|
| +
|
| +double Scheduler::nextPredictedCompositorDeadlineInternal(double currentTime)
|
| +{
|
| + if (currentTime < m_compositorDeadline)
|
| + return m_compositorDeadline;
|
| +
|
| + double interval = m_compositorInterval;
|
| + if (interval == 0.0)
|
| + return 0.0;
|
| +
|
| + double numIntervals = ceil((currentTime - m_compositorDeadline) / interval);
|
| + return m_compositorDeadline + interval * numIntervals;
|
| +}
|
| +
|
| +void Scheduler::maybePostMainThreadPendingLowPriorityTaskRunner(double currentTime)
|
| +{
|
| + ASSERT(m_pendingTasksMutex.locked());
|
| + if (m_mutexProtected.m_lowPriorityTaskRunnerPosted)
|
| + return;
|
| +
|
| + // MainThreadPendingLowPriorityTaskRunner should run after the compositor work is expected to have finished so that
|
| + // it's less likely to be preempted by a high priority task.
|
| + double delaySec = nextPredictedCompositorDeadlineInternal(currentTime) - currentTime;
|
| + long long delayMs = static_cast<long long>(delaySec * 1000.0);
|
| + m_mainThread->postDelayedTask(new MainThreadPendingLowPriorityTaskRunner(), delayMs);
|
| + m_mutexProtected.m_lowPriorityTaskRunnerPosted = true;
|
| }
|
|
|
| void Scheduler::postIdleTask(const TraceLocation& location, const IdleTask& idleTask)
|
| @@ -182,36 +269,36 @@ void Scheduler::tickSharedTimer()
|
| TRACE_EVENT0("blink", "Scheduler::tickSharedTimer");
|
|
|
| // Run any high priority tasks that are queued up, otherwise the blink timers will yield immediately.
|
| - bool workDone = swapQueuesAndRunPendingTasks();
|
| + bool workDone = runPendingHighPrioirtyTasks();
|
| m_sharedTimerFunction();
|
|
|
| // The blink timers may have just yielded, so run any high priority tasks that where queued up
|
| // while the blink timers were executing.
|
| if (!workDone)
|
| - swapQueuesAndRunPendingTasks();
|
| + runPendingHighPrioirtyTasks();
|
| }
|
|
|
| -bool Scheduler::swapQueuesAndRunPendingTasks()
|
| +bool Scheduler::runPendingHighPrioirtyTasks()
|
| {
|
| ASSERT(isMainThread());
|
|
|
| // These locks guard against another thread posting input or compositor tasks while we swap the buffers.
|
| // One the buffers have been swapped we can safely access the returned deque without having to lock.
|
| m_pendingTasksMutex.lock();
|
| - Deque<TracedTask>& highPriorityTasks = m_pendingHighPriorityTasks.swapBuffers();
|
| + Deque<TracedTask>& highPriorityTasks = m_mutexProtected.m_pendingHighPriorityTasks.swapBuffers();
|
| m_pendingTasksMutex.unlock();
|
| return executeHighPriorityTasks(highPriorityTasks);
|
| }
|
|
|
| -void Scheduler::swapQueuesRunPendingTasksAndAllowHighPriorityTaskRunnerPosting()
|
| +void Scheduler::runPendingHighPriorityTasksAndAllowTaskRunnerPosting()
|
| {
|
| ASSERT(isMainThread());
|
|
|
| // These locks guard against another thread posting input or compositor tasks while we swap the buffers.
|
| // One the buffers have been swapped we can safely access the returned deque without having to lock.
|
| m_pendingTasksMutex.lock();
|
| - Deque<TracedTask>& highPriorityTasks = m_pendingHighPriorityTasks.swapBuffers();
|
| - m_highPriorityTaskRunnerPosted = false;
|
| + Deque<TracedTask>& highPriorityTasks = m_mutexProtected.m_pendingHighPriorityTasks.swapBuffers();
|
| + m_mutexProtected.m_highPriorityTaskRunnerPosted = false;
|
| m_pendingTasksMutex.unlock();
|
| executeHighPriorityTasks(highPriorityTasks);
|
| }
|
| @@ -227,9 +314,46 @@ bool Scheduler::executeHighPriorityTasks(Deque<TracedTask>& highPriorityTasks)
|
|
|
| int highPriorityTaskCount = atomicSubtract(&m_highPriorityTaskCount, highPriorityTasksExecuted);
|
| ASSERT_UNUSED(highPriorityTaskCount, highPriorityTaskCount >= 0);
|
| + TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), "PendingHighPriorityTasks", m_highPriorityTaskCount);
|
| return highPriorityTasksExecuted > 0;
|
| }
|
|
|
| +void Scheduler::reloadEmptyLowPrioirtyQueue()
|
| +{
|
| + if (m_activeLowPrioirtyQueue && !m_activeLowPrioirtyQueue->isEmpty())
|
| + return;
|
| +
|
| + Locker<Mutex> lock(m_pendingTasksMutex);
|
| + m_activeLowPrioirtyQueue = &m_mutexProtected.m_pendingLowPriorityTasks.swapBuffers();
|
| +}
|
| +
|
| +void Scheduler::runPendingLowPriorityTasks()
|
| +{
|
| + TRACE_EVENT0("blink", "Scheduler::runPendingLowPriorityTasks");
|
| + m_pendingTasksMutex.lock();
|
| + m_mutexProtected.m_lowPriorityTaskRunnerPosted = false;
|
| + m_pendingTasksMutex.unlock();
|
| +
|
| + double startTime = Platform::current()->monotonicallyIncreasingTime();
|
| + double endTime = startTime + s_maximumLowPrioirtyTaskExecutionTimeSeconds;
|
| +
|
| + for (;;) {
|
| + reloadEmptyLowPrioirtyQueue();
|
| + if (m_activeLowPrioirtyQueue->isEmpty() || hasPendingHighPriorityWork())
|
| + break;
|
| + m_activeLowPrioirtyQueue->takeFirst().run();
|
| +
|
| + if (Platform::current()->monotonicallyIncreasingTime() >= endTime)
|
| + break;
|
| + }
|
| +
|
| + TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), "PendingLowPriorityTasks",
|
| + m_mutexProtected.m_pendingLowPriorityTasks.allQueuesSize());
|
| +
|
| + if (!m_activeLowPrioirtyQueue->isEmpty())
|
| + maybePostMainThreadPendingLowPriorityTaskRunner(Platform::current()->monotonicallyIncreasingTime());
|
| +}
|
| +
|
| void Scheduler::sharedTimerAdapter()
|
| {
|
| shared()->tickSharedTimer();
|
|
|