164
source: null | string | Error | Source, // source location of this component function, or owned child stack
165
errors: null | Map<string, number>, // error messages and count
166
warnings: null | Map<string, number>, // warning messages and count
167
+ treeBaseDuration: number, // the profiled time of the last render of this subtree
168
data: Fiber, // one of a Fiber pair
169
};
170
180
source: null,
181
errors: null,
182
warnings: null,
183
+ treeBaseDuration: 0,
184
data: fiber,
185
};
186
}
204
// that old errors/warnings don't disappear when the instance is refreshed.
205
errors: null | Map<string, number>, // error messages and count
206
warnings: null | Map<string, number>, // warning messages and count
207
+ treeBaseDuration: number, // the profiled time of the last render of this subtree
208
// The latest info for this instance. This can be updated over time and the
209
// same info can appear in more than once ServerComponentInstance.
210
data: ReactComponentInfo,
224
source: null,
225
errors: null,
226
warnings: null,
227
+ treeBaseDuration: 0,
228
data: debugEntry,
229
};
230
}
1359
}
1360
}
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
-
1362
// When a mount or update is in progress, this value tracks the root that is being operated on.
1363
let currentRootID: number = -1;
1364
2205
}
2206
2207
if (isProfilingSupported) {
2214
- idToRootMap.set(id, currentRootID);
2215
-
2216
- recordProfilingDurations(fiber);
2208
+ recordProfilingDurations(fiberInstance);
2209
}
2210
return fiberInstance;
2211
}
2218
2219
idToDevToolsInstanceMap.set(id, instance);
2220
2229
- const isProfilingSupported = false; // TODO: Support Tree Base Duration Based on Children.
2230
-
2221
const componentInfo = instance.data;
2222
2223
const key =
2264
pushOperation(ownerID);
2265
pushOperation(displayNameStringID);
2266
pushOperation(keyStringID);
2277
-
2278
- if (isProfilingSupported) {
2279
- idToRootMap.set(id, currentRootID);
2280
- // TODO: Include tree base duration of children somehow.
2281
- // recordProfilingDurations(...);
2282
- }
2267
}
2268
2269
function recordUnmount(fiberInstance: FiberInstance): void {
2298
}
2299
2300
untrackFiber(fiberInstance);
2317
-
2318
- const isProfilingSupported = fiber.hasOwnProperty('treeBaseDuration');
2319
- if (isProfilingSupported) {
2320
- idToRootMap.delete(id);
2321
- idToTreeBaseDurationMap.delete(id);
2322
- }
2301
}
2302
2303
// Running state of the remaining children from the previous version of this parent that
2408
traceNearestHostComponentUpdate,
2409
virtualLevel + 1,
2410
);
2411
+ // Must be called after all children have been appended.
2412
+ recordVirtualProfilingDurations(virtualInstance);
2413
} finally {
2414
reconcilingParent = stashedParent;
2415
previouslyReconciledSibling = stashedPrevious;
2425
2426
const id = instance.id;
2427
pendingRealUnmountedIDs.push(id);
2448
-
2449
- const isProfilingSupported = false; // TODO: Profiling support.
2450
- if (isProfilingSupported) {
2451
- idToRootMap.delete(id);
2452
- idToTreeBaseDurationMap.delete(id);
2453
- }
2428
}
2429
2430
function mountVirtualChildrenRecursively(
2658
removeChild(instance);
2659
}
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;
2664
const {actualDuration, treeBaseDuration} = fiber;
2665
2691
- idToTreeBaseDurationMap.set(id, treeBaseDuration || 0);
2666
+ fiberInstance.treeBaseDuration = treeBaseDuration || 0;
2667
2668
if (isProfiling) {
2669
const {alternate} = fiber;
2726
}
2727
}
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
+
2761
function recordResetChildren(parentInstance: DevToolsInstance) {
2762
if (__DEBUG__) {
2763
if (
2825
) {
2826
recordResetChildren(virtualInstance);
2827
}
2828
+ // Must be called after all children have been appended.
2829
+ recordVirtualProfilingDurations(virtualInstance);
2830
} finally {
2831
unmountRemainingChildren();
2832
reconcilingParent = stashedParent;
3274
}
3275
}
3276
3268
- if (shouldIncludeInTree) {
3277
+ if (fiberInstance !== null) {
3278
const isProfilingSupported =
3279
nextFiber.hasOwnProperty('treeBaseDuration');
3280
if (isProfilingSupported) {
3272
- recordProfilingDurations(nextFiber);
3281
+ recordProfilingDurations(fiberInstance);
3282
}
3283
}
3284
if (shouldResetChildren) {
5130
let currentCommitProfilingMetadata: CommitProfilingData | null = null;
5131
let displayNamesByRootID: DisplayNamesByRootID | null = null;
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;
5135
let isProfiling: boolean = false;
5136
let profilingStartTime: number = 0;
5137
let recordChangeDescriptions: boolean = false;
5150
rootToCommitProfilingMetadataMap.forEach(
5151
(commitProfilingMetadata, rootID) => {
5152
const commitData: Array<CommitDataBackend> = [];
5144
- const initialTreeBaseDurations: Array<[number, number]> = [];
5153
5154
const displayName =
5155
(displayNamesByRootID !== null && displayNamesByRootID.get(rootID)) ||
5156
'Unknown';
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
5163
commitProfilingMetadata.forEach((commitProfilingData, commitIndex) => {
5164
const {
5245
};
5246
}
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
+
5264
function startProfiling(shouldRecordChangeDescriptions: boolean) {
5265
if (isProfiling) {
5266
return;
5273
// since either of these may change during the profiling session
5274
// (e.g. when a fiber is re-rendered or when a fiber gets removed).
5275
displayNamesByRootID = new Map();
5260
- initialTreeBaseDurationsMap = new Map(idToTreeBaseDurationMap);
5261
- initialIDToRootMap = new Map(idToRootMap);
5276
+ initialTreeBaseDurationsMap = new Map();
5277
idToContextsMap = new Map();
5278
5279
hook.getFiberRoots(rendererID).forEach(root => {
5265
- const rootID = getFiberIDThrows(root.current);
5280
+ const rootInstance = getFiberInstanceThrows(root.current);
5281
+ const rootID = rootInstance.id;
5282
((displayNamesByRootID: any): DisplayNamesByRootID).set(
5283
rootID,
5284
getDisplayNameForRoot(root.current),
5285
);
5286
+ const initialTreeBaseDurations: Array<[number, number]> = [];
5287
+ snapshotTreeBaseDurations(rootInstance, initialTreeBaseDurations);
5288
+ (initialTreeBaseDurationsMap: any).set(rootID, initialTreeBaseDurations);
5289
5290
if (shouldRecordChangeDescriptions) {
5291
// Record all contexts at the time profiling is started.