[Fiber] Log Effect and Render Times in Offscreen Commit Phase (#31788)

In https://github.com/facebook/react/pull/30967 and
https://github.com/facebook/react/pull/30983 I added logging of the just
rendered components and the effects. However this didn't consider the
special Offscreen passes. So this adds the same thing to those passes.

Log component effect timings for disconnected/reconnected offscreen
subtrees. This includes initial mount of a Suspense boundary.

Log component render timings for reconnected and already offscreen
offscreen subtrees.
This commit is contained in:
Sebastian Markbåge
2024-12-17 19:46:03 -05:00
committed by GitHub
parent facec3ee71
commit 6a4b46cd70
2 changed files with 183 additions and 16 deletions
+182 -15
View File
@@ -2209,6 +2209,8 @@ function recursivelyTraverseLayoutEffects(
}
export function disappearLayoutEffects(finishedWork: Fiber) {
const prevEffectStart = pushComponentEffectStart();
switch (finishedWork.tag) {
case FunctionComponent:
case ForwardRef:
@@ -2266,6 +2268,25 @@ export function disappearLayoutEffects(finishedWork: Fiber) {
break;
}
}
if (
enableProfilerTimer &&
enableProfilerCommitHooks &&
enableComponentPerformanceTrack &&
(finishedWork.mode & ProfileMode) !== NoMode &&
componentEffectStartTime >= 0 &&
componentEffectEndTime >= 0 &&
componentEffectDuration > 0.05
) {
logComponentEffect(
finishedWork,
componentEffectStartTime,
componentEffectEndTime,
componentEffectDuration,
);
}
popComponentEffectStart(prevEffectStart);
}
function recursivelyTraverseDisappearLayoutEffects(parentFiber: Fiber) {
@@ -2286,6 +2307,8 @@ export function reappearLayoutEffects(
// node was reused.
includeWorkInProgressEffects: boolean,
) {
const prevEffectStart = pushComponentEffectStart();
// Turn on layout effects in a tree that previously disappeared.
const flags = finishedWork.flags;
switch (finishedWork.tag) {
@@ -2421,6 +2444,25 @@ export function reappearLayoutEffects(
break;
}
}
if (
enableProfilerTimer &&
enableProfilerCommitHooks &&
enableComponentPerformanceTrack &&
(finishedWork.mode & ProfileMode) !== NoMode &&
componentEffectStartTime >= 0 &&
componentEffectEndTime >= 0 &&
componentEffectDuration > 0.05
) {
logComponentEffect(
finishedWork,
componentEffectStartTime,
componentEffectEndTime,
componentEffectDuration,
);
}
popComponentEffectStart(prevEffectStart);
}
function recursivelyTraverseReappearLayoutEffects(
@@ -2846,6 +2888,7 @@ function commitPassiveMountOnFiber(
finishedWork,
committedLanes,
committedTransitions,
endTime,
);
} else {
// Legacy Mode: Fire the effects even if the tree is hidden.
@@ -2884,6 +2927,7 @@ function commitPassiveMountOnFiber(
committedLanes,
committedTransitions,
includeWorkInProgressEffects,
endTime,
);
}
}
@@ -2963,6 +3007,7 @@ function recursivelyTraverseReconnectPassiveEffects(
committedLanes: Lanes,
committedTransitions: Array<Transition> | null,
includeWorkInProgressEffects: boolean,
endTime: number,
) {
// This function visits both newly finished work and nodes that were re-used
// from a previously committed tree. We cannot check non-static flags if the
@@ -2974,14 +3019,30 @@ function recursivelyTraverseReconnectPassiveEffects(
// TODO (Offscreen) Check: flags & (RefStatic | LayoutStatic)
let child = parentFiber.child;
while (child !== null) {
reconnectPassiveEffects(
finishedRoot,
child,
committedLanes,
committedTransitions,
childShouldIncludeWorkInProgressEffects,
);
child = child.sibling;
if (enableProfilerTimer && enableComponentPerformanceTrack) {
const nextSibling = child.sibling;
reconnectPassiveEffects(
finishedRoot,
child,
committedLanes,
committedTransitions,
childShouldIncludeWorkInProgressEffects,
nextSibling !== null
? ((nextSibling.actualStartTime: any): number)
: endTime,
);
child = nextSibling;
} else {
reconnectPassiveEffects(
finishedRoot,
child,
committedLanes,
committedTransitions,
childShouldIncludeWorkInProgressEffects,
endTime,
);
child = child.sibling;
}
}
}
@@ -2994,7 +3055,28 @@ export function reconnectPassiveEffects(
// from a previously committed tree. We cannot check non-static flags if the
// node was reused.
includeWorkInProgressEffects: boolean,
endTime: number, // Profiling-only. The start time of the next Fiber or root completion.
) {
const prevEffectStart = pushComponentEffectStart();
// If this component rendered in Profiling mode (DEV or in Profiler component) then log its
// render time. We do this after the fact in the passive effect to avoid the overhead of this
// getting in the way of the render characteristics and avoid the overhead of unwinding
// uncommitted renders.
if (
enableProfilerTimer &&
enableComponentPerformanceTrack &&
(finishedWork.mode & ProfileMode) !== NoMode &&
((finishedWork.actualStartTime: any): number) > 0 &&
(finishedWork.flags & PerformedWork) !== NoFlags
) {
logComponentRender(
finishedWork,
((finishedWork.actualStartTime: any): number),
endTime,
);
}
const flags = finishedWork.flags;
switch (finishedWork.tag) {
case FunctionComponent:
@@ -3006,6 +3088,7 @@ export function reconnectPassiveEffects(
committedLanes,
committedTransitions,
includeWorkInProgressEffects,
endTime,
);
// TODO: Check for PassiveStatic flag
commitHookPassiveMountEffects(finishedWork, HookPassive);
@@ -3025,6 +3108,7 @@ export function reconnectPassiveEffects(
committedLanes,
committedTransitions,
includeWorkInProgressEffects,
endTime,
);
if (includeWorkInProgressEffects && flags & Passive) {
@@ -3051,6 +3135,7 @@ export function reconnectPassiveEffects(
committedLanes,
committedTransitions,
includeWorkInProgressEffects,
endTime,
);
} else {
if (disableLegacyMode || finishedWork.mode & ConcurrentMode) {
@@ -3064,6 +3149,7 @@ export function reconnectPassiveEffects(
finishedWork,
committedLanes,
committedTransitions,
endTime,
);
} else {
// Legacy Mode: Fire the effects even if the tree is hidden.
@@ -3074,6 +3160,7 @@ export function reconnectPassiveEffects(
committedLanes,
committedTransitions,
includeWorkInProgressEffects,
endTime,
);
}
}
@@ -3093,6 +3180,7 @@ export function reconnectPassiveEffects(
committedLanes,
committedTransitions,
includeWorkInProgressEffects,
endTime,
);
}
@@ -3110,6 +3198,7 @@ export function reconnectPassiveEffects(
committedLanes,
committedTransitions,
includeWorkInProgressEffects,
endTime,
);
if (includeWorkInProgressEffects && flags & Passive) {
// TODO: Pass `current` as argument to this function
@@ -3126,6 +3215,7 @@ export function reconnectPassiveEffects(
committedLanes,
committedTransitions,
includeWorkInProgressEffects,
endTime,
);
if (includeWorkInProgressEffects && flags & Passive) {
commitTracingMarkerPassiveMountEffect(finishedWork);
@@ -3141,10 +3231,30 @@ export function reconnectPassiveEffects(
committedLanes,
committedTransitions,
includeWorkInProgressEffects,
endTime,
);
break;
}
}
if (
enableProfilerTimer &&
enableProfilerCommitHooks &&
enableComponentPerformanceTrack &&
(finishedWork.mode & ProfileMode) !== NoMode &&
componentEffectStartTime >= 0 &&
componentEffectEndTime >= 0 &&
componentEffectDuration > 0.05
) {
logComponentEffect(
finishedWork,
componentEffectStartTime,
componentEffectEndTime,
componentEffectDuration,
);
}
popComponentEffectStart(prevEffectStart);
}
function recursivelyTraverseAtomicPassiveEffects(
@@ -3152,6 +3262,7 @@ function recursivelyTraverseAtomicPassiveEffects(
parentFiber: Fiber,
committedLanes: Lanes,
committedTransitions: Array<Transition> | null,
endTime: number, // Profiling-only. The start time of the next Fiber or root completion.
) {
// "Atomic" effects are ones that need to fire on every commit, even during
// pre-rendering. We call this function when traversing a hidden tree whose
@@ -3160,13 +3271,28 @@ function recursivelyTraverseAtomicPassiveEffects(
if (parentFiber.subtreeFlags & PassiveMask) {
let child = parentFiber.child;
while (child !== null) {
commitAtomicPassiveEffects(
finishedRoot,
child,
committedLanes,
committedTransitions,
);
child = child.sibling;
if (enableProfilerTimer && enableComponentPerformanceTrack) {
const nextSibling = child.sibling;
commitAtomicPassiveEffects(
finishedRoot,
child,
committedLanes,
committedTransitions,
nextSibling !== null
? ((nextSibling.actualStartTime: any): number)
: endTime,
);
child = nextSibling;
} else {
commitAtomicPassiveEffects(
finishedRoot,
child,
committedLanes,
committedTransitions,
endTime,
);
child = child.sibling;
}
}
}
}
@@ -3176,7 +3302,24 @@ function commitAtomicPassiveEffects(
finishedWork: Fiber,
committedLanes: Lanes,
committedTransitions: Array<Transition> | null,
endTime: number, // Profiling-only. The start time of the next Fiber or root completion.
) {
// If this component rendered in Profiling mode (DEV or in Profiler component) then log its
// render time. A render can happen even if the subtree is offscreen.
if (
enableProfilerTimer &&
enableComponentPerformanceTrack &&
(finishedWork.mode & ProfileMode) !== NoMode &&
((finishedWork.actualStartTime: any): number) > 0 &&
(finishedWork.flags & PerformedWork) !== NoFlags
) {
logComponentRender(
finishedWork,
((finishedWork.actualStartTime: any): number),
endTime,
);
}
// "Atomic" effects are ones that need to fire on every commit, even during
// pre-rendering. We call this function when traversing a hidden tree whose
// regular effects are currently disconnected.
@@ -3188,6 +3331,7 @@ function commitAtomicPassiveEffects(
finishedWork,
committedLanes,
committedTransitions,
endTime,
);
if (flags & Passive) {
// TODO: Pass `current` as argument to this function
@@ -3203,6 +3347,7 @@ function commitAtomicPassiveEffects(
finishedWork,
committedLanes,
committedTransitions,
endTime,
);
if (flags & Passive) {
// TODO: Pass `current` as argument to this function
@@ -3217,6 +3362,7 @@ function commitAtomicPassiveEffects(
finishedWork,
committedLanes,
committedTransitions,
endTime,
);
break;
}
@@ -3591,6 +3737,8 @@ function commitPassiveUnmountInsideDeletedTreeOnFiber(
current: Fiber,
nearestMountedAncestor: Fiber | null,
): void {
const prevEffectStart = pushComponentEffectStart();
switch (current.tag) {
case FunctionComponent:
case ForwardRef:
@@ -3702,6 +3850,25 @@ function commitPassiveUnmountInsideDeletedTreeOnFiber(
break;
}
}
if (
enableProfilerTimer &&
enableProfilerCommitHooks &&
enableComponentPerformanceTrack &&
(current.mode & ProfileMode) !== NoMode &&
componentEffectStartTime >= 0 &&
componentEffectEndTime >= 0 &&
componentEffectDuration > 0.05
) {
logComponentEffect(
current,
componentEffectStartTime,
componentEffectEndTime,
componentEffectDuration,
);
}
popComponentEffectStart(prevEffectStart);
}
export function invokeLayoutEffectMountInDEV(fiber: Fiber): void {
+1 -1
View File
@@ -4139,7 +4139,7 @@ function doubleInvokeEffectsOnFiber(
}
reappearLayoutEffects(root, fiber.alternate, fiber, false);
if (shouldDoubleInvokePassiveEffects) {
reconnectPassiveEffects(root, fiber, NoLanes, null, false);
reconnectPassiveEffects(root, fiber, NoLanes, null, false, 0);
}
} finally {
setIsStrictModeForDevtools(false);