From 466b26c926a2de92231f7cc2e75745563a91003d Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Tue, 16 Mar 2021 13:53:15 -0400 Subject: [PATCH] Store commit durations on HostRoot for DevTools access (#20983) Also add missing feature flag wrappers around effect duration attributes. --- .../src/ReactFiberBeginWork.new.js | 25 ++++++---- .../src/ReactFiberBeginWork.old.js | 25 ++++++---- .../src/ReactFiberCommitWork.new.js | 30 ++++++++---- .../src/ReactFiberCommitWork.old.js | 30 ++++++++---- .../src/ReactFiberRoot.new.js | 7 +++ .../src/ReactFiberRoot.old.js | 7 +++ .../src/ReactProfilerTimer.new.js | 46 ++++++++++++------- .../src/ReactProfilerTimer.old.js | 46 ++++++++++++------- 8 files changed, 144 insertions(+), 72 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.new.js b/packages/react-reconciler/src/ReactFiberBeginWork.new.js index a014ef5747895..9ba666bd548e8 100644 --- a/packages/react-reconciler/src/ReactFiberBeginWork.new.js +++ b/packages/react-reconciler/src/ReactFiberBeginWork.new.js @@ -75,6 +75,7 @@ import { debugRenderPhaseSideEffectsForStrictMode, disableLegacyContext, disableModulePatternComponents, + enableProfilerCommitHooks, enableProfilerTimer, enableSchedulerTracing, enableSuspenseServerRenderer, @@ -837,11 +838,13 @@ function updateProfiler( if (enableProfilerTimer) { workInProgress.flags |= Update; - // Reset effect durations for the next eventual effect phase. - // These are reset during render to allow the DevTools commit hook a chance to read them, - const stateNode = workInProgress.stateNode; - stateNode.effectDuration = 0; - stateNode.passiveEffectDuration = 0; + if (enableProfilerCommitHooks) { + // Reset effect durations for the next eventual effect phase. + // These are reset during render to allow the DevTools commit hook a chance to read them, + const stateNode = workInProgress.stateNode; + stateNode.effectDuration = 0; + stateNode.passiveEffectDuration = 0; + } } const nextProps = workInProgress.pendingProps; const nextChildren = nextProps.children; @@ -3320,11 +3323,13 @@ function beginWork( workInProgress.flags |= Update; } - // Reset effect durations for the next eventual effect phase. - // These are reset during render to allow the DevTools commit hook a chance to read them, - const stateNode = workInProgress.stateNode; - stateNode.effectDuration = 0; - stateNode.passiveEffectDuration = 0; + if (enableProfilerCommitHooks) { + // Reset effect durations for the next eventual effect phase. + // These are reset during render to allow the DevTools commit hook a chance to read them, + const stateNode = workInProgress.stateNode; + stateNode.effectDuration = 0; + stateNode.passiveEffectDuration = 0; + } } break; case SuspenseComponent: { diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.old.js b/packages/react-reconciler/src/ReactFiberBeginWork.old.js index 2c355abdf95b2..822b299d06ca8 100644 --- a/packages/react-reconciler/src/ReactFiberBeginWork.old.js +++ b/packages/react-reconciler/src/ReactFiberBeginWork.old.js @@ -75,6 +75,7 @@ import { debugRenderPhaseSideEffectsForStrictMode, disableLegacyContext, disableModulePatternComponents, + enableProfilerCommitHooks, enableProfilerTimer, enableSchedulerTracing, enableSuspenseServerRenderer, @@ -837,11 +838,13 @@ function updateProfiler( if (enableProfilerTimer) { workInProgress.flags |= Update; - // Reset effect durations for the next eventual effect phase. - // These are reset during render to allow the DevTools commit hook a chance to read them, - const stateNode = workInProgress.stateNode; - stateNode.effectDuration = 0; - stateNode.passiveEffectDuration = 0; + if (enableProfilerCommitHooks) { + // Reset effect durations for the next eventual effect phase. + // These are reset during render to allow the DevTools commit hook a chance to read them, + const stateNode = workInProgress.stateNode; + stateNode.effectDuration = 0; + stateNode.passiveEffectDuration = 0; + } } const nextProps = workInProgress.pendingProps; const nextChildren = nextProps.children; @@ -3320,11 +3323,13 @@ function beginWork( workInProgress.flags |= Update; } - // Reset effect durations for the next eventual effect phase. - // These are reset during render to allow the DevTools commit hook a chance to read them, - const stateNode = workInProgress.stateNode; - stateNode.effectDuration = 0; - stateNode.passiveEffectDuration = 0; + if (enableProfilerCommitHooks) { + // Reset effect durations for the next eventual effect phase. + // These are reset during render to allow the DevTools commit hook a chance to read them, + const stateNode = workInProgress.stateNode; + stateNode.effectDuration = 0; + stateNode.passiveEffectDuration = 0; + } } break; case SuspenseComponent: { diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.new.js b/packages/react-reconciler/src/ReactFiberCommitWork.new.js index 7985366d3f67c..c20719d8bfd96 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.new.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.new.js @@ -578,11 +578,16 @@ export function commitPassiveEffectDurations( // Bubble times to the next nearest ancestor Profiler. // After we process that Profiler, we'll bubble further up. let parentFiber = finishedWork.return; - while (parentFiber !== null) { - if (parentFiber.tag === Profiler) { - const parentStateNode = parentFiber.stateNode; - parentStateNode.passiveEffectDuration += passiveEffectDuration; - break; + outer: while (parentFiber !== null) { + switch (parentFiber.tag) { + case HostRoot: + const root = parentFiber.stateNode; + root.passiveEffectDuration += passiveEffectDuration; + break outer; + case Profiler: + const parentStateNode = parentFiber.stateNode; + parentStateNode.passiveEffectDuration += passiveEffectDuration; + break outer; } parentFiber = parentFiber.return; } @@ -885,11 +890,16 @@ function commitLayoutEffectOnFiber( // Propagate layout effect durations to the next nearest Profiler ancestor. // Do not reset these values until the next render so DevTools has a chance to read them first. let parentFiber = finishedWork.return; - while (parentFiber !== null) { - if (parentFiber.tag === Profiler) { - const parentStateNode = parentFiber.stateNode; - parentStateNode.effectDuration += effectDuration; - break; + outer: while (parentFiber !== null) { + switch (parentFiber.tag) { + case HostRoot: + const root = parentFiber.stateNode; + root.effectDuration += effectDuration; + break outer; + case Profiler: + const parentStateNode = parentFiber.stateNode; + parentStateNode.effectDuration += effectDuration; + break outer; } parentFiber = parentFiber.return; } diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.old.js b/packages/react-reconciler/src/ReactFiberCommitWork.old.js index d50095b3bebb1..efdbc39abfdfc 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.old.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.old.js @@ -578,11 +578,16 @@ export function commitPassiveEffectDurations( // Bubble times to the next nearest ancestor Profiler. // After we process that Profiler, we'll bubble further up. let parentFiber = finishedWork.return; - while (parentFiber !== null) { - if (parentFiber.tag === Profiler) { - const parentStateNode = parentFiber.stateNode; - parentStateNode.passiveEffectDuration += passiveEffectDuration; - break; + outer: while (parentFiber !== null) { + switch (parentFiber.tag) { + case HostRoot: + const root = parentFiber.stateNode; + root.passiveEffectDuration += passiveEffectDuration; + break outer; + case Profiler: + const parentStateNode = parentFiber.stateNode; + parentStateNode.passiveEffectDuration += passiveEffectDuration; + break outer; } parentFiber = parentFiber.return; } @@ -885,11 +890,16 @@ function commitLayoutEffectOnFiber( // Propagate layout effect durations to the next nearest Profiler ancestor. // Do not reset these values until the next render so DevTools has a chance to read them first. let parentFiber = finishedWork.return; - while (parentFiber !== null) { - if (parentFiber.tag === Profiler) { - const parentStateNode = parentFiber.stateNode; - parentStateNode.effectDuration += effectDuration; - break; + outer: while (parentFiber !== null) { + switch (parentFiber.tag) { + case HostRoot: + const root = parentFiber.stateNode; + root.effectDuration += effectDuration; + break outer; + case Profiler: + const parentStateNode = parentFiber.stateNode; + parentStateNode.effectDuration += effectDuration; + break outer; } parentFiber = parentFiber.return; } diff --git a/packages/react-reconciler/src/ReactFiberRoot.new.js b/packages/react-reconciler/src/ReactFiberRoot.new.js index f06925e10fbe9..14c20e1f7edee 100644 --- a/packages/react-reconciler/src/ReactFiberRoot.new.js +++ b/packages/react-reconciler/src/ReactFiberRoot.new.js @@ -22,6 +22,8 @@ import { enableSchedulerTracing, enableSuspenseCallback, enableCache, + enableProfilerCommitHooks, + enableProfilerTimer, } from 'shared/ReactFeatureFlags'; import {unstable_getThreadID} from 'scheduler/tracing'; import {initializeUpdateQueue} from './ReactUpdateQueue.new'; @@ -71,6 +73,11 @@ function FiberRootNode(containerInfo, tag, hydrate) { this.hydrationCallbacks = null; } + if (enableProfilerTimer && enableProfilerCommitHooks) { + this.effectDuration = 0; + this.passiveEffectDuration = 0; + } + if (__DEV__) { switch (tag) { case ConcurrentRoot: diff --git a/packages/react-reconciler/src/ReactFiberRoot.old.js b/packages/react-reconciler/src/ReactFiberRoot.old.js index 712803920ebb2..3bad9a026be0b 100644 --- a/packages/react-reconciler/src/ReactFiberRoot.old.js +++ b/packages/react-reconciler/src/ReactFiberRoot.old.js @@ -22,6 +22,8 @@ import { enableSchedulerTracing, enableSuspenseCallback, enableCache, + enableProfilerCommitHooks, + enableProfilerTimer, } from 'shared/ReactFeatureFlags'; import {unstable_getThreadID} from 'scheduler/tracing'; import {initializeUpdateQueue} from './ReactUpdateQueue.old'; @@ -71,6 +73,11 @@ function FiberRootNode(containerInfo, tag, hydrate) { this.hydrationCallbacks = null; } + if (enableProfilerTimer && enableProfilerCommitHooks) { + this.effectDuration = 0; + this.passiveEffectDuration = 0; + } + if (__DEV__) { switch (tag) { case ConcurrentRoot: diff --git a/packages/react-reconciler/src/ReactProfilerTimer.new.js b/packages/react-reconciler/src/ReactProfilerTimer.new.js index 235074b78ad8d..a5a14eae1c244 100644 --- a/packages/react-reconciler/src/ReactProfilerTimer.new.js +++ b/packages/react-reconciler/src/ReactProfilerTimer.new.js @@ -14,7 +14,7 @@ import { enableProfilerNestedUpdatePhase, enableProfilerTimer, } from 'shared/ReactFeatureFlags'; -import {Profiler} from './ReactWorkTags'; +import {HostRoot, Profiler} from './ReactWorkTags'; // Intentionally not named imports because Rollup would use dynamic dispatch for // CommonJS interop named imports. @@ -140,13 +140,19 @@ function recordLayoutEffectDuration(fiber: Fiber): void { layoutEffectStartTime = -1; - // Store duration on the next nearest Profiler ancestor. + // Store duration on the next nearest Profiler ancestor + // Or the root (for the DevTools Profiler to read) let parentFiber = fiber.return; while (parentFiber !== null) { - if (parentFiber.tag === Profiler) { - const parentStateNode = parentFiber.stateNode; - parentStateNode.effectDuration += elapsedTime; - break; + switch (parentFiber.tag) { + case HostRoot: + const root = parentFiber.stateNode; + root.effectDuration += elapsedTime; + return; + case Profiler: + const parentStateNode = parentFiber.stateNode; + parentStateNode.effectDuration += elapsedTime; + return; } parentFiber = parentFiber.return; } @@ -163,18 +169,26 @@ function recordPassiveEffectDuration(fiber: Fiber): void { passiveEffectStartTime = -1; - // Store duration on the next nearest Profiler ancestor. + // Store duration on the next nearest Profiler ancestor + // Or the root (for the DevTools Profiler to read) let parentFiber = fiber.return; while (parentFiber !== null) { - if (parentFiber.tag === Profiler) { - const parentStateNode = parentFiber.stateNode; - if (parentStateNode !== null) { - // Detached fibers have their state node cleared out. - // In this case, the return pointer is also cleared out, - // so we won't be able to report the time spent in this Profiler's subtree. - parentStateNode.passiveEffectDuration += elapsedTime; - } - break; + switch (parentFiber.tag) { + case HostRoot: + const root = parentFiber.stateNode; + if (root !== null) { + root.passiveEffectDuration += elapsedTime; + } + return; + case Profiler: + const parentStateNode = parentFiber.stateNode; + if (parentStateNode !== null) { + // Detached fibers have their state node cleared out. + // In this case, the return pointer is also cleared out, + // so we won't be able to report the time spent in this Profiler's subtree. + parentStateNode.passiveEffectDuration += elapsedTime; + } + return; } parentFiber = parentFiber.return; } diff --git a/packages/react-reconciler/src/ReactProfilerTimer.old.js b/packages/react-reconciler/src/ReactProfilerTimer.old.js index 235074b78ad8d..a5a14eae1c244 100644 --- a/packages/react-reconciler/src/ReactProfilerTimer.old.js +++ b/packages/react-reconciler/src/ReactProfilerTimer.old.js @@ -14,7 +14,7 @@ import { enableProfilerNestedUpdatePhase, enableProfilerTimer, } from 'shared/ReactFeatureFlags'; -import {Profiler} from './ReactWorkTags'; +import {HostRoot, Profiler} from './ReactWorkTags'; // Intentionally not named imports because Rollup would use dynamic dispatch for // CommonJS interop named imports. @@ -140,13 +140,19 @@ function recordLayoutEffectDuration(fiber: Fiber): void { layoutEffectStartTime = -1; - // Store duration on the next nearest Profiler ancestor. + // Store duration on the next nearest Profiler ancestor + // Or the root (for the DevTools Profiler to read) let parentFiber = fiber.return; while (parentFiber !== null) { - if (parentFiber.tag === Profiler) { - const parentStateNode = parentFiber.stateNode; - parentStateNode.effectDuration += elapsedTime; - break; + switch (parentFiber.tag) { + case HostRoot: + const root = parentFiber.stateNode; + root.effectDuration += elapsedTime; + return; + case Profiler: + const parentStateNode = parentFiber.stateNode; + parentStateNode.effectDuration += elapsedTime; + return; } parentFiber = parentFiber.return; } @@ -163,18 +169,26 @@ function recordPassiveEffectDuration(fiber: Fiber): void { passiveEffectStartTime = -1; - // Store duration on the next nearest Profiler ancestor. + // Store duration on the next nearest Profiler ancestor + // Or the root (for the DevTools Profiler to read) let parentFiber = fiber.return; while (parentFiber !== null) { - if (parentFiber.tag === Profiler) { - const parentStateNode = parentFiber.stateNode; - if (parentStateNode !== null) { - // Detached fibers have their state node cleared out. - // In this case, the return pointer is also cleared out, - // so we won't be able to report the time spent in this Profiler's subtree. - parentStateNode.passiveEffectDuration += elapsedTime; - } - break; + switch (parentFiber.tag) { + case HostRoot: + const root = parentFiber.stateNode; + if (root !== null) { + root.passiveEffectDuration += elapsedTime; + } + return; + case Profiler: + const parentStateNode = parentFiber.stateNode; + if (parentStateNode !== null) { + // Detached fibers have their state node cleared out. + // In this case, the return pointer is also cleared out, + // so we won't be able to report the time spent in this Profiler's subtree. + parentStateNode.passiveEffectDuration += elapsedTime; + } + return; } parentFiber = parentFiber.return; }