Skip to content

Commit 32a0ee0

Browse files
gaearonfacebook-github-bot
authored andcommitted
Implement Systrace integration for Fiber
Reviewed By: bvaughn Differential Revision: D5210738 fbshipit-source-id: db7df5ca7a1b4944f86719361d22ec3cc2ce8f22
1 parent e38641c commit 32a0ee0

File tree

3 files changed

+74
-62
lines changed

3 files changed

+74
-62
lines changed

Libraries/Core/InitializeCore.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,9 @@ if (!global.process.env.NODE_ENV) {
9999
// Set up profile
100100
const Systrace = require('Systrace');
101101
Systrace.setEnabled(global.__RCTProfileIsProfiling || false);
102+
if (__DEV__) {
103+
global.performance = Systrace.getUserTimingPolyfill();
104+
}
102105

103106
// Set up console
104107
const ExceptionsManager = require('ExceptionsManager');

Libraries/Performance/RCTRenderingPerf.js

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,6 @@
1111
*/
1212
'use strict';
1313

14-
var ReactDebugTool = require('ReactDebugTool');
15-
var ReactPerf = require('ReactPerf');
16-
1714
var invariant = require('fbjs/lib/invariant');
1815
var performanceNow = require('fbjs/lib/performanceNow');
1916

@@ -24,22 +21,6 @@ type perfModule = {
2421

2522
var perfModules = [];
2623
var enabled = false;
27-
var lastRenderStartTime = 0;
28-
var totalRenderDuration = 0;
29-
30-
var RCTRenderingPerfDevtool = {
31-
onBeginLifeCycleTimer(debugID, timerType) {
32-
if (timerType === 'render') {
33-
lastRenderStartTime = performanceNow();
34-
}
35-
},
36-
onEndLifeCycleTimer(debugID, timerType) {
37-
if (timerType === 'render') {
38-
var lastRenderDuration = performanceNow() - lastRenderStartTime;
39-
totalRenderDuration += lastRenderDuration;
40-
}
41-
},
42-
};
4324

4425
var RCTRenderingPerf = {
4526
// Once perf is enabled, it stays enabled
@@ -53,8 +34,6 @@ var RCTRenderingPerf = {
5334
return;
5435
}
5536

56-
ReactPerf.start();
57-
ReactDebugTool.addHook(RCTRenderingPerfDevtool);
5837
perfModules.forEach((module) => module.start());
5938
},
6039

@@ -63,15 +42,6 @@ var RCTRenderingPerf = {
6342
return;
6443
}
6544

66-
ReactPerf.stop();
67-
ReactPerf.printInclusive();
68-
ReactPerf.printWasted();
69-
ReactDebugTool.removeHook(RCTRenderingPerfDevtool);
70-
71-
console.log(`Total time spent in render(): ${totalRenderDuration.toFixed(2)} ms`);
72-
lastRenderStartTime = 0;
73-
totalRenderDuration = 0;
74-
7545
perfModules.forEach((module) => module.stop());
7646
},
7747

Libraries/Performance/Systrace.js

Lines changed: 71 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
*/
1212
'use strict';
1313

14+
const invariant = require('fbjs/lib/invariant');
15+
1416
type RelayProfiler = {
1517
attachProfileHandler(
1618
name: string,
@@ -29,52 +31,89 @@ const TRACE_TAG_JSC_CALLS = 1 << 27;
2931

3032
let _enabled = false;
3133
let _asyncCookie = 0;
34+
const _markStack = [];
35+
let _markStackIndex = -1;
3236

33-
const ReactSystraceDevtool = __DEV__ ? {
34-
onBeforeMountComponent(debugID) {
35-
const ReactComponentTreeHook = require('ReactGlobalSharedState').ReactComponentTreeHook;
36-
const displayName = ReactComponentTreeHook.getDisplayName(debugID);
37-
Systrace.beginEvent(`ReactReconciler.mountComponent(${displayName})`);
38-
},
39-
onMountComponent(debugID) {
40-
Systrace.endEvent();
41-
},
42-
onBeforeUpdateComponent(debugID) {
43-
const ReactComponentTreeHook = require('ReactGlobalSharedState').ReactComponentTreeHook;
44-
const displayName = ReactComponentTreeHook.getDisplayName(debugID);
45-
Systrace.beginEvent(`ReactReconciler.updateComponent(${displayName})`);
46-
},
47-
onUpdateComponent(debugID) {
48-
Systrace.endEvent();
49-
},
50-
onBeforeUnmountComponent(debugID) {
51-
const ReactComponentTreeHook = require('ReactGlobalSharedState').ReactComponentTreeHook;
52-
const displayName = ReactComponentTreeHook.getDisplayName(debugID);
53-
Systrace.beginEvent(`ReactReconciler.unmountComponent(${displayName})`);
37+
// Implements a subset of User Timing API necessary for React measurements.
38+
// https://developer.mozilla.org/en-US/docs/Web/API/User_Timing_API
39+
const REACT_MARKER = '\u269B';
40+
const userTimingPolyfill = {
41+
mark(markName: string) {
42+
if (__DEV__) {
43+
if (_enabled) {
44+
_markStackIndex++;
45+
_markStack[_markStackIndex] = markName;
46+
let systraceLabel = markName;
47+
// Since perf measurements are a shared namespace in User Timing API,
48+
// we prefix all React results with a React emoji.
49+
if (markName[0] === REACT_MARKER) {
50+
// This is coming from React.
51+
// Removing component IDs keeps trace colors stable.
52+
const indexOfId = markName.lastIndexOf(' (#');
53+
const cutoffIndex = indexOfId !== -1 ? indexOfId : markName.length;
54+
// Also cut off the emoji because it breaks Systrace
55+
systraceLabel = markName.slice(2, cutoffIndex);
56+
}
57+
Systrace.beginEvent(systraceLabel);
58+
}
59+
}
5460
},
55-
onUnmountComponent(debugID) {
56-
Systrace.endEvent();
61+
measure(measureName: string, startMark: ?string, endMark: ?string) {
62+
if (__DEV__) {
63+
if (_enabled) {
64+
invariant(
65+
typeof measureName === 'string' &&
66+
typeof startMark === 'string' &&
67+
typeof endMark === 'undefined',
68+
'Only performance.measure(string, string) overload is supported.'
69+
);
70+
const topMark = _markStack[_markStackIndex];
71+
invariant(
72+
startMark === topMark,
73+
'There was a mismatching performance.measure() call. ' +
74+
'Expected "%s" but got "%s."',
75+
topMark,
76+
startMark,
77+
);
78+
_markStackIndex--;
79+
// We can't use more descriptive measureName because Systrace doesn't
80+
// let us edit labels post factum.
81+
Systrace.endEvent();
82+
}
83+
}
5784
},
58-
onBeginLifeCycleTimer(debugID, timerType) {
59-
const ReactComponentTreeHook = require('ReactGlobalSharedState').ReactComponentTreeHook;
60-
const displayName = ReactComponentTreeHook.getDisplayName(debugID);
61-
Systrace.beginEvent(`${displayName}.${timerType}()`);
85+
clearMarks(markName: string) {
86+
if (__DEV__) {
87+
if (_enabled) {
88+
if (_markStackIndex === -1) {
89+
return;
90+
}
91+
if (markName === _markStack[_markStackIndex]) {
92+
// React uses this for "cancelling" started measurements.
93+
// Systrace doesn't support deleting measurements, so we just stop them.
94+
userTimingPolyfill.measure(markName, markName);
95+
}
96+
}
97+
}
6298
},
63-
onEndLifeCycleTimer(debugID, timerType) {
64-
Systrace.endEvent();
99+
clearMeasures() {
100+
// React calls this to avoid memory leaks in browsers, but we don't keep
101+
// measurements anyway.
65102
},
66-
} : null;
103+
};
67104

68105
const Systrace = {
106+
getUserTimingPolyfill() {
107+
return userTimingPolyfill;
108+
},
109+
69110
setEnabled(enabled: boolean) {
70111
if (_enabled !== enabled) {
71112
if (__DEV__) {
72113
if (enabled) {
73114
global.nativeTraceBeginLegacy && global.nativeTraceBeginLegacy(TRACE_TAG_JSC_CALLS);
74-
require('ReactDebugTool').addHook(ReactSystraceDevtool);
75115
} else {
76116
global.nativeTraceEndLegacy && global.nativeTraceEndLegacy(TRACE_TAG_JSC_CALLS);
77-
require('ReactDebugTool').removeHook(ReactSystraceDevtool);
78117
}
79118
}
80119
_enabled = enabled;

0 commit comments

Comments
 (0)