Skip to content

Commit d0bf2f7

Browse files
Brian Vaughnzhengjitf
Brian Vaughn
authored andcommitted
DevTools Profiler: Add commit and post-commit durations to UI (facebook#20984)
1 parent 2facf5e commit d0bf2f7

File tree

14 files changed

+403
-43
lines changed

14 files changed

+403
-43
lines changed

packages/react-devtools-shared/src/__tests__/__snapshots__/profilingCache-test.js.snap

+94
Large diffs are not rendered by default.

packages/react-devtools-shared/src/backend/renderer.js

+46
Original file line numberDiff line numberDiff line change
@@ -2097,6 +2097,25 @@ export function attach(
20972097
// Checking root.memoizedInteractions handles multi-renderer edge-case-
20982098
// where some v16 renderers support profiling and others don't.
20992099
if (isProfiling && root.memoizedInteractions != null) {
2100+
// Profiling durations are only available for certain builds.
2101+
// If available, they'll be stored on the HostRoot.
2102+
let effectDuration = null;
2103+
let passiveEffectDuration = null;
2104+
const hostRoot = root.current;
2105+
if (hostRoot != null) {
2106+
const stateNode = hostRoot.stateNode;
2107+
if (stateNode != null) {
2108+
effectDuration =
2109+
stateNode.effectDuration != null
2110+
? stateNode.effectDuration
2111+
: null;
2112+
passiveEffectDuration =
2113+
stateNode.passiveEffectDuration != null
2114+
? stateNode.passiveEffectDuration
2115+
: null;
2116+
}
2117+
}
2118+
21002119
// If profiling is active, store commit time and duration, and the current interactions.
21012120
// The frontend may request this information after profiling has stopped.
21022121
currentCommitProfilingMetadata = {
@@ -2111,6 +2130,8 @@ export function attach(
21112130
),
21122131
maxActualDuration: 0,
21132132
priorityLevel: null,
2133+
effectDuration,
2134+
passiveEffectDuration,
21142135
};
21152136
}
21162137

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

21512172
if (isProfiling && isProfilingSupported) {
2173+
// Profiling durations are only available for certain builds.
2174+
// If available, they'll be stored on the HostRoot.
2175+
let effectDuration = null;
2176+
let passiveEffectDuration = null;
2177+
const hostRoot = root.current;
2178+
if (hostRoot != null) {
2179+
const stateNode = hostRoot.stateNode;
2180+
if (stateNode != null) {
2181+
effectDuration =
2182+
stateNode.effectDuration != null ? stateNode.effectDuration : null;
2183+
passiveEffectDuration =
2184+
stateNode.passiveEffectDuration != null
2185+
? stateNode.passiveEffectDuration
2186+
: null;
2187+
}
2188+
}
2189+
21522190
// If profiling is active, store commit time and duration, and the current interactions.
21532191
// The frontend may request this information after profiling has stopped.
21542192
currentCommitProfilingMetadata = {
@@ -2164,6 +2202,8 @@ export function attach(
21642202
maxActualDuration: 0,
21652203
priorityLevel:
21662204
priorityLevel == null ? null : formatPriorityLevel(priorityLevel),
2205+
effectDuration,
2206+
passiveEffectDuration,
21672207
};
21682208
}
21692209

@@ -3294,8 +3334,10 @@ export function attach(
32943334
changeDescriptions: Map<number, ChangeDescription> | null,
32953335
commitTime: number,
32963336
durations: Array<number>,
3337+
effectDuration: number | null,
32973338
interactions: Array<Interaction>,
32983339
maxActualDuration: number,
3340+
passiveEffectDuration: number | null,
32993341
priorityLevel: string | null,
33003342
|};
33013343

@@ -3349,8 +3391,10 @@ export function attach(
33493391
const {
33503392
changeDescriptions,
33513393
durations,
3394+
effectDuration,
33523395
interactions,
33533396
maxActualDuration,
3397+
passiveEffectDuration,
33543398
priorityLevel,
33553399
commitTime,
33563400
} = commitProfilingData;
@@ -3386,9 +3430,11 @@ export function attach(
33863430
? Array.from(changeDescriptions.entries())
33873431
: null,
33883432
duration: maxActualDuration,
3433+
effectDuration,
33893434
fiberActualDurations,
33903435
fiberSelfDurations,
33913436
interactionIDs,
3437+
passiveEffectDuration,
33923438
priorityLevel,
33933439
timestamp: commitTime,
33943440
});

packages/react-devtools-shared/src/backend/types.js

+4
Original file line numberDiff line numberDiff line change
@@ -156,11 +156,15 @@ export type CommitDataBackend = {|
156156
// Tuple of fiber ID and change description
157157
changeDescriptions: Array<[number, ChangeDescription]> | null,
158158
duration: number,
159+
// Only available in certain (newer) React builds,
160+
effectDuration: number | null,
159161
// Tuple of fiber ID and actual duration
160162
fiberActualDurations: Array<[number, number]>,
161163
// Tuple of fiber ID and computed "self" duration
162164
fiberSelfDurations: Array<[number, number]>,
163165
interactionIDs: Array<number>,
166+
// Only available in certain (newer) React builds,
167+
passiveEffectDuration: number | null,
164168
priorityLevel: string | null,
165169
timestamp: number,
166170
|};

packages/react-devtools-shared/src/devtools/views/Profiler/SidebarCommitInfo.css

+16
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,19 @@
6363
height: 100%;
6464
color: var(--color-dim);
6565
}
66+
67+
.DurationsList {
68+
list-style: none;
69+
margin: 0.25rem 0 0 0;
70+
padding: 0;
71+
background: var(--color-background-inactive);
72+
padding: 0.25rem 0.5rem;
73+
border-radius: 0.25rem;
74+
}
75+
76+
.DurationsListItem {
77+
margin: 0.25rem 0 0 0;
78+
}
79+
.DurationsListItem:first-of-type {
80+
margin: 0;
81+
}

packages/react-devtools-shared/src/devtools/views/Profiler/SidebarCommitInfo.js

+43-4
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ export default function SidebarCommitInfo(_: Props) {
3434
const {interactions} = profilerStore.getDataForRoot(rootID);
3535
const {
3636
duration,
37+
effectDuration,
3738
interactionIDs,
39+
passiveEffectDuration,
3840
priorityLevel,
3941
timestamp,
4042
} = profilerStore.getCommitData(rootID, selectedCommitIndex);
@@ -44,6 +46,9 @@ export default function SidebarCommitInfo(_: Props) {
4446
selectInteraction(interactionID);
4547
};
4648

49+
const hasCommitPhaseDurations =
50+
effectDuration !== null || passiveEffectDuration !== null;
51+
4752
return (
4853
<Fragment>
4954
<div className={styles.Toolbar}>Commit information</div>
@@ -59,10 +64,44 @@ export default function SidebarCommitInfo(_: Props) {
5964
<label className={styles.Label}>Committed at</label>:{' '}
6065
<span className={styles.Value}>{formatTime(timestamp)}s</span>
6166
</li>
62-
<li className={styles.ListItem}>
63-
<label className={styles.Label}>Render duration</label>:{' '}
64-
<span className={styles.Value}>{formatDuration(duration)}ms</span>
65-
</li>
67+
68+
{!hasCommitPhaseDurations && (
69+
<li className={styles.ListItem}>
70+
<label className={styles.Label}>Render duration</label>:{' '}
71+
<span className={styles.Value}>{formatDuration(duration)}ms</span>
72+
</li>
73+
)}
74+
75+
{hasCommitPhaseDurations && (
76+
<li className={styles.ListItem}>
77+
<label className={styles.Label}>Durations</label>
78+
<ul className={styles.DurationsList}>
79+
<li className={styles.DurationsListItem}>
80+
<label className={styles.Label}>Render</label>:{' '}
81+
<span className={styles.Value}>
82+
{formatDuration(duration)}ms
83+
</span>
84+
</li>
85+
{effectDuration !== null && (
86+
<li className={styles.DurationsListItem}>
87+
<label className={styles.Label}>Layout effects</label>:{' '}
88+
<span className={styles.Value}>
89+
{formatDuration(effectDuration)}ms
90+
</span>
91+
</li>
92+
)}
93+
{passiveEffectDuration !== null && (
94+
<li className={styles.DurationsListItem}>
95+
<label className={styles.Label}>Passive effects</label>:{' '}
96+
<span className={styles.Value}>
97+
{formatDuration(passiveEffectDuration)}ms
98+
</span>
99+
</li>
100+
)}
101+
</ul>
102+
</li>
103+
)}
104+
66105
<li className={styles.Interactions}>
67106
<label className={styles.Label}>Interactions</label>:
68107
<div className={styles.InteractionList}>

packages/react-devtools-shared/src/devtools/views/Profiler/SnapshotCommitList.css

+53
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,56 @@
77
*/
88
overflow-x: hidden !important;
99
}
10+
11+
.Tooltip {
12+
margin-top: 2.5rem;
13+
}
14+
15+
.TooltipList {
16+
list-style: none;
17+
padding: 0;
18+
margin: 0;
19+
}
20+
21+
.TooltipListItem {
22+
display: flex;
23+
}
24+
25+
.TooltipLabel {
26+
font-weight: bold;
27+
margin-right: 0.25rem;
28+
}
29+
.TooltipLabel:after {
30+
content: ':';
31+
}
32+
33+
.TooltipValue {
34+
flex-grow: 1;
35+
text-align: end;
36+
}
37+
38+
.DurationsWrapper {
39+
flex-grow: 1;
40+
}
41+
42+
.DurationsList {
43+
list-style: none;
44+
margin: 0 0 0 1rem;
45+
padding: 0;
46+
}
47+
48+
.DurationsListItem {
49+
display: flex;
50+
}
51+
52+
.DurationsLabel {
53+
margin-right: 0.25rem;
54+
}
55+
.DurationsLabel:after {
56+
content: ':';
57+
}
58+
59+
.DurationsValue {
60+
flex-grow: 1;
61+
text-align: end;
62+
}

0 commit comments

Comments
 (0)