Store commit durations on HostRoot for DevTools access (#20983)
Also add missing feature flag wrappers around effect duration attributes.
Brian Vaughn committed
Mar 16, 2021 at 13:53 UTC
466b26c926a2de92231f7cc2e75745563a91003d
8 files changed
+144
-72
packages/react-reconciler/src/ReactFiberBeginWork.new.js
+15
-10
@@ -75,6 +75,7 @@ import {
75
debugRenderPhaseSideEffectsForStrictMode,
76
disableLegacyContext,
77
disableModulePatternComponents,
78
+ enableProfilerCommitHooks,
79
enableProfilerTimer,
80
enableSchedulerTracing,
81
enableSuspenseServerRenderer,
@@ -837,11 +838,13 @@ function updateProfiler(
838
if (enableProfilerTimer) {
839
workInProgress.flags |= Update;
840
840
- // Reset effect durations for the next eventual effect phase.
841
- // These are reset during render to allow the DevTools commit hook a chance to read them,
842
- const stateNode = workInProgress.stateNode;
843
- stateNode.effectDuration = 0;
844
- stateNode.passiveEffectDuration = 0;
841
+ if (enableProfilerCommitHooks) {
842
+ // Reset effect durations for the next eventual effect phase.
843
+ // These are reset during render to allow the DevTools commit hook a chance to read them,
844
+ const stateNode = workInProgress.stateNode;
845
+ stateNode.effectDuration = 0;
846
+ stateNode.passiveEffectDuration = 0;
847
+ }
848
}
849
const nextProps = workInProgress.pendingProps;
850
const nextChildren = nextProps.children;
@@ -3320,11 +3323,13 @@ function beginWork(
3323
workInProgress.flags |= Update;
3324
}
3325
3323
- // Reset effect durations for the next eventual effect phase.
3324
- // These are reset during render to allow the DevTools commit hook a chance to read them,
3325
- const stateNode = workInProgress.stateNode;
3326
- stateNode.effectDuration = 0;
3327
- stateNode.passiveEffectDuration = 0;
3326
+ if (enableProfilerCommitHooks) {
3327
+ // Reset effect durations for the next eventual effect phase.
3328
+ // These are reset during render to allow the DevTools commit hook a chance to read them,
3329
+ const stateNode = workInProgress.stateNode;
3330
+ stateNode.effectDuration = 0;
3331
+ stateNode.passiveEffectDuration = 0;
3332
+ }
3333
}
3334
break;
3335
case SuspenseComponent: {
packages/react-reconciler/src/ReactFiberBeginWork.old.js
+15
-10
@@ -75,6 +75,7 @@ import {
75
debugRenderPhaseSideEffectsForStrictMode,
76
disableLegacyContext,
77
disableModulePatternComponents,
78
+ enableProfilerCommitHooks,
79
enableProfilerTimer,
80
enableSchedulerTracing,
81
enableSuspenseServerRenderer,
@@ -837,11 +838,13 @@ function updateProfiler(
838
if (enableProfilerTimer) {
839
workInProgress.flags |= Update;
840
840
- // Reset effect durations for the next eventual effect phase.
841
- // These are reset during render to allow the DevTools commit hook a chance to read them,
842
- const stateNode = workInProgress.stateNode;
843
- stateNode.effectDuration = 0;
844
- stateNode.passiveEffectDuration = 0;
841
+ if (enableProfilerCommitHooks) {
842
+ // Reset effect durations for the next eventual effect phase.
843
+ // These are reset during render to allow the DevTools commit hook a chance to read them,
844
+ const stateNode = workInProgress.stateNode;
845
+ stateNode.effectDuration = 0;
846
+ stateNode.passiveEffectDuration = 0;
847
+ }
848
}
849
const nextProps = workInProgress.pendingProps;
850
const nextChildren = nextProps.children;
@@ -3320,11 +3323,13 @@ function beginWork(
3323
workInProgress.flags |= Update;
3324
}
3325
3323
- // Reset effect durations for the next eventual effect phase.
3324
- // These are reset during render to allow the DevTools commit hook a chance to read them,
3325
- const stateNode = workInProgress.stateNode;
3326
- stateNode.effectDuration = 0;
3327
- stateNode.passiveEffectDuration = 0;
3326
+ if (enableProfilerCommitHooks) {
3327
+ // Reset effect durations for the next eventual effect phase.
3328
+ // These are reset during render to allow the DevTools commit hook a chance to read them,
3329
+ const stateNode = workInProgress.stateNode;
3330
+ stateNode.effectDuration = 0;
3331
+ stateNode.passiveEffectDuration = 0;
3332
+ }
3333
}
3334
break;
3335
case SuspenseComponent: {
packages/react-reconciler/src/ReactFiberCommitWork.new.js
+20
-10
@@ -578,11 +578,16 @@ export function commitPassiveEffectDurations(
578
// Bubble times to the next nearest ancestor Profiler.
579
// After we process that Profiler, we'll bubble further up.
580
let parentFiber = finishedWork.return;
581
- while (parentFiber !== null) {
582
- if (parentFiber.tag === Profiler) {
583
- const parentStateNode = parentFiber.stateNode;
584
- parentStateNode.passiveEffectDuration += passiveEffectDuration;
585
- break;
581
+ outer: while (parentFiber !== null) {
582
+ switch (parentFiber.tag) {
583
+ case HostRoot:
584
+ const root = parentFiber.stateNode;
585
+ root.passiveEffectDuration += passiveEffectDuration;
586
+ break outer;
587
+ case Profiler:
588
+ const parentStateNode = parentFiber.stateNode;
589
+ parentStateNode.passiveEffectDuration += passiveEffectDuration;
590
+ break outer;
591
}
592
parentFiber = parentFiber.return;
593
}
@@ -885,11 +890,16 @@ function commitLayoutEffectOnFiber(
890
// Propagate layout effect durations to the next nearest Profiler ancestor.
891
// Do not reset these values until the next render so DevTools has a chance to read them first.
892
let parentFiber = finishedWork.return;
888
- while (parentFiber !== null) {
889
- if (parentFiber.tag === Profiler) {
890
- const parentStateNode = parentFiber.stateNode;
891
- parentStateNode.effectDuration += effectDuration;
892
- break;
893
+ outer: while (parentFiber !== null) {
894
+ switch (parentFiber.tag) {
895
+ case HostRoot:
896
+ const root = parentFiber.stateNode;
897
+ root.effectDuration += effectDuration;
898
+ break outer;
899
+ case Profiler:
900
+ const parentStateNode = parentFiber.stateNode;
901
+ parentStateNode.effectDuration += effectDuration;
902
+ break outer;
903
}
904
parentFiber = parentFiber.return;
905
}
packages/react-reconciler/src/ReactFiberCommitWork.old.js
+20
-10
@@ -578,11 +578,16 @@ export function commitPassiveEffectDurations(
578
// Bubble times to the next nearest ancestor Profiler.
579
// After we process that Profiler, we'll bubble further up.
580
let parentFiber = finishedWork.return;
581
- while (parentFiber !== null) {
582
- if (parentFiber.tag === Profiler) {
583
- const parentStateNode = parentFiber.stateNode;
584
- parentStateNode.passiveEffectDuration += passiveEffectDuration;
585
- break;
581
+ outer: while (parentFiber !== null) {
582
+ switch (parentFiber.tag) {
583
+ case HostRoot:
584
+ const root = parentFiber.stateNode;
585
+ root.passiveEffectDuration += passiveEffectDuration;
586
+ break outer;
587
+ case Profiler:
588
+ const parentStateNode = parentFiber.stateNode;
589
+ parentStateNode.passiveEffectDuration += passiveEffectDuration;
590
+ break outer;
591
}
592
parentFiber = parentFiber.return;
593
}
@@ -885,11 +890,16 @@ function commitLayoutEffectOnFiber(
890
// Propagate layout effect durations to the next nearest Profiler ancestor.
891
// Do not reset these values until the next render so DevTools has a chance to read them first.
892
let parentFiber = finishedWork.return;
888
- while (parentFiber !== null) {
889
- if (parentFiber.tag === Profiler) {
890
- const parentStateNode = parentFiber.stateNode;
891
- parentStateNode.effectDuration += effectDuration;
892
- break;
893
+ outer: while (parentFiber !== null) {
894
+ switch (parentFiber.tag) {
895
+ case HostRoot:
896
+ const root = parentFiber.stateNode;
897
+ root.effectDuration += effectDuration;
898
+ break outer;
899
+ case Profiler:
900
+ const parentStateNode = parentFiber.stateNode;
901
+ parentStateNode.effectDuration += effectDuration;
902
+ break outer;
903
}
904
parentFiber = parentFiber.return;
905
}
packages/react-reconciler/src/ReactFiberRoot.new.js
+7
@@ -22,6 +22,8 @@ import {
22
enableSchedulerTracing,
23
enableSuspenseCallback,
24
enableCache,
25
+ enableProfilerCommitHooks,
26
+ enableProfilerTimer,
27
} from 'shared/ReactFeatureFlags';
28
import {unstable_getThreadID} from 'scheduler/tracing';
29
import {initializeUpdateQueue} from './ReactUpdateQueue.new';
@@ -71,6 +73,11 @@ function FiberRootNode(containerInfo, tag, hydrate) {
73
this.hydrationCallbacks = null;
74
}
75
76
+ if (enableProfilerTimer && enableProfilerCommitHooks) {
77
+ this.effectDuration = 0;
78
+ this.passiveEffectDuration = 0;
79
+ }
80
+
81
if (__DEV__) {
82
switch (tag) {
83
case ConcurrentRoot:
packages/react-reconciler/src/ReactFiberRoot.old.js
+7
@@ -22,6 +22,8 @@ import {
22
enableSchedulerTracing,
23
enableSuspenseCallback,
24
enableCache,
25
+ enableProfilerCommitHooks,
26
+ enableProfilerTimer,
27
} from 'shared/ReactFeatureFlags';
28
import {unstable_getThreadID} from 'scheduler/tracing';
29
import {initializeUpdateQueue} from './ReactUpdateQueue.old';
@@ -71,6 +73,11 @@ function FiberRootNode(containerInfo, tag, hydrate) {
73
this.hydrationCallbacks = null;
74
}
75
76
+ if (enableProfilerTimer && enableProfilerCommitHooks) {
77
+ this.effectDuration = 0;
78
+ this.passiveEffectDuration = 0;
79
+ }
80
+
81
if (__DEV__) {
82
switch (tag) {
83
case ConcurrentRoot:
packages/react-reconciler/src/ReactProfilerTimer.new.js
+30
-16
@@ -14,7 +14,7 @@ import {
14
enableProfilerNestedUpdatePhase,
15
enableProfilerTimer,
16
} from 'shared/ReactFeatureFlags';
17
-import {Profiler} from './ReactWorkTags';
17
+import {HostRoot, Profiler} from './ReactWorkTags';
18
19
// Intentionally not named imports because Rollup would use dynamic dispatch for
20
// CommonJS interop named imports.
@@ -140,13 +140,19 @@ function recordLayoutEffectDuration(fiber: Fiber): void {
140
141
layoutEffectStartTime = -1;
142
143
- // Store duration on the next nearest Profiler ancestor.
143
+ // Store duration on the next nearest Profiler ancestor
144
+ // Or the root (for the DevTools Profiler to read)
145
let parentFiber = fiber.return;
146
while (parentFiber !== null) {
146
- if (parentFiber.tag === Profiler) {
147
- const parentStateNode = parentFiber.stateNode;
148
- parentStateNode.effectDuration += elapsedTime;
149
- break;
147
+ switch (parentFiber.tag) {
148
+ case HostRoot:
149
+ const root = parentFiber.stateNode;
150
+ root.effectDuration += elapsedTime;
151
+ return;
152
+ case Profiler:
153
+ const parentStateNode = parentFiber.stateNode;
154
+ parentStateNode.effectDuration += elapsedTime;
155
+ return;
156
}
157
parentFiber = parentFiber.return;
158
}
@@ -163,18 +169,26 @@ function recordPassiveEffectDuration(fiber: Fiber): void {
169
170
passiveEffectStartTime = -1;
171
166
- // Store duration on the next nearest Profiler ancestor.
172
+ // Store duration on the next nearest Profiler ancestor
173
+ // Or the root (for the DevTools Profiler to read)
174
let parentFiber = fiber.return;
175
while (parentFiber !== null) {
169
- if (parentFiber.tag === Profiler) {
170
- const parentStateNode = parentFiber.stateNode;
171
- if (parentStateNode !== null) {
172
- // Detached fibers have their state node cleared out.
173
- // In this case, the return pointer is also cleared out,
174
- // so we won't be able to report the time spent in this Profiler's subtree.
175
- parentStateNode.passiveEffectDuration += elapsedTime;
176
- }
177
- break;
176
+ switch (parentFiber.tag) {
177
+ case HostRoot:
178
+ const root = parentFiber.stateNode;
179
+ if (root !== null) {
180
+ root.passiveEffectDuration += elapsedTime;
181
+ }
182
+ return;
183
+ case Profiler:
184
+ const parentStateNode = parentFiber.stateNode;
185
+ if (parentStateNode !== null) {
186
+ // Detached fibers have their state node cleared out.
187
+ // In this case, the return pointer is also cleared out,
188
+ // so we won't be able to report the time spent in this Profiler's subtree.
189
+ parentStateNode.passiveEffectDuration += elapsedTime;
190
+ }
191
+ return;
192
}
193
parentFiber = parentFiber.return;
194
}
packages/react-reconciler/src/ReactProfilerTimer.old.js
+30
-16
@@ -14,7 +14,7 @@ import {
14
enableProfilerNestedUpdatePhase,
15
enableProfilerTimer,
16
} from 'shared/ReactFeatureFlags';
17
-import {Profiler} from './ReactWorkTags';
17
+import {HostRoot, Profiler} from './ReactWorkTags';
18
19
// Intentionally not named imports because Rollup would use dynamic dispatch for
20
// CommonJS interop named imports.
@@ -140,13 +140,19 @@ function recordLayoutEffectDuration(fiber: Fiber): void {
140
141
layoutEffectStartTime = -1;
142
143
- // Store duration on the next nearest Profiler ancestor.
143
+ // Store duration on the next nearest Profiler ancestor
144
+ // Or the root (for the DevTools Profiler to read)
145
let parentFiber = fiber.return;
146
while (parentFiber !== null) {
146
- if (parentFiber.tag === Profiler) {
147
- const parentStateNode = parentFiber.stateNode;
148
- parentStateNode.effectDuration += elapsedTime;
149
- break;
147
+ switch (parentFiber.tag) {
148
+ case HostRoot:
149
+ const root = parentFiber.stateNode;
150
+ root.effectDuration += elapsedTime;
151
+ return;
152
+ case Profiler:
153
+ const parentStateNode = parentFiber.stateNode;
154
+ parentStateNode.effectDuration += elapsedTime;
155
+ return;
156
}
157
parentFiber = parentFiber.return;
158
}
@@ -163,18 +169,26 @@ function recordPassiveEffectDuration(fiber: Fiber): void {
169
170
passiveEffectStartTime = -1;
171
166
- // Store duration on the next nearest Profiler ancestor.
172
+ // Store duration on the next nearest Profiler ancestor
173
+ // Or the root (for the DevTools Profiler to read)
174
let parentFiber = fiber.return;
175
while (parentFiber !== null) {
169
- if (parentFiber.tag === Profiler) {
170
- const parentStateNode = parentFiber.stateNode;
171
- if (parentStateNode !== null) {
172
- // Detached fibers have their state node cleared out.
173
- // In this case, the return pointer is also cleared out,
174
- // so we won't be able to report the time spent in this Profiler's subtree.
175
- parentStateNode.passiveEffectDuration += elapsedTime;
176
- }
177
- break;
176
+ switch (parentFiber.tag) {
177
+ case HostRoot:
178
+ const root = parentFiber.stateNode;
179
+ if (root !== null) {
180
+ root.passiveEffectDuration += elapsedTime;
181
+ }
182
+ return;
183
+ case Profiler:
184
+ const parentStateNode = parentFiber.stateNode;
185
+ if (parentStateNode !== null) {
186
+ // Detached fibers have their state node cleared out.
187
+ // In this case, the return pointer is also cleared out,
188
+ // so we won't be able to report the time spent in this Profiler's subtree.
189
+ parentStateNode.passiveEffectDuration += elapsedTime;
190
+ }
191
+ return;
192
}
193
parentFiber = parentFiber.return;
194
}