Skip to content

Commit

Permalink
DevTools Profiler: Add commit and post-commit durations to UI (#20984)
Browse files Browse the repository at this point in the history
  • Loading branch information
Brian Vaughn authored Mar 17, 2021
1 parent 825c302 commit bf11788
Show file tree
Hide file tree
Showing 14 changed files with 403 additions and 43 deletions.

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

0 comments on commit bf11788

Please sign in to comment.