diff --git a/packages/react-reconciler/src/ReactFiberLane.js b/packages/react-reconciler/src/ReactFiberLane.js index ee3a0a3df2b60..4c96207bd6696 100644 --- a/packages/react-reconciler/src/ReactFiberLane.js +++ b/packages/react-reconciler/src/ReactFiberLane.js @@ -621,6 +621,18 @@ export function includesTransitionLane(lanes: Lanes): boolean { return (lanes & TransitionLanes) !== NoLanes; } +export function includesOnlyHydrationLanes(lanes: Lanes): boolean { + return (lanes & HydrationLanes) === lanes; +} + +export function includesOnlyOffscreenLanes(lanes: Lanes): boolean { + return (lanes & OffscreenLane) === lanes; +} + +export function includesOnlyHydrationOrOffscreenLanes(lanes: Lanes): boolean { + return (lanes & (HydrationLanes | OffscreenLane)) === lanes; +} + export function includesBlockingLane(lanes: Lanes): boolean { const SyncDefaultLanes = InputContinuousHydrationLane | diff --git a/packages/react-reconciler/src/ReactFiberPerformanceTrack.js b/packages/react-reconciler/src/ReactFiberPerformanceTrack.js index 56470bb0e55d6..7e9e246d8beb2 100644 --- a/packages/react-reconciler/src/ReactFiberPerformanceTrack.js +++ b/packages/react-reconciler/src/ReactFiberPerformanceTrack.js @@ -9,9 +9,16 @@ import type {Fiber} from './ReactInternalTypes'; +import type {Lanes} from './ReactFiberLane'; + import getComponentNameFromFiber from './getComponentNameFromFiber'; -import {getGroupNameOfHighestPriorityLane} from './ReactFiberLane'; +import { + getGroupNameOfHighestPriorityLane, + includesOnlyHydrationLanes, + includesOnlyOffscreenLanes, + includesOnlyHydrationOrOffscreenLanes, +} from './ReactFiberLane'; import {enableProfilerTimer} from 'shared/ReactFeatureFlags'; @@ -51,7 +58,7 @@ const reusableLaneOptions = { }, }; -export function setCurrentTrackFromLanes(lanes: number): void { +export function setCurrentTrackFromLanes(lanes: Lanes): void { reusableLaneDevToolDetails.track = getGroupNameOfHighestPriorityLane(lanes); } @@ -223,6 +230,7 @@ export function logBlockingStart( eventType: null | string, eventIsRepeat: boolean, renderStartTime: number, + lanes: Lanes, ): void { if (supportsUserTiming) { reusableLaneDevToolDetails.track = 'Blocking'; @@ -240,7 +248,11 @@ export function logBlockingStart( } if (updateTime > 0) { // Log the time from when we called setState until we started rendering. - reusableLaneDevToolDetails.color = 'primary-light'; + reusableLaneDevToolDetails.color = includesOnlyHydrationOrOffscreenLanes( + lanes, + ) + ? 'tertiary-light' + : 'primary-light'; reusableLaneOptions.start = updateTime; reusableLaneOptions.end = renderStartTime; performance.measure('Blocked', reusableLaneOptions); @@ -292,33 +304,65 @@ export function logTransitionStart( } } -export function logRenderPhase(startTime: number, endTime: number): void { +export function logRenderPhase( + startTime: number, + endTime: number, + lanes: Lanes, +): void { if (supportsUserTiming) { - reusableLaneDevToolDetails.color = 'primary-dark'; + reusableLaneDevToolDetails.color = includesOnlyHydrationOrOffscreenLanes( + lanes, + ) + ? 'tertiary-dark' + : 'primary-dark'; reusableLaneOptions.start = startTime; reusableLaneOptions.end = endTime; - performance.measure('Render', reusableLaneOptions); + performance.measure( + includesOnlyOffscreenLanes(lanes) + ? 'Prepared' + : includesOnlyHydrationLanes(lanes) + ? 'Hydrated' + : 'Render', + reusableLaneOptions, + ); } } export function logInterruptedRenderPhase( startTime: number, endTime: number, + lanes: Lanes, ): void { if (supportsUserTiming) { - reusableLaneDevToolDetails.color = 'primary-dark'; + reusableLaneDevToolDetails.color = includesOnlyHydrationOrOffscreenLanes( + lanes, + ) + ? 'tertiary-dark' + : 'primary-dark'; reusableLaneOptions.start = startTime; reusableLaneOptions.end = endTime; - performance.measure('Interrupted Render', reusableLaneOptions); + performance.measure( + includesOnlyOffscreenLanes(lanes) + ? 'Prewarm' + : includesOnlyHydrationLanes(lanes) + ? 'Interrupted Hydration' + : 'Interrupted Render', + reusableLaneOptions, + ); } } export function logSuspendedRenderPhase( startTime: number, endTime: number, + lanes: Lanes, ): void { if (supportsUserTiming) { - reusableLaneDevToolDetails.color = 'primary-dark'; + reusableLaneDevToolDetails.color = includesOnlyHydrationOrOffscreenLanes( + lanes, + ) + ? 'tertiary-dark' + : 'primary-dark'; reusableLaneOptions.start = startTime; reusableLaneOptions.end = endTime; performance.measure('Prewarm', reusableLaneOptions); @@ -328,10 +372,15 @@ export function logSuspendedRenderPhase( export function logSuspendedWithDelayPhase( startTime: number, endTime: number, + lanes: Lanes, ): void { // This means the render was suspended and cannot commit until it gets unblocked. if (supportsUserTiming) { - reusableLaneDevToolDetails.color = 'primary-dark'; + reusableLaneDevToolDetails.color = includesOnlyHydrationOrOffscreenLanes( + lanes, + ) + ? 'tertiary-dark' + : 'primary-dark'; reusableLaneOptions.start = startTime; reusableLaneOptions.end = endTime; performance.measure('Suspended', reusableLaneOptions); @@ -341,6 +390,7 @@ export function logSuspendedWithDelayPhase( export function logErroredRenderPhase( startTime: number, endTime: number, + lanes: Lanes, ): void { if (supportsUserTiming) { reusableLaneDevToolDetails.color = 'error'; diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js index f812d16c9c65a..dd637d687da4f 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js @@ -1035,7 +1035,7 @@ export function performWorkOnRoot( if (errorRetryLanes !== NoLanes) { if (enableProfilerTimer && enableComponentPerformanceTrack) { setCurrentTrackFromLanes(lanes); - logErroredRenderPhase(renderStartTime, renderEndTime); + logErroredRenderPhase(renderStartTime, renderEndTime, lanes); finalizeRender(lanes, renderEndTime); } lanes = errorRetryLanes; @@ -1066,7 +1066,7 @@ export function performWorkOnRoot( if (exitStatus === RootFatalErrored) { if (enableProfilerTimer && enableComponentPerformanceTrack) { setCurrentTrackFromLanes(lanes); - logErroredRenderPhase(renderStartTime, renderEndTime); + logErroredRenderPhase(renderStartTime, renderEndTime, lanes); finalizeRender(lanes, renderEndTime); } prepareFreshStack(root, NoLanes); @@ -1207,7 +1207,7 @@ function finishConcurrentRender( // until we receive more data. if (enableProfilerTimer && enableComponentPerformanceTrack) { setCurrentTrackFromLanes(lanes); - logSuspendedRenderPhase(renderStartTime, renderEndTime); + logSuspendedRenderPhase(renderStartTime, renderEndTime, lanes); finalizeRender(lanes, renderEndTime); trackSuspendedTime(lanes, renderEndTime); } @@ -1757,9 +1757,17 @@ function prepareFreshStack(root: FiberRoot, lanes: Lanes): Fiber { // then this is considered a prewarm and not an interrupted render because // we couldn't have shown anything anyway so it's not a bad thing that we // got interrupted. - logSuspendedRenderPhase(previousRenderStartTime, renderStartTime); + logSuspendedRenderPhase( + previousRenderStartTime, + renderStartTime, + lanes, + ); } else { - logInterruptedRenderPhase(previousRenderStartTime, renderStartTime); + logInterruptedRenderPhase( + previousRenderStartTime, + renderStartTime, + lanes, + ); } finalizeRender(workInProgressRootRenderLanes, renderStartTime); } @@ -1783,6 +1791,7 @@ function prepareFreshStack(root: FiberRoot, lanes: Lanes): Fiber { : clampedUpdateTime >= 0 ? clampedUpdateTime : renderStartTime, + lanes, ); } logBlockingStart( @@ -1791,6 +1800,7 @@ function prepareFreshStack(root: FiberRoot, lanes: Lanes): Fiber { blockingEventType, blockingEventIsRepeat, renderStartTime, + lanes, ); clearBlockingTimers(); } @@ -1817,6 +1827,7 @@ function prepareFreshStack(root: FiberRoot, lanes: Lanes): Fiber { : clampedUpdateTime >= 0 ? clampedUpdateTime : renderStartTime, + lanes, ); } logTransitionStart( @@ -3202,9 +3213,13 @@ function commitRootImpl( // Log the previous render phase once we commit. I.e. we weren't interrupted. setCurrentTrackFromLanes(lanes); if (exitStatus === RootErrored) { - logErroredRenderPhase(completedRenderStartTime, completedRenderEndTime); + logErroredRenderPhase( + completedRenderStartTime, + completedRenderEndTime, + lanes, + ); } else { - logRenderPhase(completedRenderStartTime, completedRenderEndTime); + logRenderPhase(completedRenderStartTime, completedRenderEndTime, lanes); } }