Performance optimization to allow paint to happen (up to) 1 frame earlier

Summary:
Due to the way we're dispatching queued MountItems on Android, we could be doing nothing on the UI thread for up to 15.99...ms before the start of the next frame, resulting in a delayed paint of up to 1 full (16ms) frame.

The delay is totally random and depends only on when the work is scheduled.

The tl;dr is that currently all MountItems are dispatched starting only at the /beginning/ of a UI frame. If we schedule work at FrameStart+0.000001ms, it will not be operated on until the start of the next frame, 16ms later. So the "wasted" time could be anywhere from 0 to ~16ms, but will result in at least 1 wasted frame regardless.

The fix is fairly trivial: start working on large buffered work as soon as we schedule it.

Changelog: [Android][Changed] Optimization to paint changes up to 1 frame earlier on Android/Fabric

Reviewed By: NickGerleman

Differential Revision: D37478885

fbshipit-source-id: 8af846736caf3a9d9f0d0c5e33328bebb87b1b32
This commit is contained in:
Joshua Gross 2022-06-28 16:13:07 -07:00 коммит произвёл Facebook GitHub Bot
Родитель 3fa3aeba93
Коммит 3a7170ca52
2 изменённых файлов: 23 добавлений и 0 удалений

Просмотреть файл

@ -140,4 +140,7 @@ public class ReactFeatureFlags {
* Allow Differentiator.cpp and FabricMountingManager.cpp to generate a RemoveDeleteTree mega-op.
*/
public static boolean enableRemoveDeleteTreeInstruction = false;
/** Temporary flag to allow execution of mount items up to 15ms earlier than normal. */
public static boolean enableEarlyScheduledMountItemExecution = false;
}

Просмотреть файл

@ -814,6 +814,26 @@ public class FabricUIManager implements UIManager, LifecycleEventListener {
if (UiThreadUtil.isOnUiThread()) {
// We only read these flags on the UI thread.
mMountItemDispatcher.tryDispatchMountItems();
} else {
// The Choreographer will dispatch any mount items,
// but it only gets called at the /beginning/ of the
// frame - it has no idea if, or when, there is actually work scheduled. That means if we
// have a big chunk of work
// scheduled but the scheduling happens 1ms after the
// start of a UI frame, we'll miss out on 15ms of time
// to perform the work (assuming a 16ms frame).
// The DispatchUIFrameCallback still has value because of
// the PreMountItems that we need to process at a lower
// priority.
if (ReactFeatureFlags.enableEarlyScheduledMountItemExecution) {
UiThreadUtil.runOnUiThread(
new Runnable() {
@Override
public void run() {
mDispatchUIFrameCallback.doFrameGuarded(System.nanoTime());
}
});
}
}
}