[webkit-changes] [WebKit/WebKit] c7bdb5: Add a mechanism to schedule opportunistic work in ...

Wenson Hsieh noreply at github.com
Wed Jun 14 20:44:11 PDT 2023


  Branch: refs/heads/main
  Home:   https://github.com/WebKit/WebKit
  Commit: c7bdb5bcd411cab772466fdc79661c41c115095a
      https://github.com/WebKit/WebKit/commit/c7bdb5bcd411cab772466fdc79661c41c115095a
  Author: Wenson Hsieh <wenson_hsieh at apple.com>
  Date:   2023-06-14 (Wed, 14 Jun 2023)

  Changed paths:
    M Source/WebCore/Sources.txt
    M Source/WebCore/WebCore.xcodeproj/project.pbxproj
    M Source/WebCore/dom/ScriptExecutionContext.h
    M Source/WebCore/page/DOMTimer.cpp
    M Source/WebCore/page/DOMTimer.h
    M Source/WebCore/page/LocalFrameView.cpp
    A Source/WebCore/page/OpportunisticTaskScheduler.cpp
    A Source/WebCore/page/OpportunisticTaskScheduler.h
    M Source/WebCore/page/Page.cpp
    M Source/WebCore/page/Page.h
    M Source/WebCore/platform/RunLoopObserver.h
    M Source/WebCore/platform/cf/RunLoopObserverCF.cpp

  Log Message:
  -----------
  Add a mechanism to schedule opportunistic work in between rendering updates
https://bugs.webkit.org/show_bug.cgi?id=258032
rdar://110076652

Reviewed by Ryosuke Niwa.

Add an `OpportunisticTaskScheduler` helper class to be used in a subsequent patch to dispatch
periodically-scheduled cleanup tasks, such as incremental sweeping, in between rendering updates
(i.e. after the runloop begins to wait for more work, but before the next rendering update is
scheduled to start).

This `OpportunisticTaskScheduler` is essentially a wrapper around a `RunLoopObserver`, which calls
into `Page` to perform scheduled work until a given deadline. The `Page` is the only entity that
owns the task scheduler, and will tell it to reschedule after every rendering update. Additionally,
we introduce another mechanism — `OpportunisticTaskDeferralScope` — that prevents the task scheduler
from firing during certain time intervals where we know that scheduled work is imminent. For now,
this just includes:

1. Scheduled one-shot timers with a very short duration.
2. Any time prior to first paint, after navigation.

No change in behavior (yet).

* Source/WebCore/Sources.txt:
* Source/WebCore/WebCore.xcodeproj/project.pbxproj:
* Source/WebCore/dom/ScriptExecutionContext.h:
(WebCore::ScriptExecutionContext::addTimeout):
(WebCore::ScriptExecutionContext::takeTimeout):
(WebCore::ScriptExecutionContext::removeTimeout): Deleted.

Change `removeTimeout` to `takeTimeout`, and have it return the removed `DOMTimer`. This allows us
to (more easily) call `clearOpportunisticTaskDeferralScopeIfPossible()` on the removed timer below.

* Source/WebCore/page/DOMTimer.cpp:
(WebCore::DOMTimer::install):
(WebCore::DOMTimer::removeById):
(WebCore::DOMTimer::fired):
(WebCore::DOMTimer::didStop):
(WebCore::DOMTimer::makeOpportunisticTaskDeferralScopeIfPossible):
(WebCore::DOMTimer::clearOpportunisticTaskDeferralScopeIfPossible):

Add a opportunistic task deferral scope to prevent us from scheduling opportunistic tasks in the
case where one-shot zero-delay timers are about to fire.

* Source/WebCore/page/DOMTimer.h:
* Source/WebCore/page/LocalFrameView.cpp:
(WebCore::LocalFrameView::fireLayoutRelatedMilestonesIfNeeded):

Add some plumbing to notify `Page` when we hit first meaningful paint.

* Source/WebCore/page/OpportunisticTaskScheduler.cpp: Added.
(WebCore::OpportunisticTaskDeferralScope::OpportunisticTaskDeferralScope):
(WebCore::OpportunisticTaskDeferralScope::~OpportunisticTaskDeferralScope):

Add a RAII helper class to increment and decrement the deferral count in
`OpportunisticTaskScheduler`, which prevents opportunistically scheduled tasks from firing; this
RAII pattern hopefully makes it a bit easier to ensure that nothing ends up with unbalanced calls to
increment or decrement.

(WebCore::OpportunisticTaskScheduler::OpportunisticTaskScheduler):
(WebCore::OpportunisticTaskScheduler::reschedule):

Helper method to reschedule the task scheduler, with a target deadline; called after completing
rendering updates in `Page`.

(WebCore::OpportunisticTaskScheduler::makeDeferralScope):

Helper method to make a `OpportunisticTaskDeferralScope`, which increments the deferral count (and
only decrements the count upon detroying the scope).

(WebCore::OpportunisticTaskScheduler::runLoopObserverFired):

Call into page to `performOpportunisticallyScheduledTasks`, once the runloop observer fires (i.e.,
the runloop has become idle) and only if we still have remaining time until the next deadline (which
is established when we were most recently rescheduled). This ensures that if post-rendering-update
tasks take a long time to finish and another rendering update is imminent, we'll skip this
opportunistic task call entirely, and instead do the work when we're less busy.

(WebCore::OpportunisticTaskScheduler::incrementDeferralCount):
(WebCore::OpportunisticTaskScheduler::decrementDeferralCount):

Private methods to manage the task deferral count; while the count is non-zero, we avoid calling
into the page to perform opportunistic tasks. When the deferral count is restored to 0, we then
wait for the runloop to become idle (via `RunLoopObserver`), and then run tasks if appropriate.

* Source/WebCore/page/OpportunisticTaskScheduler.h: Added.
(WebCore::OpportunisticTaskScheduler::create):
* Source/WebCore/page/Page.cpp:
(WebCore::Page::didCommitLoad):
(WebCore::Page::didFirstMeaningfulPaint):

Hold on to a `OpportunisticTaskDeferralScope` before the page has finished first paint.

(WebCore::Page::renderingUpdateCompleted):

Reschedule opportunistic tasks (see above for more information).

(WebCore::Page::performOpportunisticallyScheduledTasks):

Leave an empty method stub for now; in the next patch, this will call into a new `JSC::VM`
entrypoint to perform some pre-scheduled, periodic cleanup tasks, such as running the incremental
sweeper until the deadline.

* Source/WebCore/page/Page.h:
(WebCore::Page::opportunisticTaskScheduler const):
* Source/WebCore/platform/RunLoopObserver.h:
(WebCore::RunLoopObserver::RunLoopObserver):
(WebCore::RunLoopObserver::isRepeating const):
* Source/WebCore/platform/cf/RunLoopObserverCF.cpp:
(WebCore::RunLoopObserver::schedule):

Add an option to make the `RunLoopObserver` one-shot (as opposed to repeating). We use this flag
when creating runloop observers in the new `OpportunisticTaskScheduler`, since we don't want the
runloop observer to continue listening forever.

Canonical link: https://commits.webkit.org/265178@main




More information about the webkit-changes mailing list