Index: Source/platform/scheduler/Scheduler.cpp |
diff --git a/Source/platform/scheduler/Scheduler.cpp b/Source/platform/scheduler/Scheduler.cpp |
index 4a447721f58921b8fe0500568ed583f76288b5c8..eb6c698604630c429e1374f82446497987a24b74 100644 |
--- a/Source/platform/scheduler/Scheduler.cpp |
+++ b/Source/platform/scheduler/Scheduler.cpp |
@@ -18,6 +18,9 @@ namespace blink { |
namespace { |
+// The time we should stay in CompositorPriority mode for, after a touch event. |
+double kLowSchedulerPolicyAfterTouchTimeSeconds = 0.1; |
+ |
// Can be created from any thread. |
// Note if the scheduler gets shutdown, this may be run after. |
class MainThreadIdleTaskAdapter : public WebThread::Task { |
@@ -63,6 +66,8 @@ public: |
ASSERT(scheduler); |
if (!scheduler) |
return; |
+ // NOTE we must unconditionally execute high priority tasks here, since if we're not in CompositorPriority |
+ // mode, then this is the only place where high priority tasks will be executed. |
scheduler->swapQueuesRunPendingTasksAndAllowHighPriorityTaskRunnerPosting(); |
} |
}; |
@@ -86,7 +91,7 @@ public: |
// FIXME: This check should't be necessary, tasks should not outlive blink. |
ASSERT(scheduler); |
if (scheduler) |
- Scheduler::shared()->swapQueuesAndRunPendingTasks(); |
+ Scheduler::shared()->runPendingHighPriorityTasksIfInCompositorPriority(); |
m_task.run(); |
} |
@@ -114,8 +119,10 @@ Scheduler* Scheduler::shared() |
Scheduler::Scheduler() |
: m_sharedTimerFunction(nullptr) |
, m_mainThread(blink::Platform::current()->currentThread()) |
+ , m_compositorPriorityPolicyEndTimeSeconds(0) |
, m_highPriorityTaskCount(0) |
, m_highPriorityTaskRunnerPosted(false) |
+ , m_schedulerPolicy(Normal) |
{ |
} |
@@ -153,6 +160,7 @@ void Scheduler::postInputTask(const TraceLocation& location, const Task& task) |
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 +169,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 +191,22 @@ 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 = runPendingHighPriorityTasksIfInCompositorPriority(); |
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(); |
+ runPendingHighPriorityTasksIfInCompositorPriority(); |
+} |
+ |
+bool Scheduler::runPendingHighPriorityTasksIfInCompositorPriority() |
+{ |
+ ASSERT(isMainThread()); |
+ if (schedulerPolicy() != CompositorPriority) |
+ return false; |
+ |
+ return swapQueuesAndRunPendingTasks(); |
} |
bool Scheduler::swapQueuesAndRunPendingTasks() |
@@ -199,6 +217,7 @@ bool Scheduler::swapQueuesAndRunPendingTasks() |
// 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(); |
+ maybeEnterNormalSchedulerPolicy(); |
m_pendingTasksMutex.unlock(); |
return executeHighPriorityTasks(highPriorityTasks); |
} |
@@ -212,10 +231,21 @@ void Scheduler::swapQueuesRunPendingTasksAndAllowHighPriorityTaskRunnerPosting() |
m_pendingTasksMutex.lock(); |
Deque<TracedTask>& highPriorityTasks = m_pendingHighPriorityTasks.swapBuffers(); |
m_highPriorityTaskRunnerPosted = false; |
+ maybeEnterNormalSchedulerPolicy(); |
m_pendingTasksMutex.unlock(); |
executeHighPriorityTasks(highPriorityTasks); |
} |
+void Scheduler::maybeEnterNormalSchedulerPolicy() |
+{ |
+ ASSERT(isMainThread()); |
+ ASSERT(m_pendingTasksMutex.locked()); |
+ |
+ // Go back to the normal scheduler policy if enough time has elapsed. |
+ if (schedulerPolicy() == CompositorPriority && Platform::current()->monotonicallyIncreasingTime() > m_compositorPriorityPolicyEndTimeSeconds) |
+ enterSchedulerPolicyLocked(Normal); |
+} |
+ |
bool Scheduler::executeHighPriorityTasks(Deque<TracedTask>& highPriorityTasks) |
{ |
TRACE_EVENT0("blink", "Scheduler::executeHighPriorityTasks"); |
@@ -227,6 +257,7 @@ 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; |
} |
@@ -253,6 +284,10 @@ void Scheduler::stopSharedTimer() |
bool Scheduler::shouldYieldForHighPriorityWork() const |
{ |
+ // It's only worthwhile yielding in CompositorPriority mode. |
+ if (schedulerPolicy() != CompositorPriority) |
+ return false; |
+ |
return hasPendingHighPriorityWork(); |
} |
@@ -266,6 +301,31 @@ bool Scheduler::hasPendingHighPriorityWork() const |
return acquireLoad(&m_highPriorityTaskCount) != 0; |
} |
+Scheduler::SchedulerPolicy Scheduler::schedulerPolicy() 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<SchedulerPolicy>(acquireLoad(&m_schedulerPolicy)); |
+} |
+ |
+void Scheduler::enterSchedulerPolicy(SchedulerPolicy schedulerPolicy) |
+{ |
+ Locker<Mutex> lock(m_pendingTasksMutex); |
+ enterSchedulerPolicyLocked(schedulerPolicy); |
+} |
+ |
+void Scheduler::enterSchedulerPolicyLocked(SchedulerPolicy schedulerPolicy) |
+{ |
+ ASSERT(m_pendingTasksMutex.locked()); |
+ if (schedulerPolicy == CompositorPriority) |
+ m_compositorPriorityPolicyEndTimeSeconds = Platform::current()->monotonicallyIncreasingTime() + kLowSchedulerPolicyAfterTouchTimeSeconds; |
+ |
+ releaseStore(&m_schedulerPolicy, schedulerPolicy); |
+ TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.scheduler"), "SchedulerPolicy", schedulerPolicy); |
+} |
+ |
void Scheduler::TracedTask::run() |
{ |
TRACE_EVENT2("blink", "TracedTask::run", |