import type {Fiber} from './ReactInternalTypes';
import getComponentNameFromFiber from './getComponentNameFromFiber';
import {getGroupNameOfHighestPriorityLane} from './ReactFiberLane';
import {enableProfilerTimer} from 'shared/ReactFeatureFlags';
const supportsUserTiming =
enableProfilerTimer &&
typeof performance !== 'undefined' &&
typeof performance.measure === 'function';
const TRACK_GROUP = 'Components ⚛';
const reusableComponentDevToolDetails = {
dataType: 'track-entry',
color: 'primary',
track: 'Blocking',
trackGroup: TRACK_GROUP,
};
const reusableComponentOptions = {
start: -0,
end: -0,
detail: {
devtools: reusableComponentDevToolDetails,
},
};
export function setCurrentTrackFromLanes(lanes: number): void {
reusableComponentDevToolDetails.track =
getGroupNameOfHighestPriorityLane(lanes);
}
export function logComponentRender(
fiber: Fiber,
startTime: number,
endTime: number,
): void {
const name = getComponentNameFromFiber(fiber);
if (name === null) {
return;
}
if (supportsUserTiming) {
let selfTime: number = (fiber.actualDuration: any);
if (fiber.alternate === null || fiber.alternate.child !== fiber.child) {
for (let child = fiber.child; child !== null; child = child.sibling) {
selfTime -= (child.actualDuration: any);
}
}
reusableComponentDevToolDetails.color =
selfTime < 0.5
? 'primary-light'
: selfTime < 10
? 'primary'
: selfTime < 100
? 'primary-dark'
: 'error';
reusableComponentOptions.start = startTime;
reusableComponentOptions.end = endTime;
performance.measure(name, reusableComponentOptions);
}
}
export function logComponentEffect(
fiber: Fiber,
startTime: number,
endTime: number,
selfTime: number,
): void {
const name = getComponentNameFromFiber(fiber);
if (name === null) {
return;
}
if (supportsUserTiming) {
reusableComponentDevToolDetails.color =
selfTime < 1
? 'secondary-light'
: selfTime < 100
? 'secondary'
: selfTime < 500
? 'secondary-dark'
: 'error';
reusableComponentOptions.start = startTime;
reusableComponentOptions.end = endTime;
performance.measure(name, reusableComponentOptions);
}
}
export function logBlockingStart(
updateTime: number,
eventTime: number,
eventType: null | string,
renderStartTime: number,
): void {
if (supportsUserTiming) {
reusableComponentDevToolDetails.track = 'Blocking';
if (eventTime > 0 && eventType !== null) {
reusableComponentDevToolDetails.color = 'secondary-dark';
reusableComponentOptions.start = eventTime;
reusableComponentOptions.end =
updateTime > 0 ? updateTime : renderStartTime;
performance.measure(eventType, reusableComponentOptions);
}
if (updateTime > 0) {
reusableComponentDevToolDetails.color = 'primary-light';
reusableComponentOptions.start = updateTime;
reusableComponentOptions.end = renderStartTime;
performance.measure('Blocked', reusableComponentOptions);
}
}
}
export function logTransitionStart(
startTime: number,
updateTime: number,
eventTime: number,
eventType: null | string,
renderStartTime: number,
): void {
if (supportsUserTiming) {
reusableComponentDevToolDetails.track = 'Transition';
if (eventTime > 0 && eventType !== null) {
reusableComponentDevToolDetails.color = 'secondary-dark';
reusableComponentOptions.start = eventTime;
reusableComponentOptions.end =
startTime > 0
? startTime
: updateTime > 0
? updateTime
: renderStartTime;
performance.measure(eventType, reusableComponentOptions);
}
if (startTime > 0) {
reusableComponentDevToolDetails.color = 'primary-dark';
reusableComponentOptions.start = startTime;
reusableComponentOptions.end =
updateTime > 0 ? updateTime : renderStartTime;
performance.measure('Action', reusableComponentOptions);
}
if (updateTime > 0) {
reusableComponentDevToolDetails.color = 'primary-light';
reusableComponentOptions.start = updateTime;
reusableComponentOptions.end = renderStartTime;
performance.measure('Blocked', reusableComponentOptions);
}
}
}
export function logRenderPhase(startTime: number, endTime: number): void {
if (supportsUserTiming) {
reusableComponentDevToolDetails.color = 'primary-dark';
reusableComponentOptions.start = startTime;
reusableComponentOptions.end = endTime;
performance.measure('Render', reusableComponentOptions);
}
}
export function logSuspenseThrottlePhase(
startTime: number,
endTime: number,
): void {
if (supportsUserTiming) {
reusableComponentDevToolDetails.color = 'secondary-light';
reusableComponentOptions.start = startTime;
reusableComponentOptions.end = endTime;
performance.measure('Throttled', reusableComponentOptions);
}
}
export function logSuspendedCommitPhase(
startTime: number,
endTime: number,
): void {
if (supportsUserTiming) {
reusableComponentDevToolDetails.color = 'secondary-light';
reusableComponentOptions.start = startTime;
reusableComponentOptions.end = endTime;
performance.measure('Suspended', reusableComponentOptions);
}
}
export function logCommitPhase(startTime: number, endTime: number): void {
if (supportsUserTiming) {
reusableComponentDevToolDetails.color = 'secondary-dark';
reusableComponentOptions.start = startTime;
reusableComponentOptions.end = endTime;
performance.measure('Commit', reusableComponentOptions);
}
}
export function logPaintYieldPhase(startTime: number, endTime: number): void {
if (supportsUserTiming) {
reusableComponentDevToolDetails.color = 'secondary-light';
reusableComponentOptions.start = startTime;
reusableComponentOptions.end = endTime;
performance.measure('Waiting for Paint', reusableComponentOptions);
}
}
export function logPassiveCommitPhase(
startTime: number,
endTime: number,
): void {
if (supportsUserTiming) {
reusableComponentDevToolDetails.color = 'secondary-dark';
reusableComponentOptions.start = startTime;
reusableComponentOptions.end = endTime;
performance.measure('Remaining Effects', reusableComponentOptions);
}
}