Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DevTools Profiler: Add commit and post-commit durations to UI #20984

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

46 changes: 46 additions & 0 deletions packages/react-devtools-shared/src/backend/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2097,6 +2097,25 @@ export function attach(
// Checking root.memoizedInteractions handles multi-renderer edge-case-
// where some v16 renderers support profiling and others don't.
if (isProfiling && root.memoizedInteractions != null) {
// Profiling durations are only available for certain builds.
// If available, they'll be stored on the HostRoot.
let effectDuration = null;
let passiveEffectDuration = null;
const hostRoot = root.current;
if (hostRoot != null) {
const stateNode = hostRoot.stateNode;
if (stateNode != null) {
effectDuration =
stateNode.effectDuration != null
? stateNode.effectDuration
: null;
passiveEffectDuration =
stateNode.passiveEffectDuration != null
? stateNode.passiveEffectDuration
: null;
}
}

// If profiling is active, store commit time and duration, and the current interactions.
// The frontend may request this information after profiling has stopped.
currentCommitProfilingMetadata = {
Expand All @@ -2111,6 +2130,8 @@ export function attach(
),
maxActualDuration: 0,
priorityLevel: null,
effectDuration,
passiveEffectDuration,
};
}

Expand Down Expand Up @@ -2149,6 +2170,23 @@ export function attach(
const isProfilingSupported = root.memoizedInteractions != null;

if (isProfiling && isProfilingSupported) {
// Profiling durations are only available for certain builds.
// If available, they'll be stored on the HostRoot.
let effectDuration = null;
let passiveEffectDuration = null;
const hostRoot = root.current;
if (hostRoot != null) {
const stateNode = hostRoot.stateNode;
if (stateNode != null) {
effectDuration =
stateNode.effectDuration != null ? stateNode.effectDuration : null;
passiveEffectDuration =
stateNode.passiveEffectDuration != null
? stateNode.passiveEffectDuration
: null;
}
}

// If profiling is active, store commit time and duration, and the current interactions.
// The frontend may request this information after profiling has stopped.
currentCommitProfilingMetadata = {
Expand All @@ -2164,6 +2202,8 @@ export function attach(
maxActualDuration: 0,
priorityLevel:
priorityLevel == null ? null : formatPriorityLevel(priorityLevel),
effectDuration,
passiveEffectDuration,
};
}

Expand Down Expand Up @@ -3294,8 +3334,10 @@ export function attach(
changeDescriptions: Map<number, ChangeDescription> | null,
commitTime: number,
durations: Array<number>,
effectDuration: number | null,
interactions: Array<Interaction>,
maxActualDuration: number,
passiveEffectDuration: number | null,
priorityLevel: string | null,
|};

Expand Down Expand Up @@ -3349,8 +3391,10 @@ export function attach(
const {
changeDescriptions,
durations,
effectDuration,
interactions,
maxActualDuration,
passiveEffectDuration,
priorityLevel,
commitTime,
} = commitProfilingData;
Expand Down Expand Up @@ -3386,9 +3430,11 @@ export function attach(
? Array.from(changeDescriptions.entries())
: null,
duration: maxActualDuration,
effectDuration,
fiberActualDurations,
fiberSelfDurations,
interactionIDs,
passiveEffectDuration,
priorityLevel,
timestamp: commitTime,
});
Expand Down
4 changes: 4 additions & 0 deletions packages/react-devtools-shared/src/backend/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,11 +156,15 @@ export type CommitDataBackend = {|
// Tuple of fiber ID and change description
changeDescriptions: Array<[number, ChangeDescription]> | null,
duration: number,
// Only available in certain (newer) React builds,
effectDuration: number | null,
// Tuple of fiber ID and actual duration
fiberActualDurations: Array<[number, number]>,
// Tuple of fiber ID and computed "self" duration
fiberSelfDurations: Array<[number, number]>,
interactionIDs: Array<number>,
// Only available in certain (newer) React builds,
passiveEffectDuration: number | null,
priorityLevel: string | null,
timestamp: number,
|};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,19 @@
height: 100%;
color: var(--color-dim);
}

.DurationsList {
list-style: none;
margin: 0.25rem 0 0 0;
padding: 0;
background: var(--color-background-inactive);
padding: 0.25rem 0.5rem;
border-radius: 0.25rem;
}

.DurationsListItem {
margin: 0.25rem 0 0 0;
}
.DurationsListItem:first-of-type {
margin: 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ export default function SidebarCommitInfo(_: Props) {
const {interactions} = profilerStore.getDataForRoot(rootID);
const {
duration,
effectDuration,
interactionIDs,
passiveEffectDuration,
priorityLevel,
timestamp,
} = profilerStore.getCommitData(rootID, selectedCommitIndex);
Expand All @@ -44,6 +46,9 @@ export default function SidebarCommitInfo(_: Props) {
selectInteraction(interactionID);
};

const hasCommitPhaseDurations =
effectDuration !== null || passiveEffectDuration !== null;

return (
<Fragment>
<div className={styles.Toolbar}>Commit information</div>
Expand All @@ -59,10 +64,44 @@ export default function SidebarCommitInfo(_: Props) {
<label className={styles.Label}>Committed at</label>:{' '}
<span className={styles.Value}>{formatTime(timestamp)}s</span>
</li>
<li className={styles.ListItem}>
<label className={styles.Label}>Render duration</label>:{' '}
<span className={styles.Value}>{formatDuration(duration)}ms</span>
</li>

{!hasCommitPhaseDurations && (
<li className={styles.ListItem}>
<label className={styles.Label}>Render duration</label>:{' '}
<span className={styles.Value}>{formatDuration(duration)}ms</span>
</li>
)}

{hasCommitPhaseDurations && (
<li className={styles.ListItem}>
<label className={styles.Label}>Durations</label>
<ul className={styles.DurationsList}>
<li className={styles.DurationsListItem}>
<label className={styles.Label}>Render</label>:{' '}
<span className={styles.Value}>
{formatDuration(duration)}ms
</span>
</li>
{effectDuration !== null && (
<li className={styles.DurationsListItem}>
<label className={styles.Label}>Layout effects</label>:{' '}
<span className={styles.Value}>
{formatDuration(effectDuration)}ms
</span>
</li>
)}
{passiveEffectDuration !== null && (
<li className={styles.DurationsListItem}>
<label className={styles.Label}>Passive effects</label>:{' '}
<span className={styles.Value}>
{formatDuration(passiveEffectDuration)}ms
</span>
</li>
)}
</ul>
</li>
)}

<li className={styles.Interactions}>
<label className={styles.Label}>Interactions</label>:
<div className={styles.InteractionList}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,56 @@
*/
overflow-x: hidden !important;
}

.Tooltip {
margin-top: 2.5rem;
}

.TooltipList {
list-style: none;
padding: 0;
margin: 0;
}

.TooltipListItem {
display: flex;
}

.TooltipLabel {
font-weight: bold;
margin-right: 0.25rem;
}
.TooltipLabel:after {
content: ':';
}

.TooltipValue {
flex-grow: 1;
text-align: end;
}

.DurationsWrapper {
flex-grow: 1;
}

.DurationsList {
list-style: none;
margin: 0 0 0 1rem;
padding: 0;
}

.DurationsListItem {
display: flex;
}

.DurationsLabel {
margin-right: 0.25rem;
}
.DurationsLabel:after {
content: ':';
}

.DurationsValue {
flex-grow: 1;
text-align: end;
}
Loading