Show commit priority levels in Profiler UI
Brian Vaughn committed
May 15, 2019 at 15:36 UTC
9a6a19456f0e07a9f308b079ad7245ca627a4f59
10 files changed
+134
-12
shells/dev/app/PriorityLevels/index.js
new
+29
@@ -0,0 +1,29 @@
1
+// @flow
2
+
3
+import React, { Fragment, useCallback, useState } from 'react';
4
+import { unstable_next as next } from 'scheduler';
5
+
6
+export default function PriorityLevels() {
7
+ const [count, setCount] = useState(0);
8
+
9
+ const startSequence = useCallback(() => {
10
+ setCount(1);
11
+ next(() => setCount(2));
12
+ }, []);
13
+
14
+ return (
15
+ <Fragment>
16
+ <h1>Priority Levels</h1>
17
+ <button onClick={startSequence}>start sequence</button>
18
+ {count >= 1 && <Text>One</Text>}
19
+ {count >= 2 && <Text>Two</Text>}
20
+ {count >= 2 && (
21
+ <div hidden>
22
+ <Text>Three</Text>
23
+ </div>
24
+ )}
25
+ </Fragment>
26
+ );
27
+}
28
+
29
+const Text = ({ children }) => children;
shells/dev/app/index.js
+9
-2
@@ -3,12 +3,17 @@
3
// This test harness mounts each test app as a separate root to test multi-root applications.
4
5
import { createElement } from 'react';
6
-import { render, unmountComponentAtNode } from 'react-dom';
6
+import {
7
+ unmountComponentAtNode,
8
+ // $FlowFixMe Flow does not yet know about createRoot()
9
+ unstable_createRoot as createRoot,
10
+} from 'react-dom';
11
import DeeplyNestedComponents from './DeeplyNestedComponents';
12
import EditableProps from './EditableProps';
13
import ElementTypes from './ElementTypes';
14
import InspectableElements from './InspectableElements';
15
import InteractionTracing from './InteractionTracing';
16
+import PriorityLevels from './PriorityLevels';
17
import ToDoList from './ToDoList';
18
import Toggle from './Toggle';
19
import SuspenseTree from './SuspenseTree';
@@ -24,7 +29,8 @@ function mountHelper(App) {
29
30
containers.push(container);
31
27
- render(createElement(App), container);
32
+ const root = createRoot(container);
33
+ root.render(createElement(App));
34
}
35
36
function mountTestApp() {
@@ -33,6 +39,7 @@ function mountTestApp() {
39
mountHelper(InspectableElements);
40
mountHelper(ElementTypes);
41
mountHelper(EditableProps);
42
+ mountHelper(PriorityLevels);
43
mountHelper(Toggle);
44
mountHelper(SuspenseTree);
45
mountHelper(DeeplyNestedComponents);
src/__tests__/__snapshots__/profiling-test.js.snap
+19
@@ -11,6 +11,7 @@ Object {
11
},
12
"commitIndex": 0,
13
"interactions": Array [],
14
+ "priorityLevel": 99,
15
"rootID": 1,
16
"selfDurations": Map {
17
1 => 0,
@@ -33,6 +34,7 @@ Object {
34
},
35
"commitIndex": 1,
36
"interactions": Array [],
37
+ "priorityLevel": 99,
38
"rootID": 1,
39
"selfDurations": Map {
40
3 => 0,
@@ -53,6 +55,7 @@ Object {
55
},
56
"commitIndex": 2,
57
"interactions": Array [],
58
+ "priorityLevel": 99,
59
"rootID": 1,
60
"selfDurations": Map {
61
3 => 0,
@@ -70,6 +73,7 @@ Object {
73
},
74
"commitIndex": 3,
75
"interactions": Array [],
76
+ "priorityLevel": 99,
77
"rootID": 1,
78
"selfDurations": Map {
79
2 => 10,
@@ -91,6 +95,7 @@ Object {
95
},
96
"commitIndex": 0,
97
"interactions": Array [],
98
+ "priorityLevel": 99,
99
"rootID": 1,
100
"selfDurations": Map {
101
1 => 0,
@@ -110,6 +115,7 @@ Object {
115
},
116
"commitIndex": 1,
117
"interactions": Array [],
118
+ "priorityLevel": 99,
119
"rootID": 1,
120
"selfDurations": Map {
121
3 => 0,
@@ -127,6 +133,7 @@ Object {
133
},
134
"commitIndex": 2,
135
"interactions": Array [],
136
+ "priorityLevel": 99,
137
"rootID": 1,
138
"selfDurations": Map {
139
3 => 0,
@@ -141,6 +148,7 @@ Object {
148
},
149
"commitIndex": 3,
150
"interactions": Array [],
151
+ "priorityLevel": 99,
152
"rootID": 1,
153
"selfDurations": Map {
154
2 => 10,
@@ -324,6 +332,7 @@ Object {
332
},
333
"commitIndex": 0,
334
"interactions": Array [],
335
+ "priorityLevel": 99,
336
"rootID": 1,
337
"selfDurations": Map {
338
1 => 0,
@@ -344,6 +353,7 @@ Object {
353
},
354
"commitIndex": 0,
355
"interactions": Array [],
356
+ "priorityLevel": 99,
357
"rootID": 1,
358
"selfDurations": Map {
359
1 => 0,
@@ -362,6 +372,7 @@ Object {
372
},
373
"commitIndex": 1,
374
"interactions": Array [],
375
+ "priorityLevel": 99,
376
"rootID": 1,
377
"selfDurations": Map {
378
5 => 3,
@@ -447,6 +458,7 @@ Object {
458
},
459
"commitIndex": 0,
460
"interactions": Array [],
461
+ "priorityLevel": 99,
462
"rootID": 1,
463
"selfDurations": Map {
464
1 => 0,
@@ -464,6 +476,7 @@ Object {
476
},
477
"commitIndex": 1,
478
"interactions": Array [],
479
+ "priorityLevel": 99,
480
"rootID": 1,
481
"selfDurations": Map {
482
3 => 0,
@@ -482,6 +495,7 @@ Object {
495
},
496
"commitIndex": 2,
497
"interactions": Array [],
498
+ "priorityLevel": 99,
499
"rootID": 1,
500
"selfDurations": Map {
501
3 => 0,
@@ -696,6 +710,7 @@ Object {
710
"timestamp": 0,
711
},
712
],
713
+ "priorityLevel": 99,
714
"rootID": 1,
715
"selfDurations": Map {
716
1 => 0,
@@ -720,6 +735,7 @@ Object {
735
"timestamp": 11,
736
},
737
],
738
+ "priorityLevel": 99,
739
"rootID": 1,
740
"selfDurations": Map {
741
3 => 0,
@@ -906,6 +922,7 @@ Object {
922
},
923
"commitIndex": 0,
924
"interactions": Array [],
925
+ "priorityLevel": 99,
926
"rootID": 1,
927
"selfDurations": Map {
928
3 => 0,
@@ -923,6 +940,7 @@ Object {
940
},
941
"commitIndex": 1,
942
"interactions": Array [],
943
+ "priorityLevel": 99,
944
"rootID": 1,
945
"selfDurations": Map {
946
3 => 0,
@@ -937,6 +955,7 @@ Object {
955
},
956
"commitIndex": 2,
957
"interactions": Array [],
958
+ "priorityLevel": 99,
959
"rootID": 1,
960
"selfDurations": Map {
961
2 => 10,
src/backend/renderer.js
+7
-1
@@ -48,6 +48,7 @@ import type {
48
PathFrame,
49
PathMatch,
50
ProfilingSummaryBackend,
51
+ ReactPriorityLevel,
52
ReactRenderer,
53
RendererInterface,
54
} from './types';
@@ -1267,6 +1268,7 @@ export function attach(
1268
})
1269
),
1270
maxActualDuration: 0,
1271
+ priorityLevel: null,
1272
};
1273
}
1274
@@ -1284,7 +1286,7 @@ export function attach(
1286
recordUnmount(fiber, false);
1287
}
1288
1287
- function handleCommitFiberRoot(root) {
1289
+ function handleCommitFiberRoot(root, priorityLevel) {
1290
const current = root.current;
1291
const alternate = current.alternate;
1292
@@ -1309,6 +1311,7 @@ export function attach(
1311
})
1312
),
1313
maxActualDuration: 0,
1314
+ priorityLevel: priorityLevel || null,
1315
};
1316
}
1317
@@ -1955,6 +1958,7 @@ export function attach(
1958
durations: Array<number>,
1959
interactions: Array<InteractionBackend>,
1960
maxActualDuration: number,
1961
+ priorityLevel: ReactPriorityLevel | null,
1962
|};
1963
1964
type CommitProfilingMetadataMap = Map<number, Array<CommitProfilingData>>;
@@ -1980,6 +1984,7 @@ export function attach(
1984
commitIndex,
1985
durations: commitProfilingData.durations,
1986
interactions: commitProfilingData.interactions,
1987
+ priorityLevel: commitProfilingData.priorityLevel,
1988
rootID,
1989
};
1990
}
@@ -1993,6 +1998,7 @@ export function attach(
1998
commitIndex,
1999
durations: [],
2000
interactions: [],
2001
+ priorityLevel: null,
2002
rootID,
2003
};
2004
}
src/backend/types.js
+20
-2
@@ -32,6 +32,16 @@ export type HookType =
32
| 'useImperativeHandle'
33
| 'useDebugValue';
34
35
+// Priority level is copied from React and should be kept in sync:
36
+// https://github.com/facebook/react/blob/master/packages/react-reconciler/src/SchedulerWithReactIntegration.js
37
+export opaque type ReactPriorityLevel = 99 | 98 | 97 | 96 | 95 | 90;
38
+export const ImmediatePriority: ReactPriorityLevel = 99;
39
+export const UserBlockingPriority: ReactPriorityLevel = 98;
40
+export const NormalPriority: ReactPriorityLevel = 97;
41
+export const LowPriority: ReactPriorityLevel = 96;
42
+export const IdlePriority: ReactPriorityLevel = 95;
43
+export const NoPriority: ReactPriorityLevel = 90;
44
+
45
// The Fiber type is copied from React and should be kept in sync:
46
// https://github.com/facebook/react/blob/master/packages/react-reconciler/src/ReactFiber.js
47
// The properties we don't use in DevTools are omitted.
@@ -126,6 +136,7 @@ export type CommitDetailsBackend = {|
136
// An interleaved array: fiberID at [i], actualDuration at [i + 1], computed selfDuration at [i + 2].
137
durations: Array<number>,
138
interactions: Array<InteractionBackend>,
139
+ priorityLevel: ReactPriorityLevel | null,
140
rootID: number,
141
|};
142
@@ -193,7 +204,10 @@ export type RendererInterface = {
204
) => ExportedProfilingDataFromRenderer,
205
getProfilingSummary: (rootID: number) => ProfilingSummaryBackend,
206
getPathForElement: (id: number) => Array<PathFrame> | null,
196
- handleCommitFiberRoot: (fiber: Object) => void,
207
+ handleCommitFiberRoot: (
208
+ fiber: Object,
209
+ commitPriority?: ReactPriorityLevel
210
+ ) => void,
211
handleCommitFiberUnmount: (fiber: Object) => void,
212
inspectElement: (id: number) => InspectedElement | null,
213
logElementToConsole: (id: number) => void,
@@ -234,7 +248,11 @@ export type DevToolsHook = {
248
// React uses these methods.
249
checkDCE: (fn: Function) => void,
250
onCommitFiberUnmount: (rendererID: RendererID, fiber: Object) => void,
237
- onCommitFiberRoot: (rendererID: RendererID, fiber: Object) => void,
251
+ onCommitFiberRoot: (
252
+ rendererID: RendererID,
253
+ fiber: Object,
254
+ commitPriority?: ReactPriorityLevel
255
+ ) => void,
256
};
257
258
export type HooksNode = {
src/devtools/ProfilingCache.js
+4
-1
@@ -130,8 +130,9 @@ export default class ProfilingCache {
130
rootID,
131
commitIndex,
132
actualDurations: new Map(),
133
- selfDurations: new Map(),
133
+ priorityLevel: null,
134
interactions: [],
135
+ selfDurations: new Map(),
136
});
137
});
138
},
@@ -346,6 +347,7 @@ export default class ProfilingCache {
347
commitIndex,
348
durations,
349
interactions,
350
+ priorityLevel,
351
rootID,
352
}: CommitDetailsBackend) => {
353
const key = `${rootID}-${commitIndex}`;
@@ -365,6 +367,7 @@ export default class ProfilingCache {
367
actualDurations: actualDurationsMap,
368
commitIndex,
369
interactions,
370
+ priorityLevel,
371
rootID,
372
selfDurations: selfDurationsMap,
373
});
src/devtools/views/Profiler/SidebarCommitInfo.js
+10
-2
@@ -2,7 +2,7 @@
2
3
import React, { Fragment, useCallback, useContext, useState } from 'react';
4
import { ProfilerContext } from './ProfilerContext';
5
-import { formatDuration, formatTime } from './utils';
5
+import { formatDuration, formatPriorityLevel, formatTime } from './utils';
6
import { StoreContext } from '../context';
7
8
import styles from './SidebarCommitInfo.css';
@@ -56,7 +56,7 @@ export default function SidebarCommitInfo(_: Props) {
56
}
57
);
58
59
- const { interactions } = profilingCache.CommitDetails.read({
59
+ const { interactions, priorityLevel } = profilingCache.CommitDetails.read({
60
commitIndex: selectedCommitIndex,
61
rendererID: ((rendererID: any): number),
62
rootID: ((rootID: any): number),
@@ -72,6 +72,14 @@ export default function SidebarCommitInfo(_: Props) {
72
<div className={styles.Toolbar}>Commit information</div>
73
<div className={styles.Content}>
74
<ul className={styles.List}>
75
+ {priorityLevel !== null && (
76
+ <li className={styles.ListItem}>
77
+ <label className={styles.Label}>Priority</label>:{' '}
78
+ <span className={styles.Value}>
79
+ {formatPriorityLevel(priorityLevel)}
80
+ </span>
81
+ </li>
82
+ )}
83
<li className={styles.ListItem}>
84
<label className={styles.Label}>Committed at</label>:{' '}
85
<span className={styles.Value}>
src/devtools/views/Profiler/types.js
+2
@@ -5,6 +5,7 @@ import type {
5
CommitDetailsBackend,
6
InteractionsBackend,
7
ProfilingSummaryBackend,
8
+ ReactPriorityLevel,
9
} from 'src/backend/types';
10
11
export type CommitTreeNodeFrontend = {|
@@ -42,6 +43,7 @@ export type CommitDetailsFrontend = {|
43
actualDurations: Map<number, number>,
44
commitIndex: number,
45
interactions: Array<InteractionFrontend>,
46
+ priorityLevel: ReactPriorityLevel | null,
47
rootID: number,
48
selfDurations: Map<number, number>,
49
|};
src/devtools/views/Profiler/utils.js
+32
-2
@@ -1,6 +1,14 @@
1
// @flow
2
3
import { PROFILER_EXPORT_VERSION } from 'src/constants';
4
+import {
5
+ ImmediatePriority,
6
+ UserBlockingPriority,
7
+ NormalPriority,
8
+ LowPriority,
9
+ IdlePriority,
10
+ NoPriority,
11
+} from 'src/backend/types';
12
13
import type {
14
ExportedProfilingSummaryFromFrontend,
@@ -9,7 +17,10 @@ import type {
17
ProfilingSnapshotNode,
18
} from './types';
19
12
-import type { ExportedProfilingDataFromRenderer } from 'src/backend/types';
20
+import type {
21
+ ExportedProfilingDataFromRenderer,
22
+ ReactPriorityLevel,
23
+} from 'src/backend/types';
24
25
const commitGradient = [
26
'var(--color-commit-gradient-0)',
@@ -152,10 +163,11 @@ export const prepareImportedProfilingData = (
163
}
164
return {
165
actualDurations: actualDurationsMap,
155
- selfDurations: selfDurationsMap,
166
commitIndex: commitDetailsBackendItem.commitIndex,
167
interactions: commitDetailsBackendItem.interactions,
168
+ priorityLevel: commitDetailsBackendItem.priorityLevel,
169
rootID: commitDetailsBackendItem.rootID,
170
+ selfDurations: selfDurationsMap,
171
};
172
}
173
),
@@ -184,6 +196,24 @@ export const getGradientColor = (value: number) => {
196
return commitGradient[Math.round(index)];
197
};
198
199
+export const formatPriorityLevel = (priorityLevel: ReactPriorityLevel) => {
200
+ switch (priorityLevel) {
201
+ case ImmediatePriority:
202
+ return 'Immediate';
203
+ case UserBlockingPriority:
204
+ return 'User-Blocking';
205
+ case NormalPriority:
206
+ return 'Normal';
207
+ case LowPriority:
208
+ return 'Low';
209
+ case IdlePriority:
210
+ return 'Idle';
211
+ case NoPriority:
212
+ default:
213
+ return 'Unknown';
214
+ }
215
+};
216
+
217
export const formatDuration = (duration: number) =>
218
Math.round(duration * 10) / 10 || '<0.1';
219
export const formatPercentage = (percentage: number) =>
src/hook.js
+2
-2
@@ -138,7 +138,7 @@ export function installHook(target: any): DevToolsHook | null {
138
}
139
}
140
141
- function onCommitFiberRoot(rendererID, root) {
141
+ function onCommitFiberRoot(rendererID, root, priorityLevel) {
142
const mountedRoots = hook.getFiberRoots(rendererID);
143
const current = root.current;
144
const isKnownRoot = mountedRoots.has(root);
@@ -153,7 +153,7 @@ export function installHook(target: any): DevToolsHook | null {
153
}
154
const rendererInterface = rendererInterfaces.get(rendererID);
155
if (rendererInterface != null) {
156
- rendererInterface.handleCommitFiberRoot(root);
156
+ rendererInterface.handleCommitFiberRoot(root, priorityLevel);
157
}
158
}
159