@@ -164,6 +164,7 @@ type FiberInstance = {
164
164
source : null | string | Error | Source , // source location of this component function, or owned child stack
165
165
errors : null | Map < string , number> , // error messages and count
166
166
warnings : null | Map < string , number> , // warning messages and count
167
+ treeBaseDuration : number , // the profiled time of the last render of this subtree
167
168
data : Fiber , // one of a Fiber pair
168
169
} ;
169
170
@@ -179,6 +180,7 @@ function createFiberInstance(fiber: Fiber): FiberInstance {
179
180
source : null ,
180
181
errors : null ,
181
182
warnings : null ,
183
+ treeBaseDuration : 0 ,
182
184
data : fiber ,
183
185
} ;
184
186
}
@@ -202,6 +204,7 @@ type VirtualInstance = {
202
204
// that old errors/warnings don't disappear when the instance is refreshed.
203
205
errors : null | Map < string , number> , // error messages and count
204
206
warnings : null | Map < string , number> , // warning messages and count
207
+ treeBaseDuration : number , // the profiled time of the last render of this subtree
205
208
// The latest info for this instance. This can be updated over time and the
206
209
// same info can appear in more than once ServerComponentInstance.
207
210
data : ReactComponentInfo ,
@@ -221,6 +224,7 @@ function createVirtualInstance(
221
224
source : null ,
222
225
errors : null ,
223
226
warnings : null ,
227
+ treeBaseDuration : 0 ,
224
228
data : debugEntry ,
225
229
} ;
226
230
}
@@ -1355,16 +1359,6 @@ export function attach(
1355
1359
}
1356
1360
}
1357
1361
1358
- // When profiling is supported, we store the latest tree base durations for each Fiber.
1359
- // This is so that we can quickly capture a snapshot of those values if profiling starts.
1360
- // If we didn't store these values, we'd have to crawl the tree when profiling started,
1361
- // and use a slow path to find each of the current Fibers.
1362
- const idToTreeBaseDurationMap : Map < number , number > = new Map();
1363
-
1364
- // When profiling is supported, we store the latest tree base durations for each Fiber.
1365
- // This map enables us to filter these times by root when sending them to the frontend.
1366
- const idToRootMap: Map< number , number > = new Map();
1367
-
1368
1362
// When a mount or update is in progress, this value tracks the root that is being operated on.
1369
1363
let currentRootID : number = - 1 ;
1370
1364
@@ -2211,9 +2205,7 @@ export function attach(
2211
2205
}
2212
2206
2213
2207
if ( isProfilingSupported ) {
2214
- idToRootMap . set ( id , currentRootID ) ;
2215
-
2216
- recordProfilingDurations ( fiber ) ;
2208
+ recordProfilingDurations ( fiberInstance ) ;
2217
2209
}
2218
2210
return fiberInstance ;
2219
2211
}
@@ -2226,8 +2218,6 @@ export function attach(
2226
2218
2227
2219
idToDevToolsInstanceMap . set ( id , instance ) ;
2228
2220
2229
- const isProfilingSupported = false ; // TODO: Support Tree Base Duration Based on Children.
2230
-
2231
2221
const componentInfo = instance . data ;
2232
2222
2233
2223
const key =
@@ -2274,12 +2264,6 @@ export function attach(
2274
2264
pushOperation ( ownerID ) ;
2275
2265
pushOperation ( displayNameStringID ) ;
2276
2266
pushOperation ( keyStringID ) ;
2277
-
2278
- if ( isProfilingSupported ) {
2279
- idToRootMap . set ( id , currentRootID ) ;
2280
- // TODO: Include tree base duration of children somehow.
2281
- // recordProfilingDurations(...);
2282
- }
2283
2267
}
2284
2268
2285
2269
function recordUnmount ( fiberInstance : FiberInstance ) : void {
@@ -2314,12 +2298,6 @@ export function attach(
2314
2298
}
2315
2299
2316
2300
untrackFiber ( fiberInstance ) ;
2317
-
2318
- const isProfilingSupported = fiber . hasOwnProperty ( 'treeBaseDuration ') ;
2319
- if ( isProfilingSupported ) {
2320
- idToRootMap . delete ( id ) ;
2321
- idToTreeBaseDurationMap . delete ( id ) ;
2322
- }
2323
2301
}
2324
2302
2325
2303
// Running state of the remaining children from the previous version of this parent that
@@ -2430,6 +2408,8 @@ export function attach(
2430
2408
traceNearestHostComponentUpdate ,
2431
2409
virtualLevel + 1 ,
2432
2410
) ;
2411
+ // Must be called after all children have been appended.
2412
+ recordVirtualProfilingDurations ( virtualInstance ) ;
2433
2413
} finally {
2434
2414
reconcilingParent = stashedParent ;
2435
2415
previouslyReconciledSibling = stashedPrevious ;
@@ -2445,12 +2425,6 @@ export function attach(
2445
2425
2446
2426
const id = instance . id ;
2447
2427
pendingRealUnmountedIDs . push ( id ) ;
2448
-
2449
- const isProfilingSupported = false ; // TODO: Profiling support.
2450
- if ( isProfilingSupported ) {
2451
- idToRootMap . delete ( id ) ;
2452
- idToTreeBaseDurationMap . delete ( id ) ;
2453
- }
2454
2428
}
2455
2429
2456
2430
function mountVirtualChildrenRecursively (
@@ -2684,11 +2658,12 @@ export function attach(
2684
2658
removeChild ( instance ) ;
2685
2659
}
2686
2660
2687
- function recordProfilingDurations ( fiber : Fiber ) {
2688
- const id = getFiberIDThrows ( fiber ) ;
2661
+ function recordProfilingDurations ( fiberInstance : FiberInstance ) {
2662
+ const id = fiberInstance . id ;
2663
+ const fiber = fiberInstance . data ;
2689
2664
const { actualDuration, treeBaseDuration} = fiber ;
2690
2665
2691
- idToTreeBaseDurationMap . set ( id , treeBaseDuration || 0 ) ;
2666
+ fiberInstance . treeBaseDuration = treeBaseDuration || 0 ;
2692
2667
2693
2668
if ( isProfiling ) {
2694
2669
const { alternate} = fiber ;
@@ -2751,6 +2726,38 @@ export function attach(
2751
2726
}
2752
2727
}
2753
2728
2729
+ function recordVirtualProfilingDurations ( virtualInstance : VirtualInstance ) {
2730
+ const id = virtualInstance . id ;
2731
+
2732
+ let treeBaseDuration = 0 ;
2733
+ // Add up the base duration of the child instances. The virtual base duration
2734
+ // will be the same as children's duration since we don't take up any render
2735
+ // time in the virtual instance.
2736
+ for (
2737
+ let child = virtualInstance . firstChild ;
2738
+ child !== null ;
2739
+ child = child . nextSibling
2740
+ ) {
2741
+ treeBaseDuration += child . treeBaseDuration ;
2742
+ }
2743
+
2744
+ if ( isProfiling ) {
2745
+ const previousTreeBaseDuration = virtualInstance . treeBaseDuration ;
2746
+ if ( treeBaseDuration !== previousTreeBaseDuration ) {
2747
+ // Tree base duration updates are included in the operations typed array.
2748
+ // So we have to convert them from milliseconds to microseconds so we can send them as ints.
2749
+ const convertedTreeBaseDuration = Math . floor (
2750
+ ( treeBaseDuration || 0 ) * 1000 ,
2751
+ ) ;
2752
+ pushOperation ( TREE_OPERATION_UPDATE_TREE_BASE_DURATION ) ;
2753
+ pushOperation ( id ) ;
2754
+ pushOperation ( convertedTreeBaseDuration ) ;
2755
+ }
2756
+ }
2757
+
2758
+ virtualInstance . treeBaseDuration = treeBaseDuration ;
2759
+ }
2760
+
2754
2761
function recordResetChildren ( parentInstance : DevToolsInstance ) {
2755
2762
if ( __DEBUG__ ) {
2756
2763
if (
@@ -2818,6 +2825,8 @@ export function attach(
2818
2825
) {
2819
2826
recordResetChildren ( virtualInstance ) ;
2820
2827
}
2828
+ // Must be called after all children have been appended.
2829
+ recordVirtualProfilingDurations ( virtualInstance ) ;
2821
2830
} finally {
2822
2831
unmountRemainingChildren ( ) ;
2823
2832
reconcilingParent = stashedParent ;
@@ -3265,11 +3274,11 @@ export function attach(
3265
3274
}
3266
3275
}
3267
3276
3268
- if ( shouldIncludeInTree ) {
3277
+ if ( fiberInstance !== null ) {
3269
3278
const isProfilingSupported =
3270
3279
nextFiber . hasOwnProperty ( 'treeBaseDuration' ) ;
3271
3280
if ( isProfilingSupported ) {
3272
- recordProfilingDurations ( nextFiber ) ;
3281
+ recordProfilingDurations ( fiberInstance ) ;
3273
3282
}
3274
3283
}
3275
3284
if ( shouldResetChildren ) {
@@ -5121,8 +5130,8 @@ export function attach(
5121
5130
let currentCommitProfilingMetadata: CommitProfilingData | null = null;
5122
5131
let displayNamesByRootID: DisplayNamesByRootID | null = null;
5123
5132
let idToContextsMap: Map< number , any > | null = null;
5124
- let initialTreeBaseDurationsMap: Map< number , number > | null = null;
5125
- let initialIDToRootMap: Map < number , number > | null = null;
5133
+ let initialTreeBaseDurationsMap: Map< number , Array < [ number , number ] >> | null =
5134
+ null ;
5126
5135
let isProfiling : boolean = false ;
5127
5136
let profilingStartTime : number = 0 ;
5128
5137
let recordChangeDescriptions : boolean = false ;
@@ -5141,24 +5150,15 @@ export function attach(
5141
5150
rootToCommitProfilingMetadataMap.forEach(
5142
5151
(commitProfilingMetadata, rootID) => {
5143
5152
const commitData : Array < CommitDataBackend > = [ ] ;
5144
- const initialTreeBaseDurations: Array< [ number , number ] > = [ ] ;
5145
5153
5146
5154
const displayName =
5147
5155
( displayNamesByRootID !== null && displayNamesByRootID . get ( rootID ) ) ||
5148
5156
'Unknown' ;
5149
5157
5150
- if ( initialTreeBaseDurationsMap != null ) {
5151
- initialTreeBaseDurationsMap . forEach ( ( treeBaseDuration , id ) => {
5152
- if (
5153
- initialIDToRootMap != null &&
5154
- initialIDToRootMap . get ( id ) === rootID
5155
- ) {
5156
- // We don't need to convert milliseconds to microseconds in this case,
5157
- // because the profiling summary is JSON serialized.
5158
- initialTreeBaseDurations . push ( [ id , treeBaseDuration ] ) ;
5159
- }
5160
- } ) ;
5161
- }
5158
+ const initialTreeBaseDurations : Array < [ number , number ] > =
5159
+ ( initialTreeBaseDurationsMap !== null &&
5160
+ initialTreeBaseDurationsMap . get ( rootID ) ) ||
5161
+ [ ] ;
5162
5162
5163
5163
commitProfilingMetadata . forEach ( ( commitProfilingData , commitIndex ) => {
5164
5164
const {
@@ -5245,6 +5245,22 @@ export function attach(
5245
5245
} ;
5246
5246
}
5247
5247
5248
+ function snapshotTreeBaseDurations (
5249
+ instance : DevToolsInstance ,
5250
+ target : Array < [ number , number ] > ,
5251
+ ) {
5252
+ // We don't need to convert milliseconds to microseconds in this case,
5253
+ // because the profiling summary is JSON serialized.
5254
+ target . push ( [ instance . id , instance . treeBaseDuration ] ) ;
5255
+ for (
5256
+ let child = instance . firstChild ;
5257
+ child !== null ;
5258
+ child = child . nextSibling
5259
+ ) {
5260
+ snapshotTreeBaseDurations ( child , target ) ;
5261
+ }
5262
+ }
5263
+
5248
5264
function startProfiling ( shouldRecordChangeDescriptions : boolean ) {
5249
5265
if ( isProfiling ) {
5250
5266
return ;
@@ -5257,16 +5273,19 @@ export function attach(
5257
5273
// since either of these may change during the profiling session
5258
5274
// (e.g. when a fiber is re-rendered or when a fiber gets removed).
5259
5275
displayNamesByRootID = new Map();
5260
- initialTreeBaseDurationsMap = new Map ( idToTreeBaseDurationMap ) ;
5261
- initialIDToRootMap = new Map ( idToRootMap ) ;
5276
+ initialTreeBaseDurationsMap = new Map();
5262
5277
idToContextsMap = new Map();
5263
5278
5264
5279
hook.getFiberRoots(rendererID).forEach(root => {
5265
- const rootID = getFiberIDThrows ( root . current ) ;
5280
+ const rootInstance = getFiberInstanceThrows ( root . current ) ;
5281
+ const rootID = rootInstance . id ;
5266
5282
( ( displayNamesByRootID : any ) : DisplayNamesByRootID ) . set (
5267
5283
rootID ,
5268
5284
getDisplayNameForRoot ( root . current ) ,
5269
5285
) ;
5286
+ const initialTreeBaseDurations : Array < [ number , number ] > = [ ] ;
5287
+ snapshotTreeBaseDurations ( rootInstance , initialTreeBaseDurations ) ;
5288
+ ( initialTreeBaseDurationsMap : any ) . set ( rootID , initialTreeBaseDurations ) ;
5270
5289
5271
5290
if ( shouldRecordChangeDescriptions ) {
5272
5291
// Record all contexts at the time profiling is started.
0 commit comments