Skip to content

Commit 7f02760

Browse files
author
Brian Vaughn
committed
Profiler also captures commit time
1 parent 5ee9c43 commit 7f02760

File tree

4 files changed

+67
-8
lines changed

4 files changed

+67
-8
lines changed

packages/react-reconciler/src/ReactFiberCommitWork.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import type {Fiber} from './ReactFiber';
1212
import type {FiberRoot} from './ReactFiberRoot';
1313
import type {ExpirationTime} from './ReactFiberExpirationTime';
1414
import type {CapturedValue, CapturedError} from './ReactCapturedValue';
15+
import type {ProfilerTimer} from './ReactProfilerTimer';
1516

1617
import {
1718
enableMutatingReconciler,
@@ -106,8 +107,10 @@ export default function<T, P, I, TI, HI, PI, C, CC, CX, PL>(
106107
) => ExpirationTime,
107108
markLegacyErrorBoundaryAsFailed: (instance: mixed) => void,
108109
recalculateCurrentTime: () => ExpirationTime,
110+
profilerTimer: ProfilerTimer,
109111
) {
110112
const {getPublicInstance, mutation, persistence} = config;
113+
const {getCommitTime} = profilerTimer;
111114

112115
const callComponentWillUnmountWithTimer = function(current, instance) {
113116
startPhaseTimer(current, 'componentWillUnmount');
@@ -829,6 +832,7 @@ export default function<T, P, I, TI, HI, PI, C, CC, CX, PL>(
829832
finishedWork.stateNode.duration,
830833
finishedWork.treeBaseTime,
831834
finishedWork.stateNode.startTime,
835+
getCommitTime(),
832836
);
833837

834838
// Reset actualTime after successful commit.

packages/react-reconciler/src/ReactFiberScheduler.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,11 +248,13 @@ export default function<T, P, I, TI, HI, PI, C, CC, CX, PL>(
248248
computeExpirationForFiber,
249249
markLegacyErrorBoundaryAsFailed,
250250
recalculateCurrentTime,
251+
profilerTimer,
251252
);
252253

253254
const {
254255
checkActualRenderTimeStackEmpty,
255256
pauseActualRenderTimerIfRunning,
257+
recordCommitTime,
256258
recordElapsedBaseRenderTimeIfRunning,
257259
resetActualRenderTimer,
258260
resumeActualRenderTimerIfPaused,
@@ -420,6 +422,10 @@ export default function<T, P, I, TI, HI, PI, C, CC, CX, PL>(
420422
}
421423
}
422424

425+
if (enableProfilerTimer) {
426+
recordCommitTime();
427+
}
428+
423429
// The following switch statement is only concerned about placement,
424430
// updates, and deletions. To avoid needing to add a case for every
425431
// possible bitmap value, we remove the secondary effects from the

packages/react-reconciler/src/ReactProfilerTimer.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import warning from 'fbjs/lib/warning';
2121
*/
2222

2323
export type ProfilerTimer = {
24+
getCommitTime(): number,
25+
recordCommitTime(): void,
2426
checkActualRenderTimeStackEmpty(): void,
2527
markActualRenderTimeStarted(fiber: Fiber): void,
2628
pauseActualRenderTimerIfRunning(): void,
@@ -39,6 +41,16 @@ export function createProfilerTimer(now: () => number): ProfilerTimer {
3941
fiberStack = [];
4042
}
4143

44+
let commitTime: number = 0;
45+
46+
function getCommitTime(): number {
47+
return commitTime;
48+
}
49+
50+
function recordCommitTime(): void {
51+
commitTime = now();
52+
}
53+
4254
let timerPausedAt: number = 0;
4355
let totalElapsedPauseTime: number = 0;
4456

@@ -123,6 +135,8 @@ export function createProfilerTimer(now: () => number): ProfilerTimer {
123135

124136
if (enableProfilerTimer) {
125137
return {
138+
getCommitTime,
139+
recordCommitTime,
126140
checkActualRenderTimeStackEmpty,
127141
markActualRenderTimeStarted,
128142
pauseActualRenderTimerIfRunning,
@@ -135,6 +149,10 @@ export function createProfilerTimer(now: () => number): ProfilerTimer {
135149
};
136150
} else {
137151
return {
152+
getCommitTime(): number {
153+
return 0;
154+
},
155+
recordCommitTime(): void {},
138156
checkActualRenderTimeStackEmpty(): void {},
139157
markActualRenderTimeStarted(fiber: Fiber): void {},
140158
pauseActualRenderTimerIfRunning(): void {},

packages/react/src/__tests__/ReactProfiler-test.internal.js

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -177,9 +177,11 @@ describe('Profiler', () => {
177177
</div>,
178178
);
179179

180-
// Should only be called twice, for normal expiration time purposes.
180+
// Should only be called three times:
181+
// Twice for normal expiration time purposes,
182+
// And once to capture the commit time.
181183
// No additional calls from ProfilerTimer are expected.
182-
expect(mockNow).toHaveBeenCalledTimes(2);
184+
expect(mockNow).toHaveBeenCalledTimes(3);
183185
});
184186

185187
it('logs render times for both mount and update', () => {
@@ -197,12 +199,13 @@ describe('Profiler', () => {
197199

198200
let [call] = callback.mock.calls;
199201

200-
expect(call).toHaveLength(5);
202+
expect(call).toHaveLength(6);
201203
expect(call[0]).toBe('test');
202204
expect(call[1]).toBe('mount');
203205
expect(call[2]).toBe(10); // actual time
204206
expect(call[3]).toBe(10); // base time
205207
expect(call[4]).toBe(5); // start time
208+
expect(call[5]).toBe(15); // commit time
206209

207210
callback.mockReset();
208211

@@ -218,12 +221,13 @@ describe('Profiler', () => {
218221

219222
[call] = callback.mock.calls;
220223

221-
expect(call).toHaveLength(5);
224+
expect(call).toHaveLength(6);
222225
expect(call[0]).toBe('test');
223226
expect(call[1]).toBe('update');
224227
expect(call[2]).toBe(10); // actual time
225228
expect(call[3]).toBe(10); // base time
226229
expect(call[4]).toBe(35); // start time
230+
expect(call[5]).toBe(45); // commit time
227231
});
228232

229233
it('includes render times of nested Profilers in their parent times', () => {
@@ -254,9 +258,11 @@ describe('Profiler', () => {
254258
expect(childCall[2]).toBe(20); // actual time
255259
expect(childCall[3]).toBe(20); // base time
256260
expect(childCall[4]).toBe(15); // start time
261+
expect(childCall[5]).toBe(35); // commit time
257262
expect(parentCall[2]).toBe(30); // actual time
258263
expect(parentCall[3]).toBe(30); // base time
259264
expect(parentCall[4]).toBe(5); // start time
265+
expect(parentCall[5]).toBe(35); // commit time
260266
});
261267

262268
it('tracks sibling Profilers separately', () => {
@@ -285,14 +291,18 @@ describe('Profiler', () => {
285291
expect(firstCall[2]).toBe(20); // actual time
286292
expect(firstCall[3]).toBe(20); // base time
287293
expect(firstCall[4]).toBe(5); // start time
294+
expect(firstCall[5]).toBe(30); // commit time
288295
expect(secondCall[2]).toBe(5); // actual time
289296
expect(secondCall[3]).toBe(5); // base time
290297
expect(secondCall[4]).toBe(25); // start time
298+
expect(secondCall[5]).toBe(30); // commit time
291299
});
292300

293301
it('does not include time spent outside of profile root', () => {
294302
const callback = jest.fn();
295303

304+
advanceTimeBy(5); // 0 -> 5
305+
296306
ReactTestRenderer.create(
297307
<React.Fragment>
298308
<AdvanceTime byAmount={20} />
@@ -309,7 +319,8 @@ describe('Profiler', () => {
309319
expect(call[0]).toBe('test');
310320
expect(call[2]).toBe(5); // actual time
311321
expect(call[3]).toBe(5); // base time
312-
expect(call[4]).toBe(20); // start time
322+
expect(call[4]).toBe(25); // start time
323+
expect(call[5]).toBe(50); // commit time
313324
});
314325

315326
it('is not called when blocked by sCU false', () => {
@@ -395,11 +406,13 @@ describe('Profiler', () => {
395406
expect(mountCall[2]).toBe(20); // actual time
396407
expect(mountCall[3]).toBe(20); // base time
397408
expect(mountCall[4]).toBe(5); // start time
409+
expect(mountCall[5]).toBe(25); // commit time
398410

399411
expect(updateCall[1]).toBe('update');
400412
expect(updateCall[2]).toBe(10); // actual time
401413
expect(updateCall[3]).toBe(20); // base time
402414
expect(updateCall[4]).toBe(55); // start time
415+
expect(updateCall[5]).toBe(65); // commit time
403416
});
404417

405418
it('includes time spent in render phase lifecycles', () => {
@@ -445,11 +458,13 @@ describe('Profiler', () => {
445458
expect(mountCall[2]).toBe(8); // actual time
446459
expect(mountCall[3]).toBe(8); // base time
447460
expect(mountCall[4]).toBe(5); // start time
461+
expect(mountCall[5]).toBe(13); // commit time
448462

449463
expect(updateCall[1]).toBe('update');
450464
expect(updateCall[2]).toBe(15); // actual time
451465
expect(updateCall[3]).toBe(15); // base time
452466
expect(updateCall[4]).toBe(28); // start time
467+
expect(updateCall[5]).toBe(43); // commit time
453468
});
454469

455470
describe('with regard to interruptions', () => {
@@ -482,9 +497,11 @@ describe('Profiler', () => {
482497

483498
// Verify that logged times include both durations above.
484499
expect(callback).toHaveBeenCalledTimes(1);
485-
expect(callback.mock.calls[0][2]).toBe(5); // actual time
486-
expect(callback.mock.calls[0][3]).toBe(5); // base time
487-
expect(callback.mock.calls[0][4]).toBe(5); // start time
500+
const [call] = callback.mock.calls;
501+
expect(call[2]).toBe(5); // actual time
502+
expect(call[3]).toBe(5); // base time
503+
expect(call[4]).toBe(5); // start time
504+
expect(call[5]).toBe(10); // commit time
488505
});
489506

490507
it('should not include time between frames', () => {
@@ -531,10 +548,12 @@ describe('Profiler', () => {
531548
expect(innerCall[2]).toBe(17); // actual time
532549
expect(innerCall[3]).toBe(17); // base time
533550
expect(innerCall[4]).toBe(70); // start time
551+
expect(innerCall[5]).toBe(87); // commit time
534552
expect(outerCall[0]).toBe('outer');
535553
expect(outerCall[2]).toBe(32); // actual time
536554
expect(outerCall[3]).toBe(32); // base time
537555
expect(outerCall[4]).toBe(5); // start time
556+
expect(outerCall[5]).toBe(87); // commit time
538557
});
539558

540559
it('should report the expected times when a high-priority update replaces an in-progress initial render', () => {
@@ -582,6 +601,7 @@ describe('Profiler', () => {
582601
expect(call[2]).toBe(5); // actual time
583602
expect(call[3]).toBe(5); // base time
584603
expect(call[4]).toBe(115); // start time
604+
expect(call[5]).toBe(120); // commit time
585605

586606
callback.mockReset();
587607

@@ -617,6 +637,7 @@ describe('Profiler', () => {
617637
expect(call[2]).toBe(21); // actual time
618638
expect(call[3]).toBe(21); // base time
619639
expect(call[4]).toBe(5); // start time
640+
expect(call[5]).toBe(26); // commit time
620641

621642
callback.mockReset();
622643

@@ -667,6 +688,7 @@ describe('Profiler', () => {
667688
expect(call[2]).toBe(19); // actual time
668689
expect(call[3]).toBe(11); // base time
669690
expect(call[4]).toBe(264); // start time
691+
expect(call[5]).toBe(275); // commit time
670692

671693
// Verify no more unexpected callbacks from low priority work
672694
expect(renderer.unstable_flushAll()).toEqual([]);
@@ -727,6 +749,7 @@ describe('Profiler', () => {
727749
expect(call[2]).toBe(14); // actual time
728750
expect(call[3]).toBe(14); // base time
729751
expect(call[4]).toBe(5); // start time
752+
expect(call[5]).toBe(19); // commit time
730753

731754
callback.mockClear();
732755

@@ -757,6 +780,7 @@ describe('Profiler', () => {
757780
expect(call[2]).toBe(47); // actual time
758781
expect(call[3]).toBe(42); // base time
759782
expect(call[4]).toBe(229); // start time
783+
expect(call[5]).toBe(266); // commit time
760784

761785
callback.mockClear();
762786

@@ -778,6 +802,7 @@ describe('Profiler', () => {
778802
expect(call[2]).toBe(14); // actual time
779803
expect(call[3]).toBe(51); // base time
780804
expect(call[4]).toBe(366); // start time
805+
expect(call[5]).toBe(380); // commit time
781806
});
782807

783808
[true, false].forEach(flagEnabled => {
@@ -842,6 +867,8 @@ describe('Profiler', () => {
842867
expect(mountCall[3]).toBe(2);
843868
// start time
844869
expect(mountCall[4]).toBe(5);
870+
// commit time
871+
expect(mountCall[5]).toBe(flagEnabled && __DEV__ ? 32 : 22);
845872

846873
// The update includes the ErrorBoundary and its fallback child
847874
expect(updateCall[1]).toBe('update');
@@ -851,6 +878,8 @@ describe('Profiler', () => {
851878
expect(updateCall[3]).toBe(22);
852879
// start time
853880
expect(updateCall[4]).toBe(flagEnabled && __DEV__ ? 32 : 22);
881+
// commit time
882+
expect(updateCall[5]).toBe(flagEnabled && __DEV__ ? 54 : 44);
854883
});
855884

856885
it('should accumulate actual time after an error handled by getDerivedStateFromCatch()', () => {
@@ -903,6 +932,8 @@ describe('Profiler', () => {
903932
expect(mountCall[3]).toBe(22);
904933
// start time
905934
expect(mountCall[4]).toBe(5);
935+
// commit time
936+
expect(mountCall[5]).toBe(flagEnabled && __DEV__ ? 54 : 44);
906937
});
907938
});
908939
});

0 commit comments

Comments
 (0)