Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions packages/react-reconciler/src/ReactFiber.js
Original file line number Diff line number Diff line change
Expand Up @@ -532,10 +532,10 @@ export function createHostRootFiber(
mode = NoMode;
}

if (enableProfilerTimer && isDevToolsPresent) {
// Always collect profile timings when DevTools are present.
// This enables DevTools to start capturing timing at any point–
// Without some nodes in the tree having empty base times.
if (__DEV__ || (enableProfilerTimer && isDevToolsPresent)) {
// dev: Enable profiling instrumentation by default.
// profile: enabled if DevTools is present or subtree is wrapped in <Profiler>.
// production: disabled.
mode |= ProfileMode;
}

Expand Down
6 changes: 3 additions & 3 deletions packages/react-reconciler/src/ReactFiberClassComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ const classComponentUpdater = {

const root = enqueueUpdate(fiber, update, lane);
if (root !== null) {
startUpdateTimerByLane(lane, 'this.setState()');
startUpdateTimerByLane(lane, 'this.setState()', fiber);
scheduleUpdateOnFiber(root, fiber, lane);
entangleTransitions(root, fiber, lane);
}
Expand All @@ -205,7 +205,7 @@ const classComponentUpdater = {

const root = enqueueUpdate(fiber, update, lane);
if (root !== null) {
startUpdateTimerByLane(lane, 'this.replaceState()');
startUpdateTimerByLane(lane, 'this.replaceState()', fiber);
scheduleUpdateOnFiber(root, fiber, lane);
entangleTransitions(root, fiber, lane);
}
Expand All @@ -231,7 +231,7 @@ const classComponentUpdater = {

const root = enqueueUpdate(fiber, update, lane);
if (root !== null) {
startUpdateTimerByLane(lane, 'this.forceUpdate()');
startUpdateTimerByLane(lane, 'this.forceUpdate()', fiber);
scheduleUpdateOnFiber(root, fiber, lane);
entangleTransitions(root, fiber, lane);
}
Expand Down
10 changes: 5 additions & 5 deletions packages/react-reconciler/src/ReactFiberHooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -1866,7 +1866,7 @@ function subscribeToStore<T>(
// read from the store.
if (checkIfSnapshotChanged(inst)) {
// Force a re-render.
startUpdateTimerByLane(SyncLane, 'updateSyncExternalStore()');
startUpdateTimerByLane(SyncLane, 'updateSyncExternalStore()', fiber);
forceStoreRerender(fiber);
}
};
Expand Down Expand Up @@ -3518,7 +3518,7 @@ function refreshCache<T>(fiber: Fiber, seedKey: ?() => T, seedValue: T): void {
const refreshUpdate = createLegacyQueueUpdate(lane);
const root = enqueueLegacyQueueUpdate(provider, refreshUpdate, lane);
if (root !== null) {
startUpdateTimerByLane(lane, 'refresh()');
startUpdateTimerByLane(lane, 'refresh()', fiber);
scheduleUpdateOnFiber(root, provider, lane);
entangleLegacyQueueTransitions(root, provider, lane);
}
Expand Down Expand Up @@ -3587,7 +3587,7 @@ function dispatchReducerAction<S, A>(
} else {
const root = enqueueConcurrentHookUpdate(fiber, queue, update, lane);
if (root !== null) {
startUpdateTimerByLane(lane, 'dispatch()');
startUpdateTimerByLane(lane, 'dispatch()', fiber);
scheduleUpdateOnFiber(root, fiber, lane);
entangleTransitionUpdate(root, queue, lane);
}
Expand Down Expand Up @@ -3621,7 +3621,7 @@ function dispatchSetState<S, A>(
lane,
);
if (didScheduleUpdate) {
startUpdateTimerByLane(lane, 'setState()');
startUpdateTimerByLane(lane, 'setState()', fiber);
}
markUpdateInDevTools(fiber, lane, action);
}
Expand Down Expand Up @@ -3783,7 +3783,7 @@ function dispatchOptimisticSetState<S, A>(
// will never be attempted before the optimistic update. This currently
// holds because the optimistic update is always synchronous. If we ever
// change that, we'll need to account for this.
startUpdateTimerByLane(lane, 'setOptimistic()');
startUpdateTimerByLane(lane, 'setOptimistic()', fiber);
scheduleUpdateOnFiber(root, fiber, lane);
// Optimistic updates are always synchronous, so we don't need to call
// entangleTransitionUpdate here.
Expand Down
125 changes: 77 additions & 48 deletions packages/react-reconciler/src/ReactFiberPerformanceTrack.js
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,8 @@ export function logBlockingStart(
renderStartTime: number,
lanes: Lanes,
debugTask: null | ConsoleTask, // DEV-only
updateMethodName: null | string,
updateComponentName: null | string,
): void {
if (supportsUserTiming) {
currentTrack = 'Blocking';
Expand Down Expand Up @@ -672,34 +674,46 @@ export function logBlockingStart(
: includesOnlyHydrationOrOffscreenLanes(lanes)
? 'tertiary-light'
: 'primary-light';
if (__DEV__ && debugTask) {
debugTask.run(
// $FlowFixMe[method-unbinding]
console.timeStamp.bind(
console,
isPingedUpdate
? 'Promise Resolved'
: isSpawnedUpdate
? 'Cascading Update'
: renderStartTime - updateTime > 5
? 'Update Blocked'
: 'Update',
updateTime,
renderStartTime,
currentTrack,
LANES_TRACK_GROUP,
color,
),
);
const label = isPingedUpdate
? 'Promise Resolved'
: isSpawnedUpdate
? 'Cascading Update'
: 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,
},
},
};

if (debugTask) {
debugTask.run(
// $FlowFixMe[method-unbinding]
performance.measure.bind(performance, label, measureOptions),
);
} else {
performance.measure(label, measureOptions);
}
} else {
console.timeStamp(
isPingedUpdate
? 'Promise Resolved'
: isSpawnedUpdate
? 'Cascading Update'
: renderStartTime - updateTime > 5
? 'Update Blocked'
: 'Update',
label,
updateTime,
renderStartTime,
currentTrack,
Expand All @@ -720,6 +734,8 @@ export function logTransitionStart(
isPingedUpdate: boolean,
renderStartTime: number,
debugTask: null | ConsoleTask, // DEV-only
updateMethodName: null | string,
updateComponentName: null | string,
): void {
if (supportsUserTiming) {
currentTrack = 'Transition';
Expand Down Expand Up @@ -781,30 +797,43 @@ export function logTransitionStart(
}
if (updateTime > 0 && renderStartTime > updateTime) {
// Log the time from when we called setState until we started rendering.
if (__DEV__ && debugTask) {
debugTask.run(
// $FlowFixMe[method-unbinding]
console.timeStamp.bind(
console,
isPingedUpdate
? 'Promise Resolved'
: renderStartTime - updateTime > 5
? 'Update Blocked'
: 'Update',
updateTime,
renderStartTime,
currentTrack,
LANES_TRACK_GROUP,
'primary-light',
),
);
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(
isPingedUpdate
? 'Promise Resolved'
: renderStartTime - updateTime > 5
? 'Update Blocked'
: 'Update',
label,
updateTime,
renderStartTime,
currentTrack,
Expand Down
4 changes: 2 additions & 2 deletions packages/react-reconciler/src/ReactFiberReconciler.js
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ export function createHydrationContainer(
update.callback =
callback !== undefined && callback !== null ? callback : null;
enqueueUpdate(current, update, lane);
startUpdateTimerByLane(lane, 'hydrateRoot()');
startUpdateTimerByLane(lane, 'hydrateRoot()', null);
scheduleInitialHydrationOnRoot(root, lane);

return root;
Expand Down Expand Up @@ -453,7 +453,7 @@ function updateContainerImpl(

const root = enqueueUpdate(rootFiber, update, lane);
if (root !== null) {
startUpdateTimerByLane(lane, 'root.render()');
startUpdateTimerByLane(lane, 'root.render()', null);
scheduleUpdateOnFiber(root, rootFiber, lane);
entangleTransitions(root, rootFiber, lane);
}
Expand Down
8 changes: 8 additions & 0 deletions packages/react-reconciler/src/ReactFiberWorkLoop.js
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,8 @@ import {
blockingUpdateTime,
blockingUpdateTask,
blockingUpdateType,
blockingUpdateMethodName,
blockingUpdateComponentName,
blockingEventTime,
blockingEventType,
blockingEventIsRepeat,
Expand All @@ -276,6 +278,8 @@ import {
transitionUpdateTime,
transitionUpdateTask,
transitionUpdateType,
transitionUpdateMethodName,
transitionUpdateComponentName,
transitionEventTime,
transitionEventType,
transitionEventIsRepeat,
Expand Down Expand Up @@ -1940,6 +1944,8 @@ function prepareFreshStack(root: FiberRoot, lanes: Lanes): Fiber {
renderStartTime,
lanes,
blockingUpdateTask,
blockingUpdateMethodName,
blockingUpdateComponentName,
);
clearBlockingTimers();
}
Expand Down Expand Up @@ -1980,6 +1986,8 @@ function prepareFreshStack(root: FiberRoot, lanes: Lanes): Fiber {
transitionUpdateType === PINGED_UPDATE,
renderStartTime,
transitionUpdateTask,
transitionUpdateMethodName,
transitionUpdateComponentName,
);
clearTransitionTimers();
}
Expand Down
21 changes: 20 additions & 1 deletion packages/react-reconciler/src/ReactProfilerTimer.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
enableComponentPerformanceTrack,
} from 'shared/ReactFeatureFlags';

import getComponentNameFromFiber from './getComponentNameFromFiber';
import {isAlreadyRendering} from './ReactFiberWorkLoop';

// Intentionally not named imports because Rollup would use dynamic dispatch for
Expand Down Expand Up @@ -68,6 +69,8 @@ export let blockingClampTime: number = -0;
export let blockingUpdateTime: number = -1.1; // First sync setState scheduled.
export let blockingUpdateTask: null | ConsoleTask = null; // First sync setState's stack trace.
export let blockingUpdateType: UpdateType = 0;
export let blockingUpdateMethodName: null | string = null; // The name of the method that caused first sync update.
export let blockingUpdateComponentName: null | string = null; // The name of the component where first sync update happened.
export let blockingEventTime: number = -1.1; // Event timeStamp of the first setState.
export let blockingEventType: null | string = null; // Event type of the first setState.
export let blockingEventIsRepeat: boolean = false;
Expand All @@ -78,6 +81,8 @@ export let transitionStartTime: number = -1.1; // First startTransition call bef
export let transitionUpdateTime: number = -1.1; // First transition setState scheduled.
export let transitionUpdateType: UpdateType = 0;
export let transitionUpdateTask: null | ConsoleTask = null; // First transition setState's stack trace.
export let transitionUpdateMethodName: null | string = null; // The name of the method that caused first transition update.
export let transitionUpdateComponentName: null | string = null; // The name of the component where first transition update happened.
export let transitionEventTime: number = -1.1; // Event timeStamp of the first transition.
export let transitionEventType: null | string = null; // Event type of the first transition.
export let transitionEventIsRepeat: boolean = false;
Expand All @@ -94,14 +99,22 @@ export function startYieldTimer(reason: SuspendedReason) {
yieldReason = reason;
}

export function startUpdateTimerByLane(lane: Lane, method: string): void {
export function startUpdateTimerByLane(
lane: Lane,
method: string,
fiber: Fiber | null,
): void {
if (!enableProfilerTimer || !enableComponentPerformanceTrack) {
return;
}
if (isSyncLane(lane) || isBlockingLane(lane)) {
if (blockingUpdateTime < 0) {
blockingUpdateTime = now();
blockingUpdateTask = createTask(method);
blockingUpdateMethodName = method;
if (__DEV__ && fiber != null) {
blockingUpdateComponentName = getComponentNameFromFiber(fiber);
}
if (isAlreadyRendering()) {
blockingUpdateType = SPAWNED_UPDATE;
}
Expand All @@ -125,6 +138,10 @@ export function startUpdateTimerByLane(lane: Lane, method: string): void {
if (transitionUpdateTime < 0) {
transitionUpdateTime = now();
transitionUpdateTask = createTask(method);
transitionUpdateMethodName = method;
if (__DEV__ && fiber != null) {
transitionUpdateComponentName = getComponentNameFromFiber(fiber);
}
if (transitionStartTime < 0) {
const newEventTime = resolveEventTimeStamp();
const newEventType = resolveEventType();
Expand Down Expand Up @@ -225,6 +242,8 @@ export function trackSuspendedTime(lanes: Lanes, renderEndTime: number) {
export function clearBlockingTimers(): void {
blockingUpdateTime = -1.1;
blockingUpdateType = 0;
blockingUpdateMethodName = null;
blockingUpdateComponentName = null;
blockingSuspendedTime = -1.1;
blockingEventIsRepeat = true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ describe(`onRender`, () => {
expect(callback).toHaveBeenCalledTimes(1);
});

// @gate !__DEV__
it('does not record times for components outside of Profiler tree', async () => {
// Mock the Scheduler module so we can track how many times the current
// time is read
Expand Down
Loading