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

Unified Diff: Source/platform/scheduler/Scheduler.cpp

Issue 540373002: Add support for Low Priorirty tasks. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Maybe fix linker issue Created 6 years, 3 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/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();

Powered by Google App Engine
This is Rietveld 408576698