Skip to content

Commit c7c0203

Browse files
author
Brian Vaughn
committed
Bubble profiler durations to parent (rather than walking children)
Note this commit fails 5 tests. I am pushing it purely for sharing purposes.
1 parent a789939 commit c7c0203

File tree

6 files changed

+125
-166
lines changed

6 files changed

+125
-166
lines changed

packages/react-reconciler/src/ReactFiber.new.js

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,10 @@ export function createWorkInProgress(current: Fiber, pendingProps: any): Fiber {
293293
// But works for yielding (the common case) and should support resuming.
294294
workInProgress.actualDuration = 0;
295295
workInProgress.actualStartTime = -1;
296+
297+
// Reset treeBaseDuration when cloning.
298+
// As each child completes rendering, its base durations will bubble up to the parent.
299+
workInProgress.treeBaseDuration = 0;
296300
}
297301
}
298302

@@ -323,11 +327,6 @@ export function createWorkInProgress(current: Fiber, pendingProps: any): Fiber {
323327
workInProgress.index = current.index;
324328
workInProgress.ref = current.ref;
325329

326-
if (enableProfilerTimer) {
327-
workInProgress.selfBaseDuration = current.selfBaseDuration;
328-
workInProgress.treeBaseDuration = current.treeBaseDuration;
329-
}
330-
331330
if (__DEV__) {
332331
workInProgress._debugNeedsRemount = current._debugNeedsRemount;
333332
switch (workInProgress.tag) {
@@ -381,8 +380,8 @@ export function resetWorkInProgress(workInProgress: Fiber, renderLanes: Lanes) {
381380
workInProgress.stateNode = null;
382381

383382
if (enableProfilerTimer) {
384-
// Note: We don't reset the actualTime counts. It's useful to accumulate
385-
// actual time across multiple render passes.
383+
// Note: We don't reset the actualTime counts.
384+
// It's useful to accumulate actual time across multiple render passes.
386385
workInProgress.selfBaseDuration = 0;
387386
workInProgress.treeBaseDuration = 0;
388387
}
@@ -412,10 +411,10 @@ export function resetWorkInProgress(workInProgress: Fiber, renderLanes: Lanes) {
412411
};
413412

414413
if (enableProfilerTimer) {
415-
// Note: We don't reset the actualTime counts. It's useful to accumulate
416-
// actual time across multiple render passes.
417-
workInProgress.selfBaseDuration = current.selfBaseDuration;
418-
workInProgress.treeBaseDuration = current.treeBaseDuration;
414+
// Note: We don't reset the actualTime counts.
415+
// It's useful to accumulate actual time across multiple render passes.
416+
workInProgress.selfBaseDuration = 0;
417+
workInProgress.treeBaseDuration = 0;
419418
}
420419
}
421420

packages/react-reconciler/src/ReactFiberBeginWork.new.js

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1714,6 +1714,15 @@ function updateSuspenseComponent(current, workInProgress, renderLanes) {
17141714
renderLanes,
17151715
)
17161716
) {
1717+
if (enableProfilerTimer) {
1718+
if ((workInProgress.mode & ProfileMode) !== NoMode) {
1719+
if (current !== null) {
1720+
// TODO (effects) Document
1721+
workInProgress.actualDuration = current.actualDuration;
1722+
}
1723+
}
1724+
}
1725+
17171726
// Something in this boundary's subtree already suspended. Switch to
17181727
// rendering the fallback children.
17191728
showFallback = true;
@@ -1990,10 +1999,9 @@ function mountSuspenseFallbackChildren(
19901999
primaryChildFragment.pendingProps = primaryChildProps;
19912000

19922001
if (enableProfilerTimer && workInProgress.mode & ProfileMode) {
1993-
// Reset the durations from the first pass so they aren't included in the
1994-
// final amounts. This seems counterintuitive, since we're intentionally
1995-
// not measuring part of the render phase, but this makes it match what we
1996-
// do in Concurrent Mode.
2002+
// Reset the durations from the first pass so they aren't included in the final amounts.
2003+
// This seems counterintuitive, since we're intentionally not measuring part of the render phase,
2004+
// but this makes it match what we do in Concurrent Mode.
19972005
primaryChildFragment.actualDuration = 0;
19982006
primaryChildFragment.actualStartTime = -1;
19992007
primaryChildFragment.selfBaseDuration = 0;
@@ -2111,10 +2119,9 @@ function updateSuspenseFallbackChildren(
21112119
primaryChildFragment.pendingProps = primaryChildProps;
21122120

21132121
if (enableProfilerTimer && workInProgress.mode & ProfileMode) {
2114-
// Reset the durations from the first pass so they aren't included in the
2115-
// final amounts. This seems counterintuitive, since we're intentionally
2116-
// not measuring part of the render phase, but this makes it match what we
2117-
// do in Concurrent Mode.
2122+
// Reset the durations from the first pass so they aren't included in the final amounts.
2123+
// This seems counterintuitive, since we're intentionally not measuring part of the render phase,
2124+
// but this makes it match what we do in Concurrent Mode.
21182125
primaryChildFragment.actualDuration = 0;
21192126
primaryChildFragment.actualStartTime = -1;
21202127
primaryChildFragment.selfBaseDuration =
@@ -2970,6 +2977,13 @@ function bailoutOnAlreadyFinishedWork(
29702977

29712978
// Check if the children have any pending work.
29722979
if (!includesSomeLane(renderLanes, workInProgress.childLanes)) {
2980+
if (enableProfilerTimer) {
2981+
if (current !== null) {
2982+
workInProgress.treeBaseDuration = current.treeBaseDuration;
2983+
workInProgress.selfBaseDuration = 0;
2984+
}
2985+
}
2986+
29732987
// The children don't have any work either. We can skip them.
29742988
// TODO: Once we add back resuming, we should check if the children are
29752989
// a work-in-progress set. If so, we need to transfer their effects.

packages/react-reconciler/src/ReactFiberCompleteWork.new.js

Lines changed: 78 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ import {
7171
DidCapture,
7272
Snapshot,
7373
MutationMask,
74+
PerformedWork,
7475
StaticMask,
7576
} from './ReactFiberFlags';
7677
import invariant from 'shared/invariant';
@@ -155,7 +156,10 @@ import {
155156
} from './ReactFiberLane';
156157
import {resetChildFibers} from './ReactChildFiber.new';
157158
import {createScopeInstance} from './ReactFiberScope.new';
158-
import {transferActualDuration} from './ReactProfilerTimer.new';
159+
import {
160+
stopProfilerTimerIfRunning,
161+
stopProfilerTimerIfRunningAndRecordDelta,
162+
} from './ReactProfilerTimer.new';
159163

160164
function markUpdate(workInProgress: Fiber) {
161165
// Tag the fiber with an update effect. This turns a Placement into
@@ -681,112 +685,99 @@ function cutOffTailIfNeeded(
681685
}
682686
}
683687

684-
function bubbleProperties(completedWork: Fiber) {
685-
const didBailout =
686-
completedWork.alternate !== null &&
687-
completedWork.alternate.child === completedWork.child;
688+
export function bubbleProfilerDurationsAfterError(erroredWork: Fiber): void {
689+
if (enableProfilerTimer) {
690+
if ((erroredWork.mode & ProfileMode) !== NoMode) {
691+
const parent = erroredWork.return;
692+
if (parent !== null) {
693+
// TODO (effects) Document
694+
parent.actualDuration += erroredWork.actualDuration;
688695

689-
let newChildLanes = NoLanes;
690-
let subtreeFlags = NoFlags;
696+
// TODO (effects) Document
697+
parent.treeBaseDuration = 0;
698+
}
699+
}
700+
}
701+
}
691702

692-
if (!didBailout) {
693-
// Bubble up the earliest expiration time.
694-
if (enableProfilerTimer && (completedWork.mode & ProfileMode) !== NoMode) {
695-
// In profiling mode, resetChildExpirationTime is also used to reset
696-
// profiler durations.
697-
let actualDuration = completedWork.actualDuration;
698-
let treeBaseDuration = ((completedWork.selfBaseDuration: any): number);
699-
700-
let child = completedWork.child;
701-
while (child !== null) {
702-
newChildLanes = mergeLanes(
703-
newChildLanes,
704-
mergeLanes(child.lanes, child.childLanes),
705-
);
703+
// TODO (effects) Temorary method; replace with bubblePropertiesToParent
704+
function bubbleProperties(completedWork: Fiber): void {
705+
bubblePropertiesFromChildren(completedWork);
706+
bubblePropertiesToParent(completedWork);
707+
}
706708

707-
subtreeFlags |= child.subtreeFlags;
708-
subtreeFlags |= child.flags;
709+
function bubblePropertiesToParent(completedWork: Fiber): void {
710+
const parent = completedWork.return;
711+
if (parent !== null) {
712+
const didBailout = (completeWork.flags & PerformedWork) !== NoFlags;
713+
if (!didBailout) {
714+
if (enableProfilerTimer) {
715+
if ((completedWork.mode & ProfileMode) !== NoMode) {
716+
stopProfilerTimerIfRunningAndRecordDelta(completedWork, true);
709717

710-
// When a fiber is cloned, its actualDuration is reset to 0. This value will
711-
// only be updated if work is done on the fiber (i.e. it doesn't bailout).
712-
// When work is done, it should bubble to the parent's actualDuration. If
713-
// the fiber has not been cloned though, (meaning no work was done), then
714-
// this value will reflect the amount of time spent working on a previous
715-
// render. In that case it should not bubble. We determine whether it was
716-
// cloned by comparing the child pointer.
717-
actualDuration += child.actualDuration;
718+
// At this point child base durations have already bubbled up to treeBaseDuration.
719+
// Add our own base duration before bubbling further to the parent Fiber.
720+
completedWork.treeBaseDuration += completedWork.selfBaseDuration;
718721

719-
treeBaseDuration += child.treeBaseDuration;
720-
child = child.sibling;
722+
// Bubble base durations to the parent.
723+
parent.actualDuration += completedWork.actualDuration;
724+
parent.treeBaseDuration += completedWork.treeBaseDuration;
725+
}
721726
}
722-
723-
completedWork.actualDuration = actualDuration;
724-
completedWork.treeBaseDuration = treeBaseDuration;
725727
} else {
726-
let child = completedWork.child;
727-
while (child !== null) {
728-
newChildLanes = mergeLanes(
729-
newChildLanes,
730-
mergeLanes(child.lanes, child.childLanes),
731-
);
732-
733-
subtreeFlags |= child.subtreeFlags;
734-
subtreeFlags |= child.flags;
728+
if (enableProfilerTimer) {
729+
if ((completedWork.mode & ProfileMode) !== NoMode) {
730+
stopProfilerTimerIfRunning(completedWork);
735731

736-
child = child.sibling;
732+
parent.treeBaseDuration += completedWork.treeBaseDuration;
733+
}
737734
}
738735
}
736+
}
737+
}
739738

740-
completedWork.subtreeFlags |= subtreeFlags;
741-
} else {
742-
// Bubble up the earliest expiration time.
743-
if (enableProfilerTimer && (completedWork.mode & ProfileMode) !== NoMode) {
744-
// In profiling mode, resetChildExpirationTime is also used to reset
745-
// profiler durations.
746-
let treeBaseDuration = ((completedWork.selfBaseDuration: any): number);
747-
748-
let child = completedWork.child;
749-
while (child !== null) {
750-
newChildLanes = mergeLanes(
751-
newChildLanes,
752-
mergeLanes(child.lanes, child.childLanes),
753-
);
739+
// TODO (effects) Move everything in this method into bubblePropertiesToParent
740+
function bubblePropertiesFromChildren(completedWork: Fiber): void {
741+
let newChildLanes = NoLanes;
742+
let subtreeFlags = NoFlags;
754743

755-
// "Static" flags share the lifetime of the fiber/hook they belong to,
756-
// so we should bubble those up even during a bailout. All the other
757-
// flags have a lifetime only of a single render + commit, so we should
758-
// ignore them.
759-
subtreeFlags |= child.subtreeFlags & StaticMask;
760-
subtreeFlags |= child.flags & StaticMask;
744+
const didBailout =
745+
completedWork.alternate !== null &&
746+
completedWork.alternate.child === completedWork.child;
747+
if (!didBailout) {
748+
let child = completedWork.child;
749+
while (child !== null) {
750+
newChildLanes = mergeLanes(
751+
newChildLanes,
752+
mergeLanes(child.lanes, child.childLanes),
753+
);
761754

762-
treeBaseDuration += child.treeBaseDuration;
763-
child = child.sibling;
764-
}
755+
subtreeFlags |= child.subtreeFlags;
756+
subtreeFlags |= child.flags;
765757

766-
completedWork.treeBaseDuration = treeBaseDuration;
767-
} else {
768-
let child = completedWork.child;
769-
while (child !== null) {
770-
newChildLanes = mergeLanes(
771-
newChildLanes,
772-
mergeLanes(child.lanes, child.childLanes),
773-
);
758+
child = child.sibling;
759+
}
760+
} else {
761+
let child = completedWork.child;
762+
while (child !== null) {
763+
newChildLanes = mergeLanes(
764+
newChildLanes,
765+
mergeLanes(child.lanes, child.childLanes),
766+
);
774767

775-
// "Static" flags share the lifetime of the fiber/hook they belong to,
776-
// so we should bubble those up even during a bailout. All the other
777-
// flags have a lifetime only of a single render + commit, so we should
778-
// ignore them.
779-
subtreeFlags |= child.subtreeFlags & StaticMask;
780-
subtreeFlags |= child.flags & StaticMask;
768+
// "Static" flags share the lifetime of the fiber/hook they belong to,
769+
// so we should bubble those up even during a bailout. All the other
770+
// flags have a lifetime only of a single render + commit, so we should
771+
// ignore them.
772+
subtreeFlags |= child.subtreeFlags & StaticMask;
773+
subtreeFlags |= child.flags & StaticMask;
781774

782-
child = child.sibling;
783-
}
775+
child = child.sibling;
784776
}
785-
786-
completedWork.subtreeFlags |= subtreeFlags;
787777
}
788778

789779
completedWork.childLanes = newChildLanes;
780+
completedWork.subtreeFlags |= subtreeFlags;
790781
}
791782

792783
function completeWork(
@@ -1036,12 +1027,6 @@ function completeWork(
10361027
// Something suspended. Re-render with the fallback children.
10371028
workInProgress.lanes = renderLanes;
10381029
// Do not reset the effect list.
1039-
if (
1040-
enableProfilerTimer &&
1041-
(workInProgress.mode & ProfileMode) !== NoMode
1042-
) {
1043-
transferActualDuration(workInProgress);
1044-
}
10451030
return workInProgress;
10461031
}
10471032

packages/react-reconciler/src/ReactFiberUnwindWork.new.js

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,7 @@ import {
2424
LegacyHiddenComponent,
2525
} from './ReactWorkTags';
2626
import {DidCapture, NoFlags, ShouldCapture} from './ReactFiberFlags';
27-
import {NoMode, ProfileMode} from './ReactTypeOfMode';
28-
import {
29-
enableSuspenseServerRenderer,
30-
enableProfilerTimer,
31-
} from 'shared/ReactFeatureFlags';
27+
import {enableSuspenseServerRenderer} from 'shared/ReactFeatureFlags';
3228

3329
import {popHostContainer, popHostContext} from './ReactFiberHostContext.new';
3430
import {popSuspenseContext} from './ReactFiberSuspenseContext.new';
@@ -40,7 +36,6 @@ import {
4036
} from './ReactFiberContext.new';
4137
import {popProvider} from './ReactFiberNewContext.new';
4238
import {popRenderLanes} from './ReactFiberWorkLoop.new';
43-
import {transferActualDuration} from './ReactProfilerTimer.new';
4439

4540
import invariant from 'shared/invariant';
4641

@@ -54,12 +49,6 @@ function unwindWork(workInProgress: Fiber, renderLanes: Lanes) {
5449
const flags = workInProgress.flags;
5550
if (flags & ShouldCapture) {
5651
workInProgress.flags = (flags & ~ShouldCapture) | DidCapture;
57-
if (
58-
enableProfilerTimer &&
59-
(workInProgress.mode & ProfileMode) !== NoMode
60-
) {
61-
transferActualDuration(workInProgress);
62-
}
6352
return workInProgress;
6453
}
6554
return null;
@@ -100,12 +89,6 @@ function unwindWork(workInProgress: Fiber, renderLanes: Lanes) {
10089
if (flags & ShouldCapture) {
10190
workInProgress.flags = (flags & ~ShouldCapture) | DidCapture;
10291
// Captured a suspense effect. Re-render the boundary.
103-
if (
104-
enableProfilerTimer &&
105-
(workInProgress.mode & ProfileMode) !== NoMode
106-
) {
107-
transferActualDuration(workInProgress);
108-
}
10992
return workInProgress;
11093
}
11194
return null;

0 commit comments

Comments
 (0)