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

0 commit comments

Comments
 (0)
Please sign in to comment.