Skip to content

Commit

Permalink
Log the previously rendered component as a deduped entry
Browse files Browse the repository at this point in the history
  • Loading branch information
sebmarkbage committed Dec 12, 2024
1 parent 1f6a108 commit 7b80979
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 6 deletions.
5 changes: 3 additions & 2 deletions fixtures/flight/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ function Foo({children}) {
return <div>{children}</div>;
}

function Bar({children}) {
async function Bar({children}) {
await new Promise(resolve => setTimeout(() => resolve('deferred text'), 10));
return <div>{children}</div>;
}

Expand Down Expand Up @@ -81,7 +82,7 @@ export default async function App({prerender}) {
<Client />
<Note />
<Foo>{dedupedChild}</Foo>
<Bar>{dedupedChild}</Bar>
<Bar>{Promise.resolve([dedupedChild])}</Bar>
</Container>
</body>
</html>
Expand Down
46 changes: 42 additions & 4 deletions packages/react-client/src/ReactFlightClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ import {readTemporaryReference} from './ReactFlightTemporaryReferences';
import {
markAllTracksInOrder,
logComponentRender,
logDedupedComponentRender,
} from './ReactFlightPerformanceTrack';

import {
Expand Down Expand Up @@ -132,6 +133,7 @@ export type JSONValue =
type ProfilingResult = {
track: number,
endTime: number,
component: null | ReactComponentInfo,
};

const ROW_ID = 0;
Expand Down Expand Up @@ -653,7 +655,7 @@ export function reportGlobalError(response: Response, error: Error): void {
});
if (enableProfilerTimer && enableComponentPerformanceTrack) {
markAllTracksInOrder();
flushComponentPerformance(getChunk(response, 0), 0, -Infinity);
flushComponentPerformance(getChunk(response, 0), 0, -Infinity, -Infinity);
}
}

Expand Down Expand Up @@ -2761,7 +2763,8 @@ function resolveTypedArray(
function flushComponentPerformance(
root: SomeChunk<any>,
trackIdx: number, // Next available track
trackTime: number, // The time after which it is available
trackTime: number, // The time after which it is available,
parentEndTime: number,
): ProfilingResult {
if (!enableProfilerTimer || !enableComponentPerformanceTrack) {
// eslint-disable-next-line react-internal/prod-error-codes
Expand All @@ -2778,6 +2781,22 @@ function flushComponentPerformance(
// chunk in two places. We should extend the current end time as if it was
// rendered as part of this tree.
const previousResult: ProfilingResult = root._children;
const previousEndTime = previousResult.endTime;
if (
parentEndTime > -Infinity &&
parentEndTime < previousEndTime &&
previousResult.component !== null
) {
// Log a placeholder for the deduped value under this child starting
// from the end of the self time of the parent and spanning until the
// the deduped end.
logDedupedComponentRender(
previousResult.component,
trackIdx,
parentEndTime,
previousEndTime,
);
}
// Since we didn't bump the track this time, we just return the same track.
previousResult.track = trackIdx;
return previousResult;
Expand All @@ -2793,6 +2812,7 @@ function flushComponentPerformance(
// First find the start time of the first component to know if it was running
// in parallel with the previous.
const debugInfo = root._debugInfo;
let selfEndTime = -Infinity;

Check failure on line 2815 in packages/react-client/src/ReactFlightClient.js

View workflow job for this annotation

GitHub Actions / Run eslint

'selfEndTime' is never reassigned. Use 'const' instead

Check failure on line 2815 in packages/react-client/src/ReactFlightClient.js

View workflow job for this annotation

GitHub Actions / Run eslint

'selfEndTime' is assigned a value but never used
if (debugInfo) {
for (let i = 1; i < debugInfo.length; i++) {
const info = debugInfo[i];
Expand All @@ -2805,15 +2825,27 @@ function flushComponentPerformance(
// The start time of this component is before the end time of the previous
// component on this track so we need to bump the next one to a parallel track.
trackIdx++;
trackTime = startTime;
}
trackTime = startTime;
break;
}
}
}
for (let i = debugInfo.length - 1; i >= 0; i--) {
const info = debugInfo[i];
if (typeof info.time === 'number') {
if (info.time > parentEndTime) {
parentEndTime = info.time;
}
}
}
}

const result: ProfilingResult = {track: trackIdx, endTime: -Infinity};
const result: ProfilingResult = {
track: trackIdx,
endTime: -Infinity,
component: null,
};
root._children = result;
let childrenEndTime = -Infinity;
let childTrackIdx = trackIdx;
Expand All @@ -2823,7 +2855,11 @@ function flushComponentPerformance(
children[i],
childTrackIdx,
childTrackTime,
parentEndTime,
);
if (childResult.component !== null) {
result.component = childResult.component;
}
childTrackIdx = childResult.track;
const childEndTime = childResult.endTime;
childTrackTime = childEndTime;
Expand Down Expand Up @@ -2855,6 +2891,8 @@ function flushComponentPerformance(
endTime,
childrenEndTime,
);
// Track the root most component of the result for deduping logging.
result.component = componentInfo;
}
}
}
Expand Down
16 changes: 16 additions & 0 deletions packages/react-client/src/ReactFlightPerformanceTrack.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,19 @@ export function logComponentRender(
performance.measure(name, reusableComponentOptions);
}
}

export function logDedupedComponentRender(
componentInfo: ReactComponentInfo,
trackIdx: number,
startTime: number,
endTime: number,
): void {
if (supportsUserTiming && endTime >= 0 && trackIdx < 10) {
const name = componentInfo.name;
reusableComponentDevToolDetails.color = 'tertiary-light';
reusableComponentDevToolDetails.track = trackNames[trackIdx];
reusableComponentOptions.start = startTime < 0 ? 0 : startTime;
reusableComponentOptions.end = endTime;
performance.measure(name + ' [deduped]', reusableComponentOptions);
}
}

0 comments on commit 7b80979

Please sign in to comment.