Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit a8725a3

Browse files
author
Brian Vaughn
authoredAug 5, 2021
Scheduling profiler: Added lane labels and durations to React measures (#22029)
1 parent 19092ac commit a8725a3

File tree

16 files changed

+1297
-778
lines changed

16 files changed

+1297
-778
lines changed
 

‎packages/react-devtools-scheduling-profiler/src/EventTooltip.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ export default function EventTooltip({
105105
} else if (schedulingEvent !== null) {
106106
return (
107107
<TooltipSchedulingEvent
108+
data={data}
108109
schedulingEvent={schedulingEvent}
109110
tooltipRef={tooltipRef}
110111
/>
@@ -234,9 +235,11 @@ const TooltipNativeEvent = ({
234235
};
235236

236237
const TooltipSchedulingEvent = ({
238+
data,
237239
schedulingEvent,
238240
tooltipRef,
239241
}: {
242+
data: ReactProfilerData,
240243
schedulingEvent: SchedulingEvent,
241244
tooltipRef: Return<typeof useRef>,
242245
}) => {
@@ -257,8 +260,10 @@ const TooltipSchedulingEvent = ({
257260
case 'schedule-render':
258261
case 'schedule-state-update':
259262
case 'schedule-force-update':
260-
laneLabels = schedulingEvent.laneLabels;
261263
lanes = schedulingEvent.lanes;
264+
laneLabels = lanes.map(
265+
lane => ((data.laneToLabelMap.get(lane): any): string),
266+
);
262267
break;
263268
}
264269

@@ -366,9 +371,13 @@ const TooltipReactMeasure = ({
366371
return null;
367372
}
368373

369-
const {batchUID, duration, timestamp, lanes, laneLabels} = measure;
374+
const {batchUID, duration, timestamp, lanes} = measure;
370375
const [startTime, stopTime] = getBatchRange(batchUID, data);
371376

377+
const laneLabels = lanes.map(
378+
lane => ((data.laneToLabelMap.get(lane): any): string),
379+
);
380+
372381
return (
373382
<div className={styles.Tooltip} ref={tooltipRef}>
374383
<div className={styles.TooltipSection}>

‎packages/react-devtools-scheduling-profiler/src/constants.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,6 @@ export {
1313
} from 'react-devtools-shared/src/constants.js';
1414

1515
export const REACT_TOTAL_NUM_LANES = 31;
16+
17+
// Increment this number any time a backwards breaking change is made to the profiler metadata.
18+
export const SCHEDULING_PROFILER_VERSION = 1;

‎packages/react-devtools-scheduling-profiler/src/content-views/ComponentMeasuresView.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,7 @@ export class ComponentMeasuresView extends View {
161161
context,
162162
visibleArea,
163163
visibleArea,
164-
'center',
165-
COLORS.TEXT_DIM_COLOR,
164+
{fillStyle: COLORS.TEXT_DIM_COLOR, textAlign: 'center'},
166165
);
167166
}
168167

‎packages/react-devtools-scheduling-profiler/src/content-views/ReactMeasuresView.js

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import type {
1616
ViewRefs,
1717
} from '../view-base';
1818

19+
import {formatDuration} from '../utils/formatting';
20+
import {drawText} from './utils/text';
1921
import {
2022
durationToWidth,
2123
positioningScaleFactor,
@@ -102,17 +104,19 @@ export class ReactMeasuresView extends View {
102104
context: CanvasRenderingContext2D,
103105
rect: Rect,
104106
measure: ReactMeasure,
107+
nextMeasure: ReactMeasure | null,
105108
baseY: number,
106109
scaleFactor: number,
107110
showGroupHighlight: boolean,
108111
showHoverHighlight: boolean,
109112
) {
110-
const {frame} = this;
113+
const {frame, visibleArea} = this;
111114
const {timestamp, type, duration} = measure;
112115

113116
let fillStyle = null;
114117
let hoveredFillStyle = null;
115118
let groupSelectedFillStyle = null;
119+
let textFillStyle = null;
116120

117121
// We could change the max to 0 and just skip over rendering anything that small,
118122
// but this has the effect of making the chart look very empty when zoomed out.
@@ -131,11 +135,29 @@ export class ReactMeasuresView extends View {
131135
return; // Not in view
132136
}
133137

138+
const drawableRect = intersectionOfRects(measureRect, rect);
139+
let textRect = measureRect;
140+
134141
switch (type) {
135142
case 'commit':
136143
fillStyle = COLORS.REACT_COMMIT;
137144
hoveredFillStyle = COLORS.REACT_COMMIT_HOVER;
138145
groupSelectedFillStyle = COLORS.REACT_COMMIT_HOVER;
146+
textFillStyle = COLORS.REACT_COMMIT_TEXT;
147+
148+
// Commit phase rects are overlapped by layout and passive rects,
149+
// and it looks bad if text flows underneath/behind these overlayed rects.
150+
if (nextMeasure != null) {
151+
textRect = {
152+
...measureRect,
153+
size: {
154+
width:
155+
timestampToPosition(nextMeasure.timestamp, scaleFactor, frame) -
156+
x,
157+
height: REACT_MEASURE_HEIGHT,
158+
},
159+
};
160+
}
139161
break;
140162
case 'render-idle':
141163
// We could render idle time as diagonal hashes.
@@ -149,22 +171,24 @@ export class ReactMeasuresView extends View {
149171
fillStyle = COLORS.REACT_RENDER;
150172
hoveredFillStyle = COLORS.REACT_RENDER_HOVER;
151173
groupSelectedFillStyle = COLORS.REACT_RENDER_HOVER;
174+
textFillStyle = COLORS.REACT_RENDER_TEXT;
152175
break;
153176
case 'layout-effects':
154177
fillStyle = COLORS.REACT_LAYOUT_EFFECTS;
155178
hoveredFillStyle = COLORS.REACT_LAYOUT_EFFECTS_HOVER;
156179
groupSelectedFillStyle = COLORS.REACT_LAYOUT_EFFECTS_HOVER;
180+
textFillStyle = COLORS.REACT_LAYOUT_EFFECTS_TEXT;
157181
break;
158182
case 'passive-effects':
159183
fillStyle = COLORS.REACT_PASSIVE_EFFECTS;
160184
hoveredFillStyle = COLORS.REACT_PASSIVE_EFFECTS_HOVER;
161185
groupSelectedFillStyle = COLORS.REACT_PASSIVE_EFFECTS_HOVER;
186+
textFillStyle = COLORS.REACT_PASSIVE_EFFECTS_TEXT;
162187
break;
163188
default:
164189
throw new Error(`Unexpected measure type "${type}"`);
165190
}
166191

167-
const drawableRect = intersectionOfRects(measureRect, rect);
168192
context.fillStyle = showHoverHighlight
169193
? hoveredFillStyle
170194
: showGroupHighlight
@@ -176,6 +200,12 @@ export class ReactMeasuresView extends View {
176200
drawableRect.size.width,
177201
drawableRect.size.height,
178202
);
203+
204+
if (textFillStyle !== null) {
205+
drawText(formatDuration(duration), context, textRect, visibleArea, {
206+
fillStyle: textFillStyle,
207+
});
208+
}
179209
}
180210

181211
draw(context: CanvasRenderingContext2D) {
@@ -211,6 +241,27 @@ export class ReactMeasuresView extends View {
211241
);
212242
}
213243

244+
// Render lane labels
245+
const label = this._profilerData.laneToLabelMap.get(lane);
246+
if (label == null) {
247+
console.warn(`Could not find label for lane ${lane}.`);
248+
} else {
249+
const labelRect = {
250+
origin: {
251+
x: visibleArea.origin.x,
252+
y: baseY,
253+
},
254+
size: {
255+
width: visibleArea.size.width,
256+
height: REACT_LANE_HEIGHT,
257+
},
258+
};
259+
260+
drawText(label, context, labelRect, visibleArea, {
261+
fillStyle: COLORS.TEXT_DIM_COLOR,
262+
});
263+
}
264+
214265
// Draw measures
215266
for (let j = 0; j < measuresForLane.length; j++) {
216267
const measure = measuresForLane[j];
@@ -222,6 +273,7 @@ export class ReactMeasuresView extends View {
222273
context,
223274
visibleArea,
224275
measure,
276+
measuresForLane[j + 1] || null,
225277
baseY,
226278
scaleFactor,
227279
showGroupHighlight,

‎packages/react-devtools-scheduling-profiler/src/content-views/constants.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export const SUSPENSE_EVENT_HEIGHT = 14;
1919
export const PENDING_SUSPENSE_EVENT_SIZE = 8;
2020
export const REACT_EVENT_DIAMETER = 6;
2121
export const USER_TIMING_MARK_SIZE = 8;
22-
export const REACT_MEASURE_HEIGHT = 9;
22+
export const REACT_MEASURE_HEIGHT = 14;
2323
export const BORDER_SIZE = 1;
2424
export const FLAMECHART_FRAME_HEIGHT = 14;
2525
export const TEXT_PADDING = 3;
@@ -56,12 +56,16 @@ export let COLORS = {
5656
REACT_IDLE_HOVER: '',
5757
REACT_RENDER: '',
5858
REACT_RENDER_HOVER: '',
59+
REACT_RENDER_TEXT: '',
5960
REACT_COMMIT: '',
6061
REACT_COMMIT_HOVER: '',
62+
REACT_COMMIT_TEXT: '',
6163
REACT_LAYOUT_EFFECTS: '',
6264
REACT_LAYOUT_EFFECTS_HOVER: '',
65+
REACT_LAYOUT_EFFECTS_TEXT: '',
6366
REACT_PASSIVE_EFFECTS: '',
6467
REACT_PASSIVE_EFFECTS_HOVER: '',
68+
REACT_PASSIVE_EFFECTS_TEXT: '',
6569
REACT_RESIZE_BAR: '',
6670
REACT_RESIZE_BAR_ACTIVE: '',
6771
REACT_RESIZE_BAR_BORDER: '',
@@ -132,24 +136,36 @@ export function updateColorsToMatchTheme(element: Element): boolean {
132136
REACT_RENDER_HOVER: computedStyle.getPropertyValue(
133137
'--color-scheduling-profiler-react-render-hover',
134138
),
139+
REACT_RENDER_TEXT: computedStyle.getPropertyValue(
140+
'--color-scheduling-profiler-react-render-text',
141+
),
135142
REACT_COMMIT: computedStyle.getPropertyValue(
136143
'--color-scheduling-profiler-react-commit',
137144
),
138145
REACT_COMMIT_HOVER: computedStyle.getPropertyValue(
139146
'--color-scheduling-profiler-react-commit-hover',
140147
),
148+
REACT_COMMIT_TEXT: computedStyle.getPropertyValue(
149+
'--color-scheduling-profiler-react-commit-text',
150+
),
141151
REACT_LAYOUT_EFFECTS: computedStyle.getPropertyValue(
142152
'--color-scheduling-profiler-react-layout-effects',
143153
),
144154
REACT_LAYOUT_EFFECTS_HOVER: computedStyle.getPropertyValue(
145155
'--color-scheduling-profiler-react-layout-effects-hover',
146156
),
157+
REACT_LAYOUT_EFFECTS_TEXT: computedStyle.getPropertyValue(
158+
'--color-scheduling-profiler-react-layout-effects-text',
159+
),
147160
REACT_PASSIVE_EFFECTS: computedStyle.getPropertyValue(
148161
'--color-scheduling-profiler-react-passive-effects',
149162
),
150163
REACT_PASSIVE_EFFECTS_HOVER: computedStyle.getPropertyValue(
151164
'--color-scheduling-profiler-react-passive-effects-hover',
152165
),
166+
REACT_PASSIVE_EFFECTS_TEXT: computedStyle.getPropertyValue(
167+
'--color-scheduling-profiler-react-passive-effects-text',
168+
),
153169
REACT_RESIZE_BAR: computedStyle.getPropertyValue('--color-resize-bar'),
154170
REACT_RESIZE_BAR_ACTIVE: computedStyle.getPropertyValue(
155171
'--color-resize-bar-active',

‎packages/react-devtools-scheduling-profiler/src/content-views/utils/text.js

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,40 +14,57 @@ import {COLORS, FONT_SIZE, TEXT_PADDING} from '../constants';
1414

1515
const cachedTextWidths = new Map();
1616

17+
export function getTextWidth(
18+
context: CanvasRenderingContext2D,
19+
text: string,
20+
): number {
21+
let measuredWidth = cachedTextWidths.get(text);
22+
if (measuredWidth == null) {
23+
measuredWidth = context.measureText(text).width;
24+
cachedTextWidths.set(text, measuredWidth);
25+
}
26+
27+
return ((measuredWidth: any): number);
28+
}
29+
1730
export function trimText(
1831
context: CanvasRenderingContext2D,
1932
text: string,
2033
width: number,
2134
): string | null {
2235
for (let i = text.length - 1; i >= 0; i--) {
2336
const trimmedText = i === text.length - 1 ? text : text.substr(0, i) + '…';
24-
25-
let measuredWidth = cachedTextWidths.get(trimmedText);
26-
if (measuredWidth == null) {
27-
measuredWidth = context.measureText(trimmedText).width;
28-
cachedTextWidths.set(trimmedText, measuredWidth);
29-
}
30-
31-
if (measuredWidth <= width) {
37+
if (getTextWidth(context, trimmedText) <= width) {
3238
return trimmedText;
3339
}
3440
}
3541

3642
return null;
3743
}
3844

45+
type TextConfig = {|
46+
fillStyle?: string,
47+
fontSize?: number,
48+
textAlign?: 'left' | 'center',
49+
|};
50+
3951
export function drawText(
4052
text: string,
4153
context: CanvasRenderingContext2D,
4254
fullRect: Rect,
4355
drawableRect: Rect,
44-
textAlign: 'left' | 'center' = 'left',
45-
fillStyle: string = COLORS.TEXT_COLOR,
56+
config?: TextConfig,
4657
): void {
58+
const {
59+
fillStyle = COLORS.TEXT_COLOR,
60+
fontSize = FONT_SIZE,
61+
textAlign = 'left',
62+
} = config || {};
63+
4764
if (fullRect.size.width > TEXT_PADDING * 2) {
4865
context.textAlign = textAlign;
4966
context.textBaseline = 'middle';
50-
context.font = `${FONT_SIZE}px sans-serif`;
67+
context.font = `${fontSize}px sans-serif`;
5168

5269
const {x, y} = fullRect.origin;
5370

‎packages/react-devtools-scheduling-profiler/src/import-worker/__tests__/preprocessData-test.internal.js

Lines changed: 510 additions & 299 deletions
Large diffs are not rendered by default.

‎packages/react-devtools-scheduling-profiler/src/import-worker/preprocessData.js

Lines changed: 73 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,15 @@ import type {
1717
BatchUID,
1818
Flamechart,
1919
NativeEvent,
20+
Phase,
2021
ReactLane,
2122
ReactComponentMeasure,
2223
ReactMeasureType,
2324
ReactProfilerData,
2425
SuspenseEvent,
2526
} from '../types';
2627

27-
import {REACT_TOTAL_NUM_LANES} from '../constants';
28+
import {REACT_TOTAL_NUM_LANES, SCHEDULING_PROFILER_VERSION} from '../constants';
2829
import InvalidProfileError from './InvalidProfileError';
2930

3031
type MeasureStackElement = {|
@@ -52,7 +53,7 @@ const WARNING_STRINGS = {
5253
'An event handler scheduled a big update with React. Consider using the Transition API to defer some of this work.',
5354
NESTED_UPDATE:
5455
'A nested update was scheduled during layout. These updates require React to re-render synchronously before the browser can paint.',
55-
SUSPENDD_DURING_UPATE:
56+
SUSPEND_DURING_UPATE:
5657
'A component suspended during an update which caused a fallback to be shown. ' +
5758
"Consider using the Transition API to avoid hiding components after they've been mounted.",
5859
};
@@ -80,6 +81,23 @@ export function getLanesFromTransportDecimalBitmask(
8081
return lanes;
8182
}
8283

84+
const laneToLabelMap: Map<number, string> = new Map();
85+
function updateLaneToLabelMap(laneLabelTuplesString: string): void {
86+
// These marks appear multiple times in the data;
87+
// We only need to extact them once.
88+
if (laneToLabelMap.size === 0) {
89+
const laneLabelTuples = laneLabelTuplesString.split(',');
90+
for (let laneIndex = 0; laneIndex < laneLabelTuples.length; laneIndex++) {
91+
// The numeric lane value (e.g. 64) isn't important.
92+
// The profiler parses and stores the lane's position within the bitmap,
93+
// (e.g. lane 1 is index 0, lane 16 is index 4).
94+
laneToLabelMap.set(laneIndex, laneLabelTuples[laneIndex]);
95+
}
96+
}
97+
}
98+
99+
let profilerVersion = null;
100+
83101
function getLastType(stack: $PropertyType<ProcessorState, 'measureStack'>) {
84102
if (stack.length > 0) {
85103
const {type} = stack[stack.length - 1];
@@ -100,7 +118,6 @@ function markWorkStarted(
100118
type: ReactMeasureType,
101119
startTime: Milliseconds,
102120
lanes: ReactLane[],
103-
laneLabels: Array<string>,
104121
currentProfilerData: ReactProfilerData,
105122
state: ProcessorState,
106123
) {
@@ -115,7 +132,6 @@ function markWorkStarted(
115132
batchUID,
116133
depth,
117134
lanes,
118-
laneLabels,
119135
timestamp: startTime,
120136
duration: 0,
121137
});
@@ -242,7 +258,21 @@ function processTimelineEvent(
242258
case 'blink.user_timing':
243259
const startTime = (ts - currentProfilerData.startTime) / 1000;
244260

245-
if (name.startsWith('--component-render-start-')) {
261+
if (name.startsWith('--react-version-')) {
262+
const [reactVersion] = name.substr(16).split('-');
263+
currentProfilerData.reactVersion = reactVersion;
264+
} else if (name.startsWith('--profiler-version-')) {
265+
const [versionString] = name.substr(19).split('-');
266+
profilerVersion = parseInt(versionString, 10);
267+
if (profilerVersion !== SCHEDULING_PROFILER_VERSION) {
268+
throw new InvalidProfileError(
269+
`This version of profiling data (${versionString}) is not supported by the current profiler.`,
270+
);
271+
}
272+
} else if (name.startsWith('--react-lane-labels-')) {
273+
const [laneLabelTuplesString] = name.substr(20).split('-');
274+
updateLaneToLabelMap(laneLabelTuplesString);
275+
} else if (name.startsWith('--component-render-start-')) {
246276
const [componentName] = name.substr(25).split('-');
247277

248278
if (state.currentReactComponentMeasure !== null) {
@@ -268,48 +298,44 @@ function processTimelineEvent(
268298
currentProfilerData.componentMeasures.push(componentMeasure);
269299
}
270300
} else if (name.startsWith('--schedule-render-')) {
271-
const [laneBitmaskString, laneLabels] = name.substr(18).split('-');
301+
const [laneBitmaskString] = name.substr(18).split('-');
302+
272303
currentProfilerData.schedulingEvents.push({
273304
type: 'schedule-render',
274305
lanes: getLanesFromTransportDecimalBitmask(laneBitmaskString),
275-
laneLabels: laneLabels ? laneLabels.split(',') : [],
276306
timestamp: startTime,
277307
warning: null,
278308
});
279309
} else if (name.startsWith('--schedule-forced-update-')) {
280-
const [laneBitmaskString, laneLabels, componentName] = name
281-
.substr(25)
282-
.split('-');
310+
const [laneBitmaskString, componentName] = name.substr(25).split('-');
283311

284312
let warning = null;
285313
if (state.measureStack.find(({type}) => type === 'commit')) {
286314
// TODO (scheduling profiler) Only warn if the subsequent update is longer than some threshold.
315+
// This might be easier to do if we separated warnings into a second pass.
287316
warning = WARNING_STRINGS.NESTED_UPDATE;
288317
}
289318

290319
currentProfilerData.schedulingEvents.push({
291320
type: 'schedule-force-update',
292321
lanes: getLanesFromTransportDecimalBitmask(laneBitmaskString),
293-
laneLabels: laneLabels ? laneLabels.split(',') : [],
294322
componentName,
295323
timestamp: startTime,
296324
warning,
297325
});
298326
} else if (name.startsWith('--schedule-state-update-')) {
299-
const [laneBitmaskString, laneLabels, componentName] = name
300-
.substr(24)
301-
.split('-');
327+
const [laneBitmaskString, componentName] = name.substr(24).split('-');
302328

303329
let warning = null;
304330
if (state.measureStack.find(({type}) => type === 'commit')) {
305331
// TODO (scheduling profiler) Only warn if the subsequent update is longer than some threshold.
332+
// This might be easier to do if we separated warnings into a second pass.
306333
warning = WARNING_STRINGS.NESTED_UPDATE;
307334
}
308335

309336
currentProfilerData.schedulingEvents.push({
310337
type: 'schedule-state-update',
311338
lanes: getLanesFromTransportDecimalBitmask(laneBitmaskString),
312-
laneLabels: laneLabels ? laneLabels.split(',') : [],
313339
componentName,
314340
timestamp: startTime,
315341
warning,
@@ -318,25 +344,18 @@ function processTimelineEvent(
318344

319345
// React Events - suspense
320346
else if (name.startsWith('--suspense-suspend-')) {
321-
const [id, componentName, ...rest] = name.substr(19).split('-');
347+
const [id, componentName, phase, laneBitmaskString] = name
348+
.substr(19)
349+
.split('-');
350+
const lanes = getLanesFromTransportDecimalBitmask(laneBitmaskString);
322351

323-
// Older versions of the scheduling profiler data didn't contain phase or lane values.
324-
let phase = null;
352+
// TODO It's possible we don't have lane-to-label mapping yet (since it's logged during commit phase)
353+
// We may need to do this sort of error checking in a separate pass.
325354
let warning = null;
326-
if (rest.length === 3) {
327-
switch (rest[0]) {
328-
case 'mount':
329-
case 'update':
330-
phase = rest[0];
331-
break;
332-
}
333-
334-
if (phase === 'update') {
335-
const laneLabels = rest[2];
336-
// HACK This is a bit gross but the numeric lane value might change between render versions.
337-
if (!laneLabels.includes('Transition')) {
338-
warning = WARNING_STRINGS.SUSPENDD_DURING_UPATE;
339-
}
355+
if (phase === 'update') {
356+
// HACK This is a bit gross but the numeric lane value might change between render versions.
357+
if (lanes.some(lane => laneToLabelMap.get(lane) === 'Transition')) {
358+
warning = WARNING_STRINGS.SUSPEND_DURING_UPATE;
340359
}
341360
}
342361

@@ -365,7 +384,7 @@ function processTimelineEvent(
365384
depth,
366385
duration: null,
367386
id,
368-
phase,
387+
phase: ((phase: any): Phase),
369388
resolution: 'unresolved',
370389
resuspendTimestamps: null,
371390
timestamp: startTime,
@@ -411,24 +430,22 @@ function processTimelineEvent(
411430
state.nextRenderShouldGenerateNewBatchID = false;
412431
state.batchUID = ((state.uidCounter++: any): BatchUID);
413432
}
414-
const [laneBitmaskString, laneLabels] = name.substr(15).split('-');
415-
const lanes = getLanesFromTransportDecimalBitmask(laneBitmaskString);
433+
const [laneBitmaskString] = name.substr(15).split('-');
434+
416435
throwIfIncomplete('render', state.measureStack);
417436
if (getLastType(state.measureStack) !== 'render-idle') {
418437
markWorkStarted(
419438
'render-idle',
420439
startTime,
421-
lanes,
422-
laneLabels ? laneLabels.split(',') : [],
440+
getLanesFromTransportDecimalBitmask(laneBitmaskString),
423441
currentProfilerData,
424442
state,
425443
);
426444
}
427445
markWorkStarted(
428446
'render',
429447
startTime,
430-
lanes,
431-
laneLabels ? laneLabels.split(',') : [],
448+
getLanesFromTransportDecimalBitmask(laneBitmaskString),
432449
currentProfilerData,
433450
state,
434451
);
@@ -472,13 +489,12 @@ function processTimelineEvent(
472489
// React Measures - commits
473490
else if (name.startsWith('--commit-start-')) {
474491
state.nextRenderShouldGenerateNewBatchID = true;
475-
const [laneBitmaskString, laneLabels] = name.substr(15).split('-');
476-
const lanes = getLanesFromTransportDecimalBitmask(laneBitmaskString);
492+
const [laneBitmaskString] = name.substr(15).split('-');
493+
477494
markWorkStarted(
478495
'commit',
479496
startTime,
480-
lanes,
481-
laneLabels ? laneLabels.split(',') : [],
497+
getLanesFromTransportDecimalBitmask(laneBitmaskString),
482498
currentProfilerData,
483499
state,
484500
);
@@ -499,13 +515,12 @@ function processTimelineEvent(
499515

500516
// React Measures - layout effects
501517
else if (name.startsWith('--layout-effects-start-')) {
502-
const [laneBitmaskString, laneLabels] = name.substr(23).split('-');
503-
const lanes = getLanesFromTransportDecimalBitmask(laneBitmaskString);
518+
const [laneBitmaskString] = name.substr(23).split('-');
519+
504520
markWorkStarted(
505521
'layout-effects',
506522
startTime,
507-
lanes,
508-
laneLabels ? laneLabels.split(',') : [],
523+
getLanesFromTransportDecimalBitmask(laneBitmaskString),
509524
currentProfilerData,
510525
state,
511526
);
@@ -520,13 +535,12 @@ function processTimelineEvent(
520535

521536
// React Measures - passive effects
522537
else if (name.startsWith('--passive-effects-start-')) {
523-
const [laneBitmaskString, laneLabels] = name.substr(24).split('-');
524-
const lanes = getLanesFromTransportDecimalBitmask(laneBitmaskString);
538+
const [laneBitmaskString] = name.substr(24).split('-');
539+
525540
markWorkStarted(
526541
'passive-effects',
527542
startTime,
528-
lanes,
529-
laneLabels ? laneLabels.split(',') : [],
543+
getLanesFromTransportDecimalBitmask(laneBitmaskString),
530544
currentProfilerData,
531545
state,
532546
);
@@ -610,9 +624,11 @@ export default function preprocessData(
610624
componentMeasures: [],
611625
duration: 0,
612626
flamechart,
627+
laneToLabelMap,
613628
measures: [],
614629
nativeEvents: [],
615630
otherUserTimingMarks: [],
631+
reactVersion: null,
616632
schedulingEvents: [],
617633
startTime: 0,
618634
suspenseEvents: [],
@@ -656,6 +672,12 @@ export default function preprocessData(
656672

657673
timeline.forEach(event => processTimelineEvent(event, profilerData, state));
658674

675+
if (profilerVersion === null) {
676+
throw new InvalidProfileError(
677+
`This version of profiling data is not supported by the current profiler.`,
678+
);
679+
}
680+
659681
// Validate that all events and measures are complete
660682
const {measureStack} = state;
661683
if (measureStack.length > 0) {

‎packages/react-devtools-scheduling-profiler/src/types.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ type BaseReactEvent = {|
3838
type BaseReactScheduleEvent = {|
3939
...BaseReactEvent,
4040
+lanes: ReactLane[],
41-
+laneLabels: string[],
4241
|};
4342
export type ReactScheduleRenderEvent = {|
4443
...BaseReactScheduleEvent,
@@ -53,12 +52,14 @@ export type ReactScheduleForceUpdateEvent = {|
5352
+type: 'schedule-force-update',
5453
|};
5554

55+
export type Phase = 'mount' | 'update';
56+
5657
export type SuspenseEvent = {|
5758
...BaseReactEvent,
5859
depth: number,
5960
duration: number | null,
6061
+id: string,
61-
+phase: 'mount' | 'update' | null,
62+
+phase: Phase | null,
6263
resolution: 'rejected' | 'resolved' | 'unresolved',
6364
resuspendTimestamps: Array<number> | null,
6465
+type: 'suspense',
@@ -84,7 +85,6 @@ export type BatchUID = number;
8485
export type ReactMeasure = {|
8586
+type: ReactMeasureType,
8687
+lanes: ReactLane[],
87-
+laneLabels: string[],
8888
+timestamp: Milliseconds,
8989
+duration: Milliseconds,
9090
+batchUID: BatchUID,
@@ -127,9 +127,11 @@ export type ReactProfilerData = {|
127127
componentMeasures: ReactComponentMeasure[],
128128
duration: number,
129129
flamechart: Flamechart,
130+
laneToLabelMap: Map<ReactLane, string>,
130131
measures: ReactMeasure[],
131132
nativeEvents: NativeEvent[],
132133
otherUserTimingMarks: UserTimingMark[],
134+
reactVersion: string | null,
133135
schedulingEvents: SchedulingEvent[],
134136
startTime: number,
135137
suspenseEvents: SuspenseEvent[],

‎packages/react-devtools-scheduling-profiler/src/view-base/ResizableView.js

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -105,14 +105,10 @@ class ResizeBar extends View {
105105

106106
const drawableRect = intersectionOfRects(labelRect, this.visibleArea);
107107

108-
drawText(
109-
this._label,
110-
context,
111-
labelRect,
112-
drawableRect,
113-
'center',
114-
COLORS.REACT_RESIZE_BAR_DOT,
115-
);
108+
drawText(this._label, context, labelRect, drawableRect, {
109+
fillStyle: COLORS.REACT_RESIZE_BAR_DOT,
110+
textAlign: 'center',
111+
});
116112
} else {
117113
// Otherwise draw horizontally centered resize bar dots
118114
context.beginPath();

‎packages/react-devtools-shared/src/constants.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,12 +149,16 @@ export const THEME_STYLES: {[style: Theme | DisplayDensity]: any} = {
149149
'--color-scheduling-profiler-react-idle-hover': '#c3d9ef',
150150
'--color-scheduling-profiler-react-render': '#9fc3f3',
151151
'--color-scheduling-profiler-react-render-hover': '#83afe9',
152+
'--color-scheduling-profiler-react-render-text': '#11365e',
152153
'--color-scheduling-profiler-react-commit': '#c88ff0',
153154
'--color-scheduling-profiler-react-commit-hover': '#b281d6',
155+
'--color-scheduling-profiler-react-commit-text': '#3e2c4a',
154156
'--color-scheduling-profiler-react-layout-effects': '#b281d6',
155157
'--color-scheduling-profiler-react-layout-effects-hover': '#9d71bd',
158+
'--color-scheduling-profiler-react-layout-effects-text': '#3e2c4a',
156159
'--color-scheduling-profiler-react-passive-effects': '#b281d6',
157160
'--color-scheduling-profiler-react-passive-effects-hover': '#9d71bd',
161+
'--color-scheduling-profiler-react-passive-effects-text': '#3e2c4a',
158162
'--color-scheduling-profiler-react-schedule': '#9fc3f3',
159163
'--color-scheduling-profiler-react-schedule-hover': '#2683E2',
160164
'--color-scheduling-profiler-react-suspense-rejected': '#f1cc14',
@@ -280,12 +284,16 @@ export const THEME_STYLES: {[style: Theme | DisplayDensity]: any} = {
280284
'--color-scheduling-profiler-react-idle-hover': '#465269',
281285
'--color-scheduling-profiler-react-render': '#2683E2',
282286
'--color-scheduling-profiler-react-render-hover': '#1a76d4',
287+
'--color-scheduling-profiler-react-render-text': '#11365e',
283288
'--color-scheduling-profiler-react-commit': '#731fad',
284289
'--color-scheduling-profiler-react-commit-hover': '#611b94',
290+
'--color-scheduling-profiler-react-commit-text': '#e5c1ff',
285291
'--color-scheduling-profiler-react-layout-effects': '#611b94',
286292
'--color-scheduling-profiler-react-layout-effects-hover': '#51167a',
293+
'--color-scheduling-profiler-react-layout-effects-text': '#e5c1ff',
287294
'--color-scheduling-profiler-react-passive-effects': '#611b94',
288295
'--color-scheduling-profiler-react-passive-effects-hover': '#51167a',
296+
'--color-scheduling-profiler-react-passive-effects-text': '#e5c1ff',
289297
'--color-scheduling-profiler-react-schedule': '#2683E2',
290298
'--color-scheduling-profiler-react-schedule-hover': '#1a76d4',
291299
'--color-scheduling-profiler-react-suspense-rejected': '#f1cc14',

‎packages/react-reconciler/src/ReactFiberLane.new.js

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import {
2525
import {isDevToolsPresent} from './ReactFiberDevToolsHook.new';
2626
import {ConcurrentUpdatesByDefaultMode, NoMode} from './ReactTypeOfMode';
2727

28-
// Lane values below should be kept in sync with getLabelsForLanes(), used by react-devtools-scheduling-profiler.
28+
// Lane values below should be kept in sync with getLabelForLane(), used by react-devtools-scheduling-profiler.
2929
// If those values are changed that package should be rebuilt and redeployed.
3030

3131
export const TotalLanes = 31;
@@ -80,46 +80,44 @@ export const OffscreenLane: Lane = /* */ 0b1000000000000000000
8080

8181
// This function is used for the experimental scheduling profiler (react-devtools-scheduling-profiler)
8282
// It should be kept in sync with the Lanes values above.
83-
export function getLabelsForLanes(lanes: Lanes): Array<string> | void {
83+
export function getLabelForLane(lane: Lane): string | void {
8484
if (enableSchedulingProfiler) {
85-
const labels = [];
86-
if (lanes & SyncLane) {
87-
labels.push('Sync');
85+
if (lane & SyncLane) {
86+
return 'Sync';
8887
}
89-
if (lanes & InputContinuousHydrationLane) {
90-
labels.push('InputContinuousHydration');
88+
if (lane & InputContinuousHydrationLane) {
89+
return 'InputContinuousHydration';
9190
}
92-
if (lanes & InputContinuousLane) {
93-
labels.push('InputContinuous');
91+
if (lane & InputContinuousLane) {
92+
return 'InputContinuous';
9493
}
95-
if (lanes & DefaultHydrationLane) {
96-
labels.push('DefaultHydration');
94+
if (lane & DefaultHydrationLane) {
95+
return 'DefaultHydration';
9796
}
98-
if (lanes & DefaultLane) {
99-
labels.push('Default');
97+
if (lane & DefaultLane) {
98+
return 'Default';
10099
}
101-
if (lanes & TransitionHydrationLane) {
102-
labels.push('TransitionHydration');
100+
if (lane & TransitionHydrationLane) {
101+
return 'TransitionHydration';
103102
}
104-
if (lanes & TransitionLanes) {
105-
labels.push('Transition(s)');
103+
if (lane & TransitionLanes) {
104+
return 'Transition';
106105
}
107-
if (lanes & RetryLanes) {
108-
labels.push('Retry(s)');
106+
if (lane & RetryLanes) {
107+
return 'Retry';
109108
}
110-
if (lanes & SelectiveHydrationLane) {
111-
labels.push('SelectiveHydration');
109+
if (lane & SelectiveHydrationLane) {
110+
return 'SelectiveHydration';
112111
}
113-
if (lanes & IdleHydrationLane) {
114-
labels.push('IdleHydration');
112+
if (lane & IdleHydrationLane) {
113+
return 'IdleHydration';
115114
}
116-
if (lanes & IdleLane) {
117-
labels.push('Idle');
115+
if (lane & IdleLane) {
116+
return 'Idle';
118117
}
119-
if (lanes & OffscreenLane) {
120-
labels.push('Offscreen');
118+
if (lane & OffscreenLane) {
119+
return 'Offscreen';
121120
}
122-
return labels;
123121
}
124122
}
125123

‎packages/react-reconciler/src/ReactFiberLane.old.js

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import {
2525
import {isDevToolsPresent} from './ReactFiberDevToolsHook.old';
2626
import {ConcurrentUpdatesByDefaultMode, NoMode} from './ReactTypeOfMode';
2727

28-
// Lane values below should be kept in sync with getLabelsForLanes(), used by react-devtools-scheduling-profiler.
28+
// Lane values below should be kept in sync with getLabelForLane(), used by react-devtools-scheduling-profiler.
2929
// If those values are changed that package should be rebuilt and redeployed.
3030

3131
export const TotalLanes = 31;
@@ -80,46 +80,44 @@ export const OffscreenLane: Lane = /* */ 0b1000000000000000000
8080

8181
// This function is used for the experimental scheduling profiler (react-devtools-scheduling-profiler)
8282
// It should be kept in sync with the Lanes values above.
83-
export function getLabelsForLanes(lanes: Lanes): Array<string> | void {
83+
export function getLabelForLane(lane: Lane): string | void {
8484
if (enableSchedulingProfiler) {
85-
const labels = [];
86-
if (lanes & SyncLane) {
87-
labels.push('Sync');
85+
if (lane & SyncLane) {
86+
return 'Sync';
8887
}
89-
if (lanes & InputContinuousHydrationLane) {
90-
labels.push('InputContinuousHydration');
88+
if (lane & InputContinuousHydrationLane) {
89+
return 'InputContinuousHydration';
9190
}
92-
if (lanes & InputContinuousLane) {
93-
labels.push('InputContinuous');
91+
if (lane & InputContinuousLane) {
92+
return 'InputContinuous';
9493
}
95-
if (lanes & DefaultHydrationLane) {
96-
labels.push('DefaultHydration');
94+
if (lane & DefaultHydrationLane) {
95+
return 'DefaultHydration';
9796
}
98-
if (lanes & DefaultLane) {
99-
labels.push('Default');
97+
if (lane & DefaultLane) {
98+
return 'Default';
10099
}
101-
if (lanes & TransitionHydrationLane) {
102-
labels.push('TransitionHydration');
100+
if (lane & TransitionHydrationLane) {
101+
return 'TransitionHydration';
103102
}
104-
if (lanes & TransitionLanes) {
105-
labels.push('Transition(s)');
103+
if (lane & TransitionLanes) {
104+
return 'Transition';
106105
}
107-
if (lanes & RetryLanes) {
108-
labels.push('Retry(s)');
106+
if (lane & RetryLanes) {
107+
return 'Retry';
109108
}
110-
if (lanes & SelectiveHydrationLane) {
111-
labels.push('SelectiveHydration');
109+
if (lane & SelectiveHydrationLane) {
110+
return 'SelectiveHydration';
112111
}
113-
if (lanes & IdleHydrationLane) {
114-
labels.push('IdleHydration');
112+
if (lane & IdleHydrationLane) {
113+
return 'IdleHydration';
115114
}
116-
if (lanes & IdleLane) {
117-
labels.push('Idle');
115+
if (lane & IdleLane) {
116+
return 'Idle';
118117
}
119-
if (lanes & OffscreenLane) {
120-
labels.push('Offscreen');
118+
if (lane & OffscreenLane) {
119+
return 'Offscreen';
121120
}
122-
return labels;
123121
}
124122
}
125123

‎packages/react-reconciler/src/SchedulingProfiler.js

Lines changed: 58 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,22 @@ import {
1717
} from 'shared/ReactFeatureFlags';
1818
import ReactVersion from 'shared/ReactVersion';
1919
import getComponentNameFromFiber from 'react-reconciler/src/getComponentNameFromFiber';
20+
import {SCHEDULING_PROFILER_VERSION} from 'react-devtools-scheduling-profiler/src/constants';
2021

21-
import {getLabelsForLanes as getLabelsForLanes_old} from 'react-reconciler/src/ReactFiberLane.old';
22-
import {getLabelsForLanes as getLabelsForLanes_new} from 'react-reconciler/src/ReactFiberLane.new';
22+
import {
23+
getLabelForLane as getLabelForLane_old,
24+
TotalLanes as TotalLanes_old,
25+
} from 'react-reconciler/src/ReactFiberLane.old';
26+
import {
27+
getLabelForLane as getLabelForLane_new,
28+
TotalLanes as TotalLanes_new,
29+
} from 'react-reconciler/src/ReactFiberLane.new';
2330

24-
const getLabelsForLanes = enableNewReconciler
25-
? getLabelsForLanes_new
26-
: getLabelsForLanes_old;
31+
const getLabelForLane = enableNewReconciler
32+
? getLabelForLane_new
33+
: getLabelForLane_old;
34+
35+
const TotalLanes = enableNewReconciler ? TotalLanes_new : TotalLanes_old;
2736

2837
/**
2938
* If performance exists and supports the subset of the User Timing API that we
@@ -59,32 +68,52 @@ if (enableSchedulingProfiler) {
5968
}
6069
}
6170

62-
export function formatLanes(laneOrLanes: Lane | Lanes): string {
63-
let labels = getLabelsForLanes(laneOrLanes);
64-
if (labels != null) {
65-
labels = labels.sort().join(',');
66-
} else {
67-
labels = '';
71+
const laneLabels: Array<string> = [];
72+
73+
export function getLaneLabels(): Array<string> {
74+
if (laneLabels.length === 0) {
75+
let lane = 1;
76+
for (let index = 0; index < TotalLanes; index++) {
77+
laneLabels.push(((getLabelForLane(lane): any): string));
78+
79+
lane *= 2;
80+
}
6881
}
69-
return `${laneOrLanes}-${labels}`;
82+
return laneLabels;
83+
}
84+
85+
function markLaneToLabelMetadata() {
86+
getLaneLabels();
87+
88+
markAndClear(`--react-lane-labels-${laneLabels.join(',')}`);
7089
}
7190

7291
function markAndClear(name) {
7392
performance.mark(name);
7493
performance.clearMarks(name);
7594
}
7695

77-
// Create a mark on React initialization
78-
if (enableSchedulingProfiler) {
79-
if (supportsUserTimingV3) {
80-
markAndClear(`--react-init-${ReactVersion}`);
81-
}
96+
function markVersionMetadata() {
97+
markAndClear(`--react-version-${ReactVersion}`);
98+
markAndClear(`--profiler-version-${SCHEDULING_PROFILER_VERSION}`);
8299
}
83100

84101
export function markCommitStarted(lanes: Lanes): void {
85102
if (enableSchedulingProfiler) {
86103
if (supportsUserTimingV3) {
87-
markAndClear(`--commit-start-${formatLanes(lanes)}`);
104+
markAndClear(`--commit-start-${lanes}`);
105+
106+
// Certain types of metadata should be logged infrequently.
107+
// Normally we would log this during module init,
108+
// but there's no guarantee a user is profiling at that time.
109+
// Commits happen infrequently (less than renders or state updates)
110+
// so we log this extra information along with a commit.
111+
// It will likely be logged more than once but that's okay.
112+
//
113+
// TODO Once DevTools supports starting/stopping the profiler,
114+
// we can log this data only once (when started) and remove the per-commit logging.
115+
markVersionMetadata();
116+
markLaneToLabelMetadata();
88117
}
89118
}
90119
}
@@ -101,6 +130,7 @@ export function markComponentRenderStarted(fiber: Fiber): void {
101130
if (enableSchedulingProfiler) {
102131
if (supportsUserTimingV3) {
103132
const componentName = getComponentNameFromFiber(fiber) || 'Unknown';
133+
// TODO (scheduling profiler) Add component stack id
104134
markAndClear(`--component-render-start-${componentName}`);
105135
}
106136
}
@@ -137,11 +167,9 @@ export function markComponentSuspended(
137167
const id = getWakeableID(wakeable);
138168
const componentName = getComponentNameFromFiber(fiber) || 'Unknown';
139169
const phase = fiber.alternate === null ? 'mount' : 'update';
140-
// TODO (scheduling profiler) Add component stack id if we re-add component stack info.
170+
// TODO (scheduling profiler) Add component stack id
141171
markAndClear(
142-
`--suspense-${eventType}-${id}-${componentName}-${phase}-${formatLanes(
143-
lanes,
144-
)}`,
172+
`--suspense-${eventType}-${id}-${componentName}-${phase}-${lanes}`,
145173
);
146174
wakeable.then(
147175
() => markAndClear(`--suspense-resolved-${id}-${componentName}`),
@@ -154,7 +182,7 @@ export function markComponentSuspended(
154182
export function markLayoutEffectsStarted(lanes: Lanes): void {
155183
if (enableSchedulingProfiler) {
156184
if (supportsUserTimingV3) {
157-
markAndClear(`--layout-effects-start-${formatLanes(lanes)}`);
185+
markAndClear(`--layout-effects-start-${lanes}`);
158186
}
159187
}
160188
}
@@ -170,7 +198,7 @@ export function markLayoutEffectsStopped(): void {
170198
export function markPassiveEffectsStarted(lanes: Lanes): void {
171199
if (enableSchedulingProfiler) {
172200
if (supportsUserTimingV3) {
173-
markAndClear(`--passive-effects-start-${formatLanes(lanes)}`);
201+
markAndClear(`--passive-effects-start-${lanes}`);
174202
}
175203
}
176204
}
@@ -186,7 +214,7 @@ export function markPassiveEffectsStopped(): void {
186214
export function markRenderStarted(lanes: Lanes): void {
187215
if (enableSchedulingProfiler) {
188216
if (supportsUserTimingV3) {
189-
markAndClear(`--render-start-${formatLanes(lanes)}`);
217+
markAndClear(`--render-start-${lanes}`);
190218
}
191219
}
192220
}
@@ -210,7 +238,7 @@ export function markRenderStopped(): void {
210238
export function markRenderScheduled(lane: Lane): void {
211239
if (enableSchedulingProfiler) {
212240
if (supportsUserTimingV3) {
213-
markAndClear(`--schedule-render-${formatLanes(lane)}`);
241+
markAndClear(`--schedule-render-${lane}`);
214242
}
215243
}
216244
}
@@ -219,10 +247,8 @@ export function markForceUpdateScheduled(fiber: Fiber, lane: Lane): void {
219247
if (enableSchedulingProfiler) {
220248
if (supportsUserTimingV3) {
221249
const componentName = getComponentNameFromFiber(fiber) || 'Unknown';
222-
// TODO Add component stack id
223-
markAndClear(
224-
`--schedule-forced-update-${formatLanes(lane)}-${componentName}`,
225-
);
250+
// TODO (scheduling profiler) Add component stack id
251+
markAndClear(`--schedule-forced-update-${lane}-${componentName}`);
226252
}
227253
}
228254
}
@@ -231,10 +257,8 @@ export function markStateUpdateScheduled(fiber: Fiber, lane: Lane): void {
231257
if (enableSchedulingProfiler) {
232258
if (supportsUserTimingV3) {
233259
const componentName = getComponentNameFromFiber(fiber) || 'Unknown';
234-
// TODO Add component stack id
235-
markAndClear(
236-
`--schedule-state-update-${formatLanes(lane)}-${componentName}`,
237-
);
260+
// TODO (scheduling profiler) Add component stack id
261+
markAndClear(`--schedule-state-update-${lane}-${componentName}`);
238262
}
239263
}
240264
}

‎packages/react-reconciler/src/__tests__/SchedulingProfiler-test.internal.js

Lines changed: 376 additions & 252 deletions
Large diffs are not rendered by default.

‎packages/react-reconciler/src/__tests__/SchedulingProfilerLabels-test.internal.js

Lines changed: 97 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,10 @@
1515
describe('SchedulingProfiler labels', () => {
1616
let React;
1717
let ReactDOM;
18-
let ReactFiberLane;
1918

2019
let act;
2120
let clearedMarks;
2221
let featureDetectionMarkName = null;
23-
let formatLanes;
2422
let marks;
2523

2624
function polyfillJSDomUserTiming() {
@@ -75,14 +73,6 @@ describe('SchedulingProfiler labels', () => {
7573

7674
const TestUtils = require('react-dom/test-utils');
7775
act = TestUtils.act;
78-
79-
const SchedulingProfiler = require('react-reconciler/src/SchedulingProfiler');
80-
formatLanes = SchedulingProfiler.formatLanes;
81-
82-
const ReactFeatureFlags = require('shared/ReactFeatureFlags');
83-
ReactFiberLane = ReactFeatureFlags.enableNewReconciler
84-
? require('react-reconciler/src/ReactFiberLane.new')
85-
: require('react-reconciler/src/ReactFiberLane.old');
8676
});
8777

8878
afterEach(() => {
@@ -92,29 +82,45 @@ describe('SchedulingProfiler labels', () => {
9282
delete global.performance;
9383
});
9484

95-
// @gate enableSchedulingProfiler
9685
it('regression test SyncLane', () => {
9786
ReactDOM.render(<div />, document.createElement('div'));
98-
expect(clearedMarks).toContain(
99-
`--schedule-render-${formatLanes(ReactFiberLane.SyncLane)}`,
100-
);
87+
88+
if (gate(flags => flags.enableSchedulingProfiler)) {
89+
expect(clearedMarks).toMatchInlineSnapshot(`
90+
Array [
91+
"__v3",
92+
"--schedule-render-1",
93+
"--render-start-1",
94+
"--render-stop",
95+
"--commit-start-1",
96+
"--react-version-17.0.3",
97+
"--profiler-version-1",
98+
"--react-lane-labels-Sync,InputContinuousHydration,InputContinuous,DefaultHydration,Default,TransitionHydration,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Retry,Retry,Retry,Retry,Retry,SelectiveHydration,IdleHydration,Idle,Offscreen",
99+
"--layout-effects-start-1",
100+
"--layout-effects-stop",
101+
"--commit-stop",
102+
]
103+
`);
104+
}
101105
});
102106

103-
// @gate enableSchedulingProfiler
104107
it('regression test DefaultLane', () => {
105-
const container = document.createElement('div');
106-
const root = ReactDOM.createRoot(container);
107-
108-
act(() => {
109-
root.render(<div />);
110-
expect(clearedMarks).toContain(
111-
`--schedule-render-${formatLanes(ReactFiberLane.DefaultLane)}`,
112-
);
113-
});
108+
if (gate(flags => flags.enableSchedulingProfiler)) {
109+
act(() => {
110+
const container = document.createElement('div');
111+
const root = ReactDOM.createRoot(container);
112+
113+
root.render(<div />);
114+
expect(clearedMarks).toMatchInlineSnapshot(`
115+
Array [
116+
"__v3",
117+
"--schedule-render-16",
118+
]
119+
`);
120+
});
121+
}
114122
});
115123

116-
// @gate enableSchedulingProfiler
117-
// @gate !enableLegacyFBSupport
118124
it('regression test InputDiscreteLane', () => {
119125
const container = document.createElement('div');
120126
const root = ReactDOM.createRoot(container);
@@ -128,24 +134,41 @@ describe('SchedulingProfiler labels', () => {
128134
return <button ref={targetRef} onClick={handleClick} />;
129135
}
130136

131-
act(() => {
132-
root.render(<App />);
133-
});
134-
135-
clearedMarks.splice(0);
136-
137-
act(() => {
138-
targetRef.current.click();
139-
});
140-
expect(clearedMarks).toContain(
141-
`--schedule-state-update-${formatLanes(ReactFiberLane.SyncLane)}-App`,
142-
);
137+
if (
138+
gate(
139+
flags => flags.enableSchedulingProfiler && !flags.enableLegacyFBSupport,
140+
)
141+
) {
142+
act(() => {
143+
root.render(<App />);
144+
});
145+
146+
clearedMarks.splice(0);
147+
148+
act(() => {
149+
targetRef.current.click();
150+
});
151+
152+
expect(clearedMarks).toMatchInlineSnapshot(`
153+
Array [
154+
"--schedule-state-update-1-App",
155+
"--render-start-1",
156+
"--component-render-start-App",
157+
"--component-render-stop",
158+
"--render-stop",
159+
"--commit-start-1",
160+
"--react-version-17.0.3",
161+
"--profiler-version-1",
162+
"--react-lane-labels-Sync,InputContinuousHydration,InputContinuous,DefaultHydration,Default,TransitionHydration,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Retry,Retry,Retry,Retry,Retry,SelectiveHydration,IdleHydration,Idle,Offscreen",
163+
"--layout-effects-start-1",
164+
"--layout-effects-stop",
165+
"--commit-stop",
166+
]
167+
`);
168+
}
143169
});
144170

145-
// @gate enableSchedulingProfiler
146171
it('regression test InputContinuousLane', () => {
147-
const container = document.createElement('div');
148-
const root = ReactDOM.createRoot(container);
149172
const targetRef = React.createRef(null);
150173

151174
function App() {
@@ -154,21 +177,38 @@ describe('SchedulingProfiler labels', () => {
154177
return <div ref={targetRef} onMouseOver={handleMouseOver} />;
155178
}
156179

157-
act(() => {
158-
root.render(<App />);
159-
});
160-
161-
clearedMarks.splice(0);
162-
163-
act(() => {
164-
const event = document.createEvent('MouseEvents');
165-
event.initEvent('mouseover', true, true);
166-
dispatchAndSetCurrentEvent(targetRef.current, event);
167-
});
168-
expect(clearedMarks).toContain(
169-
`--schedule-state-update-${formatLanes(
170-
ReactFiberLane.InputContinuousLane,
171-
)}-App`,
172-
);
180+
if (gate(flags => flags.enableSchedulingProfiler)) {
181+
const container = document.createElement('div');
182+
const root = ReactDOM.createRoot(container);
183+
184+
act(() => {
185+
root.render(<App />);
186+
});
187+
188+
clearedMarks.splice(0);
189+
190+
act(() => {
191+
const event = document.createEvent('MouseEvents');
192+
event.initEvent('mouseover', true, true);
193+
dispatchAndSetCurrentEvent(targetRef.current, event);
194+
});
195+
196+
expect(clearedMarks).toMatchInlineSnapshot(`
197+
Array [
198+
"--schedule-state-update-4-App",
199+
"--render-start-4",
200+
"--component-render-start-App",
201+
"--component-render-stop",
202+
"--render-stop",
203+
"--commit-start-4",
204+
"--react-version-17.0.3",
205+
"--profiler-version-1",
206+
"--react-lane-labels-Sync,InputContinuousHydration,InputContinuous,DefaultHydration,Default,TransitionHydration,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Retry,Retry,Retry,Retry,Retry,SelectiveHydration,IdleHydration,Idle,Offscreen",
207+
"--layout-effects-start-4",
208+
"--layout-effects-stop",
209+
"--commit-stop",
210+
]
211+
`);
212+
}
173213
});
174214
});

0 commit comments

Comments
 (0)
Please sign in to comment.