mirror of
https://github.com/zebrajr/react.git
synced 2025-12-06 12:20:20 +01:00
Add Gesture Track in Performance Tab (#34546)
This commit is contained in:
parent
e0c421ab71
commit
05b61f812a
10
packages/react-reconciler/src/ReactFiberLane.js
vendored
10
packages/react-reconciler/src/ReactFiberLane.js
vendored
|
|
@ -28,6 +28,7 @@ import {
|
|||
retryLaneExpirationMs,
|
||||
disableLegacyMode,
|
||||
enableDefaultTransitionIndicator,
|
||||
enableGestureTransition,
|
||||
} from 'shared/ReactFeatureFlags';
|
||||
import {isDevToolsPresent} from './ReactFiberDevToolsHook';
|
||||
import {clz32} from './clz32';
|
||||
|
|
@ -710,6 +711,9 @@ export function isTransitionLane(lane: Lane): boolean {
|
|||
}
|
||||
|
||||
export function isGestureRender(lanes: Lanes): boolean {
|
||||
if (!enableGestureTransition) {
|
||||
return false;
|
||||
}
|
||||
// This should render only the one lane.
|
||||
return lanes === GestureLane;
|
||||
}
|
||||
|
|
@ -1271,11 +1275,13 @@ export function getGroupNameOfHighestPriorityLane(lanes: Lanes): string {
|
|||
InputContinuousHydrationLane |
|
||||
InputContinuousLane |
|
||||
DefaultHydrationLane |
|
||||
DefaultLane |
|
||||
GestureLane)
|
||||
DefaultLane)
|
||||
) {
|
||||
return 'Blocking';
|
||||
}
|
||||
if (lanes & GestureLane) {
|
||||
return 'Gesture';
|
||||
}
|
||||
if (lanes & (TransitionHydrationLane | TransitionLanes)) {
|
||||
return 'Transition';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,10 @@ import {
|
|||
addObjectDiffToProperties,
|
||||
} from 'shared/ReactPerformanceTrackProperties';
|
||||
|
||||
import {enableProfilerTimer} from 'shared/ReactFeatureFlags';
|
||||
import {
|
||||
enableProfilerTimer,
|
||||
enableGestureTransition,
|
||||
} from 'shared/ReactFeatureFlags';
|
||||
|
||||
const supportsUserTiming =
|
||||
enableProfilerTimer &&
|
||||
|
|
@ -68,6 +71,16 @@ export function markAllLanesInOrder() {
|
|||
LANES_TRACK_GROUP,
|
||||
'primary-light',
|
||||
);
|
||||
if (enableGestureTransition) {
|
||||
console.timeStamp(
|
||||
'Gesture Track',
|
||||
0.003,
|
||||
0.003,
|
||||
'Gesture',
|
||||
LANES_TRACK_GROUP,
|
||||
'primary-light',
|
||||
);
|
||||
}
|
||||
console.timeStamp(
|
||||
'Transition Track',
|
||||
0.003,
|
||||
|
|
@ -739,6 +752,145 @@ export function logBlockingStart(
|
|||
}
|
||||
}
|
||||
|
||||
export function logGestureStart(
|
||||
startTime: number,
|
||||
updateTime: number,
|
||||
eventTime: number,
|
||||
eventType: null | string,
|
||||
eventIsRepeat: boolean,
|
||||
isPingedUpdate: boolean,
|
||||
renderStartTime: number,
|
||||
debugTask: null | ConsoleTask, // DEV-only
|
||||
updateMethodName: null | string,
|
||||
updateComponentName: null | string,
|
||||
): void {
|
||||
if (supportsUserTiming) {
|
||||
currentTrack = 'Gesture';
|
||||
// Clamp start times
|
||||
if (updateTime > 0) {
|
||||
if (updateTime > renderStartTime) {
|
||||
updateTime = renderStartTime;
|
||||
}
|
||||
} else {
|
||||
updateTime = renderStartTime;
|
||||
}
|
||||
if (startTime > 0) {
|
||||
if (startTime > updateTime) {
|
||||
startTime = updateTime;
|
||||
}
|
||||
} else {
|
||||
startTime = updateTime;
|
||||
}
|
||||
if (eventTime > 0) {
|
||||
if (eventTime > startTime) {
|
||||
eventTime = startTime;
|
||||
}
|
||||
} else {
|
||||
eventTime = startTime;
|
||||
}
|
||||
|
||||
if (startTime > eventTime && eventType !== null) {
|
||||
// Log the time from the event timeStamp until we started a gesture.
|
||||
const color = eventIsRepeat ? 'secondary-light' : 'warning';
|
||||
if (__DEV__ && debugTask) {
|
||||
debugTask.run(
|
||||
console.timeStamp.bind(
|
||||
console,
|
||||
eventIsRepeat ? 'Consecutive' : 'Event: ' + eventType,
|
||||
eventTime,
|
||||
startTime,
|
||||
currentTrack,
|
||||
LANES_TRACK_GROUP,
|
||||
color,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
console.timeStamp(
|
||||
eventIsRepeat ? 'Consecutive' : 'Event: ' + eventType,
|
||||
eventTime,
|
||||
startTime,
|
||||
currentTrack,
|
||||
LANES_TRACK_GROUP,
|
||||
color,
|
||||
);
|
||||
}
|
||||
}
|
||||
if (updateTime > startTime) {
|
||||
// Log the time from when we started a gesture until we called setState or started rendering.
|
||||
if (__DEV__ && debugTask) {
|
||||
debugTask.run(
|
||||
// $FlowFixMe[method-unbinding]
|
||||
console.timeStamp.bind(
|
||||
console,
|
||||
'Gesture',
|
||||
startTime,
|
||||
updateTime,
|
||||
currentTrack,
|
||||
LANES_TRACK_GROUP,
|
||||
'primary-dark',
|
||||
),
|
||||
);
|
||||
} else {
|
||||
console.timeStamp(
|
||||
'Gesture',
|
||||
startTime,
|
||||
updateTime,
|
||||
currentTrack,
|
||||
LANES_TRACK_GROUP,
|
||||
'primary-dark',
|
||||
);
|
||||
}
|
||||
}
|
||||
if (renderStartTime > updateTime) {
|
||||
// Log the time from when we called setState until we started rendering.
|
||||
const label = isPingedUpdate
|
||||
? 'Promise Resolved'
|
||||
: renderStartTime - updateTime > 5
|
||||
? 'Update Blocked'
|
||||
: 'Update';
|
||||
if (__DEV__) {
|
||||
const properties = [];
|
||||
if (updateComponentName != null) {
|
||||
properties.push(['Component name', updateComponentName]);
|
||||
}
|
||||
if (updateMethodName != null) {
|
||||
properties.push(['Method name', updateMethodName]);
|
||||
}
|
||||
const measureOptions = {
|
||||
start: updateTime,
|
||||
end: renderStartTime,
|
||||
detail: {
|
||||
devtools: {
|
||||
properties,
|
||||
track: currentTrack,
|
||||
trackGroup: LANES_TRACK_GROUP,
|
||||
color: 'primary-light',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
if (debugTask) {
|
||||
debugTask.run(
|
||||
// $FlowFixMe[method-unbinding]
|
||||
performance.measure.bind(performance, label, measureOptions),
|
||||
);
|
||||
} else {
|
||||
performance.measure(label, measureOptions);
|
||||
}
|
||||
} else {
|
||||
console.timeStamp(
|
||||
label,
|
||||
updateTime,
|
||||
renderStartTime,
|
||||
currentTrack,
|
||||
LANES_TRACK_GROUP,
|
||||
'primary-light',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function logTransitionStart(
|
||||
startTime: number,
|
||||
updateTime: number,
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ import {
|
|||
} from './Scheduler';
|
||||
import {
|
||||
logBlockingStart,
|
||||
logGestureStart,
|
||||
logTransitionStart,
|
||||
logRenderPhase,
|
||||
logInterruptedRenderPhase,
|
||||
|
|
@ -282,6 +283,17 @@ import {
|
|||
blockingEventType,
|
||||
blockingEventIsRepeat,
|
||||
blockingSuspendedTime,
|
||||
gestureClampTime,
|
||||
gestureStartTime,
|
||||
gestureUpdateTime,
|
||||
gestureUpdateTask,
|
||||
gestureUpdateType,
|
||||
gestureUpdateMethodName,
|
||||
gestureUpdateComponentName,
|
||||
gestureEventTime,
|
||||
gestureEventType,
|
||||
gestureEventIsRepeat,
|
||||
gestureSuspendedTime,
|
||||
transitionClampTime,
|
||||
transitionStartTime,
|
||||
transitionUpdateTime,
|
||||
|
|
@ -294,8 +306,10 @@ import {
|
|||
transitionEventIsRepeat,
|
||||
transitionSuspendedTime,
|
||||
clearBlockingTimers,
|
||||
clearGestureTimers,
|
||||
clearTransitionTimers,
|
||||
clampBlockingTimers,
|
||||
clampGestureTimers,
|
||||
clampTransitionTimers,
|
||||
clampRetryTimers,
|
||||
clampIdleTimers,
|
||||
|
|
@ -1898,7 +1912,9 @@ function resetWorkInProgressStack() {
|
|||
|
||||
function finalizeRender(lanes: Lanes, finalizationTime: number): void {
|
||||
if (enableProfilerTimer && enableComponentPerformanceTrack) {
|
||||
if (includesBlockingLane(lanes)) {
|
||||
if (isGestureRender(lanes)) {
|
||||
clampGestureTimers(finalizationTime);
|
||||
} else if (includesBlockingLane(lanes)) {
|
||||
clampBlockingTimers(finalizationTime);
|
||||
}
|
||||
if (includesTransitionLane(lanes)) {
|
||||
|
|
@ -1963,7 +1979,58 @@ function prepareFreshStack(root: FiberRoot, lanes: Lanes): Fiber {
|
|||
const previousUpdateTask = workInProgressUpdateTask;
|
||||
|
||||
workInProgressUpdateTask = null;
|
||||
if (includesBlockingLane(lanes)) {
|
||||
if (isGestureRender(lanes)) {
|
||||
workInProgressUpdateTask = gestureUpdateTask;
|
||||
const clampedStartTime =
|
||||
gestureStartTime >= 0 && gestureStartTime < gestureClampTime
|
||||
? gestureClampTime
|
||||
: gestureStartTime;
|
||||
const clampedUpdateTime =
|
||||
gestureUpdateTime >= 0 && gestureUpdateTime < gestureClampTime
|
||||
? gestureClampTime
|
||||
: gestureUpdateTime;
|
||||
const clampedEventTime =
|
||||
gestureEventTime >= 0 && gestureEventTime < gestureClampTime
|
||||
? gestureClampTime
|
||||
: gestureEventTime;
|
||||
const clampedRenderStartTime =
|
||||
// Clamp the suspended time to the first event/update.
|
||||
clampedEventTime >= 0
|
||||
? clampedEventTime
|
||||
: clampedUpdateTime >= 0
|
||||
? clampedUpdateTime
|
||||
: renderStartTime;
|
||||
if (gestureSuspendedTime >= 0) {
|
||||
setCurrentTrackFromLanes(GestureLane);
|
||||
logSuspendedWithDelayPhase(
|
||||
gestureSuspendedTime,
|
||||
clampedRenderStartTime,
|
||||
lanes,
|
||||
workInProgressUpdateTask,
|
||||
);
|
||||
} else if (isGestureRender(animatingLanes)) {
|
||||
// If this lane is still animating, log the time from previous render finishing to now as animating.
|
||||
setCurrentTrackFromLanes(GestureLane);
|
||||
logAnimatingPhase(
|
||||
gestureClampTime,
|
||||
clampedRenderStartTime,
|
||||
animatingTask,
|
||||
);
|
||||
}
|
||||
logGestureStart(
|
||||
clampedStartTime,
|
||||
clampedUpdateTime,
|
||||
clampedEventTime,
|
||||
gestureEventType,
|
||||
gestureEventIsRepeat,
|
||||
gestureUpdateType === PINGED_UPDATE,
|
||||
renderStartTime,
|
||||
gestureUpdateTask,
|
||||
gestureUpdateMethodName,
|
||||
gestureUpdateComponentName,
|
||||
);
|
||||
clearGestureTimers();
|
||||
} else if (includesBlockingLane(lanes)) {
|
||||
workInProgressUpdateTask = blockingUpdateTask;
|
||||
const clampedUpdateTime =
|
||||
blockingUpdateTime >= 0 && blockingUpdateTime < blockingClampTime
|
||||
|
|
@ -3716,12 +3783,12 @@ function finishedViewTransition(lanes: Lanes): void {
|
|||
// If an affected track isn't in the middle of rendering or committing, log from the previous
|
||||
// finished render until the end of the animation.
|
||||
if (
|
||||
includesBlockingLane(lanes) &&
|
||||
!includesBlockingLane(workInProgressRootRenderLanes) &&
|
||||
!includesBlockingLane(pendingEffectsLanes)
|
||||
isGestureRender(lanes) &&
|
||||
!isGestureRender(workInProgressRootRenderLanes) &&
|
||||
!isGestureRender(pendingEffectsLanes)
|
||||
) {
|
||||
setCurrentTrackFromLanes(SyncLane);
|
||||
logAnimatingPhase(blockingClampTime, now(), task);
|
||||
setCurrentTrackFromLanes(GestureLane);
|
||||
logAnimatingPhase(gestureClampTime, now(), task);
|
||||
}
|
||||
if (
|
||||
includesTransitionLane(lanes) &&
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import type {CapturedValue} from './ReactCapturedValue';
|
|||
import {
|
||||
isTransitionLane,
|
||||
isBlockingLane,
|
||||
isGestureRender,
|
||||
includesTransitionLane,
|
||||
includesBlockingLane,
|
||||
NoLanes,
|
||||
|
|
@ -74,6 +75,19 @@ export let blockingEventTime: number = -1.1; // Event timeStamp of the first set
|
|||
export let blockingEventType: null | string = null; // Event type of the first setState.
|
||||
export let blockingEventIsRepeat: boolean = false;
|
||||
export let blockingSuspendedTime: number = -1.1;
|
||||
|
||||
export let gestureClampTime: number = -0;
|
||||
export let gestureStartTime: number = -1.1; // First startGestureTransition call before setOptimistic.
|
||||
export let gestureUpdateTime: number = -1.1; // First setOptimistic scheduled inside startGestureTransition.
|
||||
export let gestureUpdateTask: null | ConsoleTask = null; // First sync setState's stack trace.
|
||||
export let gestureUpdateType: UpdateType = 0;
|
||||
export let gestureUpdateMethodName: null | string = null; // The name of the method that caused first gesture update.
|
||||
export let gestureUpdateComponentName: null | string = null; // The name of the component where first gesture update happened.
|
||||
export let gestureEventTime: number = -1.1; // Event timeStamp of the first setState.
|
||||
export let gestureEventType: null | string = null; // Event type of the first setState.
|
||||
export let gestureEventIsRepeat: boolean = false;
|
||||
export let gestureSuspendedTime: number = -1.1;
|
||||
|
||||
// TODO: This should really be one per Transition lane.
|
||||
export let transitionClampTime: number = -0;
|
||||
export let transitionStartTime: number = -1.1; // First startTransition call before setState.
|
||||
|
|
@ -112,7 +126,28 @@ export function startUpdateTimerByLane(
|
|||
if (!enableProfilerTimer || !enableComponentPerformanceTrack) {
|
||||
return;
|
||||
}
|
||||
if (isBlockingLane(lane)) {
|
||||
if (isGestureRender(lane)) {
|
||||
if (gestureUpdateTime < 0) {
|
||||
gestureUpdateTime = now();
|
||||
gestureUpdateTask = createTask(method);
|
||||
gestureUpdateMethodName = method;
|
||||
if (__DEV__ && fiber != null) {
|
||||
gestureUpdateComponentName = getComponentNameFromFiber(fiber);
|
||||
}
|
||||
if (gestureStartTime < 0) {
|
||||
const newEventTime = resolveEventTimeStamp();
|
||||
const newEventType = resolveEventType();
|
||||
if (
|
||||
newEventTime !== gestureEventTime ||
|
||||
newEventType !== gestureEventType
|
||||
) {
|
||||
gestureEventIsRepeat = false;
|
||||
}
|
||||
gestureEventTime = newEventTime;
|
||||
gestureEventType = newEventType;
|
||||
}
|
||||
}
|
||||
} else if (isBlockingLane(lane)) {
|
||||
if (blockingUpdateTime < 0) {
|
||||
blockingUpdateTime = now();
|
||||
blockingUpdateTask = createTask(method);
|
||||
|
|
@ -218,7 +253,13 @@ export function startPingTimerByLanes(lanes: Lanes): void {
|
|||
// Mark the update time and clamp anything before it because we don't want
|
||||
// to show the event time for pings but we also don't want to clear it
|
||||
// because we still need to track if this was a repeat.
|
||||
if (includesBlockingLane(lanes)) {
|
||||
if (isGestureRender(lanes)) {
|
||||
if (gestureUpdateTime < 0) {
|
||||
gestureClampTime = gestureUpdateTime = now();
|
||||
gestureUpdateTask = createTask('Promise Resolved');
|
||||
gestureUpdateType = PINGED_UPDATE;
|
||||
}
|
||||
} else if (includesBlockingLane(lanes)) {
|
||||
if (blockingUpdateTime < 0) {
|
||||
blockingClampTime = blockingUpdateTime = now();
|
||||
blockingUpdateTask = createTask('Promise Resolved');
|
||||
|
|
@ -237,7 +278,9 @@ export function trackSuspendedTime(lanes: Lanes, renderEndTime: number) {
|
|||
if (!enableProfilerTimer || !enableComponentPerformanceTrack) {
|
||||
return;
|
||||
}
|
||||
if (includesBlockingLane(lanes)) {
|
||||
if (isGestureRender(lanes)) {
|
||||
gestureSuspendedTime = renderEndTime;
|
||||
} else if (includesBlockingLane(lanes)) {
|
||||
blockingSuspendedTime = renderEndTime;
|
||||
} else if (includesTransitionLane(lanes)) {
|
||||
transitionSuspendedTime = renderEndTime;
|
||||
|
|
@ -291,6 +334,43 @@ export function clearTransitionTimers(): void {
|
|||
transitionClampTime = now();
|
||||
}
|
||||
|
||||
export function startGestureTransitionTimer(): void {
|
||||
if (!enableProfilerTimer || !enableComponentPerformanceTrack) {
|
||||
return;
|
||||
}
|
||||
if (gestureStartTime < 0 && gestureUpdateTime < 0) {
|
||||
gestureStartTime = now();
|
||||
const newEventTime = resolveEventTimeStamp();
|
||||
const newEventType = resolveEventType();
|
||||
if (
|
||||
newEventTime !== gestureEventTime ||
|
||||
newEventType !== gestureEventType
|
||||
) {
|
||||
gestureEventIsRepeat = false;
|
||||
}
|
||||
gestureEventTime = newEventTime;
|
||||
gestureEventType = newEventType;
|
||||
}
|
||||
}
|
||||
|
||||
export function hasScheduledGestureTransitionWork(): boolean {
|
||||
// If we have call setOptimistic on a gesture
|
||||
return gestureUpdateTime > -1;
|
||||
}
|
||||
|
||||
export function clearGestureTransitionTimer(): void {
|
||||
gestureStartTime = -1.1;
|
||||
}
|
||||
|
||||
export function clearGestureTimers(): void {
|
||||
gestureStartTime = -1.1;
|
||||
gestureUpdateTime = -1.1;
|
||||
gestureUpdateType = 0;
|
||||
gestureSuspendedTime = -1.1;
|
||||
gestureEventIsRepeat = true;
|
||||
gestureClampTime = now();
|
||||
}
|
||||
|
||||
export function clampBlockingTimers(finalTime: number): void {
|
||||
if (!enableProfilerTimer || !enableComponentPerformanceTrack) {
|
||||
return;
|
||||
|
|
@ -301,6 +381,16 @@ export function clampBlockingTimers(finalTime: number): void {
|
|||
blockingClampTime = finalTime;
|
||||
}
|
||||
|
||||
export function clampGestureTimers(finalTime: number): void {
|
||||
if (!enableProfilerTimer || !enableComponentPerformanceTrack) {
|
||||
return;
|
||||
}
|
||||
// If we had new updates come in while we were still rendering or committing, we don't want
|
||||
// those update times to create overlapping tracks in the performance timeline so we clamp
|
||||
// them to the end of the commit phase.
|
||||
gestureClampTime = finalTime;
|
||||
}
|
||||
|
||||
export function clampTransitionTimers(finalTime: number): void {
|
||||
if (!enableProfilerTimer || !enableComponentPerformanceTrack) {
|
||||
return;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user