@@ -112,15 +112,9 @@ import {
112112import { popProvider , resetContextDependences } from './ReactFiberNewContext' ;
113113import { popHostContext , popHostContainer } from './ReactFiberHostContext' ;
114114import {
115- checkActualRenderTimeStackEmpty ,
116- pauseActualRenderTimerIfRunning ,
117115 recordCommitTime ,
118- recordElapsedActualRenderTime ,
119- recordElapsedBaseRenderTimeIfRunning ,
120- resetActualRenderTimerStackAfterFatalErrorInDev ,
121- resumeActualRenderTimerIfPaused ,
122- startBaseRenderTimer ,
123- stopBaseRenderTimerIfRunning ,
116+ startProfilerTimer ,
117+ stopProfilerTimerIfRunningAndRecordDelta ,
124118} from './ReactProfilerTimer' ;
125119import {
126120 checkThatStackIsEmpty ,
@@ -312,15 +306,6 @@ if (__DEV__ && replayFailedUnitOfWorkWithInvokeGuardedCallback) {
312306 originalReplayError = null ;
313307 if ( hasCaughtError ( ) ) {
314308 clearCaughtError ( ) ;
315-
316- if ( enableProfilerTimer ) {
317- if ( failedUnitOfWork . mode & ProfileMode ) {
318- recordElapsedActualRenderTime ( failedUnitOfWork ) ;
319- }
320-
321- // Stop "base" render timer again (after the re-thrown error).
322- stopBaseRenderTimerIfRunning ( ) ;
323- }
324309 } else {
325310 // If the begin phase did not fail the second time, set this pointer
326311 // back to the original value.
@@ -336,12 +321,6 @@ function resetStack() {
336321 if ( nextUnitOfWork !== null ) {
337322 let interruptedWork = nextUnitOfWork . return ;
338323 while ( interruptedWork !== null ) {
339- if ( enableProfilerTimer ) {
340- if ( interruptedWork . mode & ProfileMode ) {
341- // Resume in case we're picking up on work that was paused.
342- resumeActualRenderTimerIfPaused ( false ) ;
343- }
344- }
345324 unwindInterruptedWork ( interruptedWork ) ;
346325 interruptedWork = interruptedWork . return ;
347326 }
@@ -691,17 +670,6 @@ function commitRoot(root: FiberRoot, finishedWork: Fiber): void {
691670 }
692671 }
693672
694- if ( enableProfilerTimer ) {
695- if ( __DEV__ ) {
696- if ( nextRoot === null ) {
697- // Only check this stack once we're done processing async work.
698- // This prevents a false positive that occurs after a batched commit,
699- // If there was in-progress async work before the commit.
700- checkActualRenderTimeStackEmpty ( ) ;
701- }
702- }
703- }
704-
705673 isCommitting = false ;
706674 isWorking = false ;
707675 stopCommitLifeCyclesTimer ( ) ;
@@ -741,9 +709,22 @@ function resetChildExpirationTime(
741709
742710 // Bubble up the earliest expiration time.
743711 if ( enableProfilerTimer && workInProgress . mode & ProfileMode ) {
744- // We're in profiling mode. Let's use this same traversal to update the
745- // "base" render times.
712+ // We're in profiling mode.
713+ // Let's use this same traversal to update the render durations.
714+ let actualDuration = workInProgress . actualDuration ;
746715 let treeBaseDuration = workInProgress . selfBaseDuration ;
716+
717+ // When a fiber is cloned, its actualDuration is reset to 0.
718+ // This value will only be updated if work is done on the fiber (i.e. it doesn't bailout).
719+ // When work is done, it should bubble to the parent's actualDuration.
720+ // If the fiber has not been cloned though, (meaning no work was done),
721+ // Then this value will reflect the amount of time spent working on a previous render.
722+ // In that case it should not bubble.
723+ // We determine whether it was cloned by comparing the child pointer.
724+ const shouldBubbleActualDurations =
725+ workInProgress . alternate === null ||
726+ workInProgress . child !== workInProgress . alternate . child ;
727+
747728 let child = workInProgress . child ;
748729 while ( child !== null ) {
749730 const childUpdateExpirationTime = child . expirationTime ;
@@ -762,9 +743,13 @@ function resetChildExpirationTime(
762743 ) {
763744 newChildExpirationTime = childChildExpirationTime ;
764745 }
746+ if ( shouldBubbleActualDurations ) {
747+ actualDuration += child . actualDuration ;
748+ }
765749 treeBaseDuration += child . treeBaseDuration ;
766750 child = child . sibling ;
767751 }
752+ workInProgress . actualDuration = actualDuration ;
768753 workInProgress . treeBaseDuration = treeBaseDuration ;
769754 } else {
770755 let child = workInProgress . child ;
@@ -811,11 +796,28 @@ function completeUnitOfWork(workInProgress: Fiber): Fiber | null {
811796
812797 if ( ( workInProgress . effectTag & Incomplete ) === NoEffect ) {
813798 // This fiber completed.
814- nextUnitOfWork = completeWork (
815- current ,
816- workInProgress ,
817- nextRenderExpirationTime ,
818- ) ;
799+ if ( enableProfilerTimer ) {
800+ if ( workInProgress . mode & ProfileMode ) {
801+ startProfilerTimer ( workInProgress ) ;
802+ }
803+
804+ nextUnitOfWork = completeWork (
805+ current ,
806+ workInProgress ,
807+ nextRenderExpirationTime ,
808+ ) ;
809+
810+ if ( workInProgress . mode & ProfileMode ) {
811+ // Update render duration assuming we didn't error.
812+ stopProfilerTimerIfRunningAndRecordDelta ( workInProgress , false ) ;
813+ }
814+ } else {
815+ nextUnitOfWork = completeWork (
816+ current ,
817+ workInProgress ,
818+ nextRenderExpirationTime ,
819+ ) ;
820+ }
819821 let next = nextUnitOfWork ;
820822 stopWorkTimer ( workInProgress ) ;
821823 resetChildExpirationTime ( workInProgress , nextRenderExpirationTime ) ;
@@ -886,6 +888,11 @@ function completeUnitOfWork(workInProgress: Fiber): Fiber | null {
886888 return null ;
887889 }
888890 } else {
891+ if ( workInProgress . mode & ProfileMode ) {
892+ // Record the render duration for the fiber that errored.
893+ stopProfilerTimerIfRunningAndRecordDelta ( workInProgress , false ) ;
894+ }
895+
889896 // This fiber did not complete because something threw. Pop values off
890897 // the stack without entering the complete phase. If this is a boundary,
891898 // capture values if possible.
@@ -908,6 +915,19 @@ function completeUnitOfWork(workInProgress: Fiber): Fiber | null {
908915 ReactFiberInstrumentation . debugTool . onCompleteWork ( workInProgress ) ;
909916 }
910917
918+ if ( enableProfilerTimer ) {
919+ // Include the time spent working on failed children before continuing.
920+ if ( next . mode & ProfileMode ) {
921+ let actualDuration = next . actualDuration ;
922+ let child = next . child ;
923+ while ( child !== null ) {
924+ actualDuration += child . actualDuration ;
925+ child = child . sibling ;
926+ }
927+ next . actualDuration = actualDuration ;
928+ }
929+ }
930+
911931 // If completing this work spawned new work, do that next. We'll come
912932 // back here again.
913933 // Since we're restarting, remove anything that is not a host effect
@@ -968,15 +988,14 @@ function performUnitOfWork(workInProgress: Fiber): Fiber | null {
968988 let next ;
969989 if ( enableProfilerTimer ) {
970990 if ( workInProgress . mode & ProfileMode ) {
971- startBaseRenderTimer ( ) ;
991+ startProfilerTimer ( workInProgress ) ;
972992 }
973993
974994 next = beginWork ( current , workInProgress , nextRenderExpirationTime ) ;
975995
976996 if ( workInProgress . mode & ProfileMode ) {
977- // Update "base" time if the render wasn't bailed out on.
978- recordElapsedBaseRenderTimeIfRunning ( workInProgress ) ;
979- stopBaseRenderTimerIfRunning ( ) ;
997+ // Record the render duration assuming we didn't bailout (or error).
998+ stopProfilerTimerIfRunningAndRecordDelta ( workInProgress , true ) ;
980999 }
9811000 } else {
9821001 next = beginWork ( current , workInProgress , nextRenderExpirationTime ) ;
@@ -1017,12 +1036,6 @@ function workLoop(isYieldy) {
10171036 while ( nextUnitOfWork !== null && ! shouldYield ( ) ) {
10181037 nextUnitOfWork = performUnitOfWork ( nextUnitOfWork ) ;
10191038 }
1020-
1021- if ( enableProfilerTimer ) {
1022- // If we didn't finish, pause the "actual" render timer.
1023- // We'll restart it when we resume work.
1024- pauseActualRenderTimerIfRunning ( ) ;
1025- }
10261039 }
10271040}
10281041
@@ -1068,11 +1081,6 @@ function renderRoot(
10681081 try {
10691082 workLoop ( isYieldy ) ;
10701083 } catch ( thrownValue ) {
1071- if ( enableProfilerTimer ) {
1072- // Stop "base" render timer in the event of an error.
1073- stopBaseRenderTimerIfRunning ( ) ;
1074- }
1075-
10761084 if ( nextUnitOfWork === null ) {
10771085 // This is a fatal error.
10781086 didFatal = true ;
@@ -1139,10 +1147,6 @@ function renderRoot(
11391147 // There was a fatal error.
11401148 if ( __DEV__ ) {
11411149 resetStackAfterFatalErrorInDev ( ) ;
1142-
1143- // Reset the DEV fiber stack in case we're profiling roots.
1144- // (We do this for profiling bulds when DevTools is detected.)
1145- resetActualRenderTimerStackAfterFatalErrorInDev ( ) ;
11461150 }
11471151 // `nextRoot` points to the in-progress root. A non-null value indicates
11481152 // that we're in the middle of an async render. Set it to null to indicate
@@ -1871,10 +1875,6 @@ function performWork(minExpirationTime: ExpirationTime, dl: Deadline | null) {
18711875 // the deadline.
18721876 findHighestPriorityRoot ( ) ;
18731877
1874- if ( enableProfilerTimer ) {
1875- resumeActualRenderTimerIfPaused ( minExpirationTime === Sync ) ;
1876- }
1877-
18781878 if ( deadline !== null ) {
18791879 recomputeCurrentRendererTime ( ) ;
18801880 currentSchedulerTime = currentRendererTime ;
@@ -1947,7 +1947,6 @@ function flushRoot(root: FiberRoot, expirationTime: ExpirationTime) {
19471947 performWorkOnRoot ( root , expirationTime , true ) ;
19481948 // Flush any sync work that was scheduled by lifecycles
19491949 performSyncWork ( ) ;
1950- pauseActualRenderTimerIfRunning ( ) ;
19511950}
19521951
19531952function finishRendering ( ) {
@@ -2049,12 +2048,6 @@ function performWorkOnRoot(
20492048 // There's no time left. Mark this root as complete. We'll come
20502049 // back and commit it later.
20512050 root . finishedWork = finishedWork ;
2052-
2053- if ( enableProfilerTimer ) {
2054- // If we didn't finish, pause the "actual" render timer.
2055- // We'll restart it when we resume work.
2056- pauseActualRenderTimerIfRunning ( ) ;
2057- }
20582051 }
20592052 }
20602053 }
0 commit comments