Skip to content

Commit 6af7d21

Browse files
author
Brian Vaughn
committedMar 11, 2021
Add commit and post-commit durations to DevTools Profiler
1 parent 7642d82 commit 6af7d21

File tree

14 files changed

+312
-15
lines changed

14 files changed

+312
-15
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/ProfilerStore.js

+1
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ export default class ProfilerStore extends EventEmitter<{|
250250
};
251251

252252
onBridgeProfilingData = (dataBackend: ProfilingDataBackend) => {
253+
console.log('onBridgeProfilingData()', dataBackend);
253254
if (this._isProfiling) {
254255
// This should never happen, but if it does- ignore previous profiling data.
255256
return;

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

+18
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);
@@ -63,6 +65,22 @@ export default function SidebarCommitInfo(_: Props) {
6365
<label className={styles.Label}>Render duration</label>:{' '}
6466
<span className={styles.Value}>{formatDuration(duration)}ms</span>
6567
</li>
68+
{effectDuration !== null && (
69+
<li className={styles.ListItem}>
70+
<label className={styles.Label}>Layout effects duration</label>:{' '}
71+
<span className={styles.Value}>
72+
{formatDuration(effectDuration)}ms
73+
</span>
74+
</li>
75+
)}
76+
{passiveEffectDuration !== null && (
77+
<li className={styles.ListItem}>
78+
<label className={styles.Label}>Passive effects duration</label>:{' '}
79+
<span className={styles.Value}>
80+
{formatDuration(passiveEffectDuration)}ms
81+
</span>
82+
</li>
83+
)}
6684
<li className={styles.Interactions}>
6785
<label className={styles.Label}>Interactions</label>:
6886
<div className={styles.InteractionList}>

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

+27
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,30 @@
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+
}

‎packages/react-devtools-shared/src/devtools/views/Profiler/SnapshotCommitList.js

+66-6
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
* @flow
88
*/
99

10+
import type {CommitDataFrontend} from './types';
11+
1012
import * as React from 'react';
1113
import {useEffect, useMemo, useRef, useState} from 'react';
1214
import AutoSizer from 'react-virtualized-auto-sizer';
@@ -31,6 +33,7 @@ export type ItemData = {|
3133
|};
3234

3335
type Props = {|
36+
commitData: CommitDataFrontend,
3437
commitDurations: Array<number>,
3538
commitTimes: Array<number>,
3639
filteredCommitIndices: Array<number>,
@@ -40,6 +43,7 @@ type Props = {|
4043
|};
4144

4245
export default function SnapshotCommitList({
46+
commitData,
4347
commitDurations,
4448
commitTimes,
4549
filteredCommitIndices,
@@ -51,6 +55,7 @@ export default function SnapshotCommitList({
5155
<AutoSizer>
5256
{({height, width}) => (
5357
<List
58+
commitData={commitData}
5459
commitDurations={commitDurations}
5560
commitTimes={commitTimes}
5661
height={height}
@@ -66,6 +71,7 @@ export default function SnapshotCommitList({
6671
}
6772

6873
type ListProps = {|
74+
commitData: CommitDataFrontend,
6975
commitDurations: Array<number>,
7076
commitTimes: Array<number>,
7177
height: number,
@@ -83,6 +89,7 @@ type DragState = {
8389
};
8490

8591
function List({
92+
commitData,
8693
commitDurations,
8794
selectedCommitIndex,
8895
commitTimes,
@@ -200,15 +207,68 @@ function List({
200207

201208
let tooltipLabel = null;
202209
if (hoveredCommitIndex !== null) {
203-
const commitDuration = commitDurations[hoveredCommitIndex];
204-
const commitTime = commitTimes[hoveredCommitIndex];
205-
tooltipLabel = `${formatDuration(commitDuration)}ms at ${formatTime(
206-
commitTime,
207-
)}s`;
210+
const {
211+
duration,
212+
effectDuration,
213+
passiveEffectDuration,
214+
priorityLevel,
215+
timestamp,
216+
} = commitData[hoveredCommitIndex];
217+
218+
// Only some React versions include commit durations.
219+
// Show a richer tooltip only for builds that have that info.
220+
if (effectDuration > 0 || passiveEffectDuration > 0) {
221+
tooltipLabel = (
222+
<ul className={styles.TooltipList}>
223+
{priorityLevel !== null && (
224+
<li className={styles.TooltipListItem}>
225+
<label className={styles.TooltipLabel}>Priority</label>
226+
<span className={styles.TooltipValue}>{priorityLevel}</span>
227+
</li>
228+
)}
229+
<li className={styles.TooltipListItem}>
230+
<label className={styles.TooltipLabel}>Committed at</label>
231+
<span className={styles.TooltipValue}>
232+
{formatTime(timestamp)}s
233+
</span>
234+
</li>
235+
<li className={styles.TooltipListItem}>
236+
<label className={styles.TooltipLabel}>Render duration</label>
237+
<span className={styles.TooltipValue}>
238+
{formatDuration(duration)}ms
239+
</span>
240+
</li>
241+
{effectDuration !== null && (
242+
<li className={styles.TooltipListItem}>
243+
<label className={styles.TooltipLabel}>
244+
Layout effects duration
245+
</label>
246+
<span className={styles.TooltipValue}>
247+
{formatDuration(effectDuration)}ms
248+
</span>
249+
</li>
250+
)}
251+
{passiveEffectDuration !== null && (
252+
<li className={styles.TooltipListItem}>
253+
<label className={styles.TooltipLabel}>
254+
Passive effects duration
255+
</label>
256+
<span className={styles.TooltipValue}>
257+
{formatDuration(passiveEffectDuration)}ms
258+
</span>
259+
</li>
260+
)}
261+
</ul>
262+
);
263+
} else {
264+
tooltipLabel = `${formatDuration(duration)}ms at ${formatTime(
265+
timestamp,
266+
)}s`;
267+
}
208268
}
209269

210270
return (
211-
<Tooltip label={tooltipLabel}>
271+
<Tooltip className={styles.Tooltip} label={tooltipLabel}>
212272
<div
213273
ref={divRef}
214274
style={{height, width}}

‎packages/react-devtools-shared/src/devtools/views/Profiler/SnapshotCommitListItem.css

+6-1
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,14 @@
1111
background-color: var(--color-background);
1212
}
1313

14-
.Inner {
14+
.Inner,
15+
.InnerSelected {
1516
width: 100%;
1617
min-height: 2px;
1718
background-color: var(--color-commit-did-not-render-fill);
1819
color: var(--color-commit-did-not-render-fill-text);
1920
}
21+
22+
.InnerSelected {
23+
background-color: var(--color-button-active);
24+
}

‎packages/react-devtools-shared/src/devtools/views/Profiler/SnapshotCommitListItem.js

+7-3
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ function SnapshotCommitListItem({data: itemData, index, style}: Props) {
7171
}
7272
};
7373

74+
let backgroundColor;
75+
if (!isSelected && commitDuration > 0) {
76+
backgroundColor = getGradientColor(colorScale);
77+
}
78+
7479
return (
7580
<div
7681
className={styles.Outer}
@@ -87,11 +92,10 @@ function SnapshotCommitListItem({data: itemData, index, style}: Props) {
8792
commitTime,
8893
)}s`}>
8994
<div
90-
className={styles.Inner}
95+
className={isSelected ? styles.InnerSelected : styles.Inner}
9196
style={{
9297
height: `${Math.round(heightScale * 100)}%`,
93-
backgroundColor:
94-
commitDuration > 0 ? getGradientColor(colorScale) : undefined,
98+
backgroundColor,
9599
}}
96100
/>
97101
</div>

‎packages/react-devtools-shared/src/devtools/views/Profiler/SnapshotSelector.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,11 @@ export default function SnapshotSelector(_: Props) {
3535
const commitDurations: Array<number> = [];
3636
const commitTimes: Array<number> = [];
3737
commitData.forEach(commitDatum => {
38-
commitDurations.push(commitDatum.duration);
38+
commitDurations.push(
39+
commitDatum.duration +
40+
(commitDatum.effectDuration || 0) +
41+
(commitDatum.passiveEffectDuration || 0),
42+
);
3943
commitTimes.push(commitDatum.timestamp);
4044
});
4145

@@ -151,6 +155,7 @@ export default function SnapshotSelector(_: Props) {
151155
tabIndex={0}>
152156
{numFilteredCommits > 0 && (
153157
<SnapshotCommitList
158+
commitData={commitData}
154159
commitDurations={commitDurations}
155160
commitTimes={commitTimes}
156161
filteredCommitIndices={filteredCommitIndices}

‎packages/react-devtools-shared/src/devtools/views/Profiler/Tooltip.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import styles from './Tooltip.css';
77

88
const initialTooltipState = {height: 0, mouseX: 0, mouseY: 0, width: 0};
99

10-
export default function Tooltip({children, label}: any) {
10+
export default function Tooltip({children, className, label, style}: any) {
1111
const containerRef = useRef(null);
1212
const tooltipRef = useRef(null);
1313

@@ -36,7 +36,10 @@ export default function Tooltip({children, label}: any) {
3636
className={styles.Container}
3737
onMouseMove={onMouseMove}
3838
ref={containerRef}>
39-
<div ref={tooltipRef} className={`${styles.Tooltip} ${tooltipClassName}`}>
39+
<div
40+
className={`${styles.Tooltip} ${tooltipClassName} ${className || ''}`}
41+
ref={tooltipRef}
42+
style={style}>
4043
{label}
4144
</div>
4245
{children}

0 commit comments

Comments
 (0)