Index: Source/platform/scheduler/Scheduler.cpp |
diff --git a/Source/platform/scheduler/Scheduler.cpp b/Source/platform/scheduler/Scheduler.cpp |
index 4a447721f58921b8fe0500568ed583f76288b5c8..abba6b776a12d8359fb521ab171795994885dbea 100644 |
--- a/Source/platform/scheduler/Scheduler.cpp |
+++ b/Source/platform/scheduler/Scheduler.cpp |
@@ -16,6 +16,8 @@ |
namespace blink { |
+double Scheduler::s_lowLatencyModeAfterTouchTimeSeconds = 0.1; |
+ |
namespace { |
// Can be created from any thread. |
@@ -63,6 +65,7 @@ public: |
ASSERT(scheduler); |
if (!scheduler) |
return; |
+ // NOTE if we're not in low latency mode, this is the only place they will actually get executed. |
scheduler->swapQueuesRunPendingTasksAndAllowHighPriorityTaskRunnerPosting(); |
} |
}; |
@@ -86,7 +89,7 @@ public: |
// FIXME: This check should't be necessary, tasks should not outlive blink. |
ASSERT(scheduler); |
if (scheduler) |
- Scheduler::shared()->swapQueuesAndRunPendingTasks(); |
+ Scheduler::shared()->runPendingHighPrioirtyTasksIfInLowLatencyMode(); |
m_task.run(); |
} |
@@ -116,6 +119,8 @@ Scheduler::Scheduler() |
, m_mainThread(blink::Platform::current()->currentThread()) |
, m_highPriorityTaskCount(0) |
, m_highPriorityTaskRunnerPosted(false) |
+ , m_latencyMode(Normal) |
+ , m_lowLatencyModeEndTimeSeconds(0) |
{ |
} |
@@ -150,9 +155,11 @@ void Scheduler::postTask(const TraceLocation& location, const Task& task) |
void Scheduler::postInputTask(const TraceLocation& location, const Task& task) |
{ |
Locker<Mutex> lock(m_pendingTasksMutex); |
+ setLatencyMode(LowLatency); |
m_pendingHighPriorityTasks.append(TracedTask(task, location)); |
atomicIncrement(&m_highPriorityTaskCount); |
maybePostMainThreadPendingHighPriorityTaskRunner(); |
+ TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), "PendingHighPriorityTasks", m_highPriorityTaskCount); |
} |
void Scheduler::postCompositorTask(const TraceLocation& location, const Task& task) |
@@ -161,6 +168,7 @@ void Scheduler::postCompositorTask(const TraceLocation& location, const Task& ta |
m_pendingHighPriorityTasks.append(TracedTask(task, location)); |
atomicIncrement(&m_highPriorityTaskCount); |
maybePostMainThreadPendingHighPriorityTaskRunner(); |
+ TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), "PendingHighPriorityTasks", m_highPriorityTaskCount); |
} |
void Scheduler::maybePostMainThreadPendingHighPriorityTaskRunner() |
@@ -182,13 +190,21 @@ 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 = runPendingHighPrioirtyTasksIfInLowLatencyMode(); |
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(); |
+ runPendingHighPrioirtyTasksIfInLowLatencyMode(); |
+} |
+ |
+bool Scheduler::runPendingHighPrioirtyTasksIfInLowLatencyMode() |
+{ |
+ if (latencyMode() != LowLatency) |
+ return false; |
+ |
+ return swapQueuesAndRunPendingTasks(); |
} |
bool Scheduler::swapQueuesAndRunPendingTasks() |
@@ -227,6 +243,11 @@ 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); |
+ |
+ // Go back to normal latency mode if enough time has elapsed. |
+ if (latencyMode() == LowLatency && Platform::current()->monotonicallyIncreasingTime() > m_lowLatencyModeEndTimeSeconds) |
+ setLatencyMode(Normal); |
return highPriorityTasksExecuted > 0; |
} |
@@ -253,6 +274,10 @@ void Scheduler::stopSharedTimer() |
bool Scheduler::shouldYieldForHighPriorityWork() const |
{ |
+ // It's only worthwhile yielding in low latency mode. |
+ if (latencyMode() != LowLatency) |
+ return false; |
+ |
return hasPendingHighPriorityWork(); |
} |
@@ -266,6 +291,24 @@ bool Scheduler::hasPendingHighPriorityWork() const |
return acquireLoad(&m_highPriorityTaskCount) != 0; |
} |
+Scheduler::LatencyMode Scheduler::latencyMode() const |
+{ |
+ ASSERT(isMainThread()); |
+ // It's important not to miss the transition from normal to low latency mode, otherwise we're likely to |
+ // delay the processing of input tasks. Since that transition is triggered by a different thread, we |
+ // need either a lock or a memory barrier, and the memory barrier is probably cheaper. |
+ return static_cast<LatencyMode>(acquireLoad(&m_latencyMode)); |
+} |
+ |
+void Scheduler::setLatencyMode(LatencyMode latencyMode) |
+{ |
+ if (latencyMode == LowLatency) |
+ m_lowLatencyModeEndTimeSeconds = Platform::current()->monotonicallyIncreasingTime() + s_lowLatencyModeAfterTouchTimeSeconds; |
+ |
+ releaseStore(&m_latencyMode, latencyMode); |
+ TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), "LatencyMode", latencyMode); |
+} |
+ |
void Scheduler::TracedTask::run() |
{ |
TRACE_EVENT2("blink", "TracedTask::run", |