Skip to content

Commit

Permalink
[Fiber] Log Effect and Render Times in Offscreen Commit Phase (facebo…
Browse files Browse the repository at this point in the history
…ok#31788)

In facebook#30967 and
facebook#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.
  • Loading branch information
sebmarkbage authored Dec 18, 2024
1 parent facec3e commit 6a4b46c
Show file tree
Hide file tree
Showing 2 changed files with 183 additions and 16 deletions.
197 changes: 182 additions & 15 deletions packages/react-reconciler/src/ReactFiberCommitWork.js
Original file line number Diff line number Diff line change
Expand Up @@ -2209,6 +2209,8 @@ function recursivelyTraverseLayoutEffects(
}

export function disappearLayoutEffects(finishedWork: Fiber) {
const prevEffectStart = pushComponentEffectStart();

switch (finishedWork.tag) {
case FunctionComponent:
case ForwardRef:
Expand Down Expand Up @@ -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) {
Expand All @@ -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) {
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -2846,6 +2888,7 @@ function commitPassiveMountOnFiber(
finishedWork,
committedLanes,
committedTransitions,
endTime,
);
} else {
// Legacy Mode: Fire the effects even if the tree is hidden.
Expand Down Expand Up @@ -2884,6 +2927,7 @@ function commitPassiveMountOnFiber(
committedLanes,
committedTransitions,
includeWorkInProgressEffects,
endTime,
);
}
}
Expand Down Expand Up @@ -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
Expand All @@ -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;
}
}
}

Expand All @@ -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:
Expand All @@ -3006,6 +3088,7 @@ export function reconnectPassiveEffects(
committedLanes,
committedTransitions,
includeWorkInProgressEffects,
endTime,
);
// TODO: Check for PassiveStatic flag
commitHookPassiveMountEffects(finishedWork, HookPassive);
Expand All @@ -3025,6 +3108,7 @@ export function reconnectPassiveEffects(
committedLanes,
committedTransitions,
includeWorkInProgressEffects,
endTime,
);

if (includeWorkInProgressEffects && flags & Passive) {
Expand All @@ -3051,6 +3135,7 @@ export function reconnectPassiveEffects(
committedLanes,
committedTransitions,
includeWorkInProgressEffects,
endTime,
);
} else {
if (disableLegacyMode || finishedWork.mode & ConcurrentMode) {
Expand All @@ -3064,6 +3149,7 @@ export function reconnectPassiveEffects(
finishedWork,
committedLanes,
committedTransitions,
endTime,
);
} else {
// Legacy Mode: Fire the effects even if the tree is hidden.
Expand All @@ -3074,6 +3160,7 @@ export function reconnectPassiveEffects(
committedLanes,
committedTransitions,
includeWorkInProgressEffects,
endTime,
);
}
}
Expand All @@ -3093,6 +3180,7 @@ export function reconnectPassiveEffects(
committedLanes,
committedTransitions,
includeWorkInProgressEffects,
endTime,
);
}

Expand All @@ -3110,6 +3198,7 @@ export function reconnectPassiveEffects(
committedLanes,
committedTransitions,
includeWorkInProgressEffects,
endTime,
);
if (includeWorkInProgressEffects && flags & Passive) {
// TODO: Pass `current` as argument to this function
Expand All @@ -3126,6 +3215,7 @@ export function reconnectPassiveEffects(
committedLanes,
committedTransitions,
includeWorkInProgressEffects,
endTime,
);
if (includeWorkInProgressEffects && flags & Passive) {
commitTracingMarkerPassiveMountEffect(finishedWork);
Expand All @@ -3141,17 +3231,38 @@ 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(
finishedRoot: FiberRoot,
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
Expand All @@ -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;
}
}
}
}
Expand All @@ -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.
Expand All @@ -3188,6 +3331,7 @@ function commitAtomicPassiveEffects(
finishedWork,
committedLanes,
committedTransitions,
endTime,
);
if (flags & Passive) {
// TODO: Pass `current` as argument to this function
Expand All @@ -3203,6 +3347,7 @@ function commitAtomicPassiveEffects(
finishedWork,
committedLanes,
committedTransitions,
endTime,
);
if (flags & Passive) {
// TODO: Pass `current` as argument to this function
Expand All @@ -3217,6 +3362,7 @@ function commitAtomicPassiveEffects(
finishedWork,
committedLanes,
committedTransitions,
endTime,
);
break;
}
Expand Down Expand Up @@ -3591,6 +3737,8 @@ function commitPassiveUnmountInsideDeletedTreeOnFiber(
current: Fiber,
nearestMountedAncestor: Fiber | null,
): void {
const prevEffectStart = pushComponentEffectStart();

switch (current.tag) {
case FunctionComponent:
case ForwardRef:
Expand Down Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion packages/react-reconciler/src/ReactFiberWorkLoop.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit 6a4b46c

Please sign in to comment.