diff --git a/grunt/tasks/npm-react-addons.js b/grunt/tasks/npm-react-addons.js
index 1cb2cf1c304..0f3d088d9cc 100644
--- a/grunt/tasks/npm-react-addons.js
+++ b/grunt/tasks/npm-react-addons.js
@@ -16,7 +16,7 @@ var addons = {
docs: 'two-way-binding-helpers',
},
Perf: {
- module: 'ReactPerfAnalysis',
+ module: 'ReactPerf',
name: 'perf',
docs: 'perf',
},
diff --git a/src/addons/ReactWithAddons.js b/src/addons/ReactWithAddons.js
index 89e4e844824..94102c5c2e8 100644
--- a/src/addons/ReactWithAddons.js
+++ b/src/addons/ReactWithAddons.js
@@ -34,7 +34,7 @@ React.addons = {
};
if (__DEV__) {
- React.addons.Perf = require('ReactPerfAnalysis');
+ React.addons.Perf = require('ReactPerf');
React.addons.TestUtils = require('ReactTestUtils');
}
diff --git a/src/isomorphic/ReactDebugTool.js b/src/isomorphic/ReactDebugTool.js
index 5d166bca7f0..8fbc0341f80 100644
--- a/src/isomorphic/ReactDebugTool.js
+++ b/src/isomorphic/ReactDebugTool.js
@@ -72,6 +72,7 @@ function resetMeasurements() {
tree[id] = {
displayName: ReactComponentTreeDevtool.getDisplayName(id),
text: ReactComponentTreeDevtool.getText(id),
+ updateCount: ReactComponentTreeDevtool.getUpdateCount(id),
childIDs: ReactComponentTreeDevtool.getChildIDs(id),
// Text nodes don't have owners but this is close enough.
ownerID: ownerID || ReactComponentTreeDevtool.getOwnerID(parentID),
@@ -144,7 +145,7 @@ var ReactDebugTool = {
onBeginLifeCycleTimer(debugID, timerType) {
emitEvent('onBeginLifeCycleTimer', debugID, timerType);
if (__DEV__) {
- if (isProfiling) {
+ if (isProfiling && currentFlushNesting > 0) {
warning(
!currentTimerType,
'There is an internal error in the React performance measurement code. ' +
@@ -162,7 +163,7 @@ var ReactDebugTool = {
},
onEndLifeCycleTimer(debugID, timerType) {
if (__DEV__) {
- if (isProfiling) {
+ if (isProfiling && currentFlushNesting > 0) {
warning(
currentTimerType === timerType,
'There is an internal error in the React performance measurement code. ' +
@@ -175,7 +176,7 @@ var ReactDebugTool = {
currentFlushMeasurements.push({
timerType,
instanceID: debugID,
- duration: performance.now() - currentTimerStartTime,
+ duration: performanceNow() - currentTimerStartTime,
});
currentTimerStartTime = null;
currentTimerDebugID = null;
diff --git a/src/isomorphic/ReactPerfAnalysis.js b/src/isomorphic/ReactPerf.js
similarity index 79%
rename from src/isomorphic/ReactPerfAnalysis.js
rename to src/isomorphic/ReactPerf.js
index f32d6a9b4d4..4c631a7f13e 100644
--- a/src/isomorphic/ReactPerfAnalysis.js
+++ b/src/isomorphic/ReactPerf.js
@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
- * @providesModule ReactPerfAnalysis
+ * @providesModule ReactPerf
*/
'use strict';
@@ -27,12 +27,10 @@ function getExclusive(flushHistory = getFlushHistory()) {
var aggregatedStats = {};
var affectedIDs = {};
- function updateAggregatedStats(treeSnapshot, instanceID, applyUpdate) {
+ function updateAggregatedStats(treeSnapshot, instanceID, timerType, applyUpdate) {
var {displayName} = treeSnapshot[instanceID];
-
var key = displayName;
var stats = aggregatedStats[key];
-
if (!stats) {
affectedIDs[key] = {};
stats = aggregatedStats[key] = {
@@ -43,7 +41,12 @@ function getExclusive(flushHistory = getFlushHistory()) {
totalDuration: 0,
};
}
-
+ if (!stats.durations[timerType]) {
+ stats.durations[timerType] = 0;
+ }
+ if (!stats.counts[timerType]) {
+ stats.counts[timerType] = 0;
+ }
affectedIDs[key][instanceID] = true;
applyUpdate(stats);
}
@@ -52,17 +55,9 @@ function getExclusive(flushHistory = getFlushHistory()) {
var {measurements, treeSnapshot} = flush;
measurements.forEach(measurement => {
var {duration, instanceID, timerType} = measurement;
- updateAggregatedStats(treeSnapshot, instanceID, stats => {
+ updateAggregatedStats(treeSnapshot, instanceID, timerType, stats => {
stats.totalDuration += duration;
-
- if (!stats.durations[timerType]) {
- stats.durations[timerType] = 0;
- }
stats.durations[timerType] += duration;
-
- if (!stats.counts[timerType]) {
- stats.counts[timerType] = 0;
- }
stats.counts[timerType]++;
});
});
@@ -73,20 +68,20 @@ function getExclusive(flushHistory = getFlushHistory()) {
...aggregatedStats[key],
instanceCount: Object.keys(affectedIDs[key]).length,
}))
- .sort((a, b) => b.totalDuration - a.totalDuration);
+ .sort((a, b) =>
+ b.totalDuration - a.totalDuration
+ );
}
-function getInclusive(flushHistory = getFlushHistory(), wastedOnly) {
+function getInclusive(flushHistory = getFlushHistory()) {
var aggregatedStats = {};
var affectedIDs = {};
function updateAggregatedStats(treeSnapshot, instanceID, applyUpdate) {
var {displayName, ownerID} = treeSnapshot[instanceID];
-
var owner = treeSnapshot[ownerID];
- var key = `${owner ? owner.displayName : '(no owner)'} > ${displayName}`;
+ var key = (owner ? owner.displayName + ' > ' : '') + displayName;
var stats = aggregatedStats[key];
-
if (!stats) {
affectedIDs[key] = {};
stats = aggregatedStats[key] = {
@@ -96,12 +91,11 @@ function getInclusive(flushHistory = getFlushHistory(), wastedOnly) {
renderCount: 0,
};
}
-
affectedIDs[key][instanceID] = true;
applyUpdate(stats);
}
- var hasRenderedByID = {};
+ var isCompositeByID = {};
flushHistory.forEach(flush => {
var {measurements} = flush;
measurements.forEach(measurement => {
@@ -109,7 +103,7 @@ function getInclusive(flushHistory = getFlushHistory(), wastedOnly) {
if (timerType !== 'render') {
return;
}
- hasRenderedByID[instanceID] = true;
+ isCompositeByID[instanceID] = true;
});
});
@@ -125,7 +119,9 @@ function getInclusive(flushHistory = getFlushHistory(), wastedOnly) {
});
var nextParentID = instanceID;
while (nextParentID) {
- if (hasRenderedByID[nextParentID]) {
+ // As we traverse parents, only count inclusive time towards composites.
+ // We know something is a composite if its render() was called.
+ if (isCompositeByID[nextParentID]) {
updateAggregatedStats(treeSnapshot, nextParentID, stats => {
stats.inclusiveRenderDuration += duration;
});
@@ -140,7 +136,9 @@ function getInclusive(flushHistory = getFlushHistory(), wastedOnly) {
...aggregatedStats[key],
instanceCount: Object.keys(affectedIDs[key]).length,
}))
- .sort((a, b) => b.inclusiveRenderDuration - a.inclusiveRenderDuration);
+ .sort((a, b) =>
+ b.inclusiveRenderDuration - a.inclusiveRenderDuration
+ );
}
function getWasted(flushHistory = getFlushHistory()) {
@@ -149,11 +147,9 @@ function getWasted(flushHistory = getFlushHistory()) {
function updateAggregatedStats(treeSnapshot, instanceID, applyUpdate) {
var {displayName, ownerID} = treeSnapshot[instanceID];
-
var owner = treeSnapshot[ownerID];
- var key = `${owner ? owner.displayName : '(no owner)'} > ${displayName}`;
+ var key = (owner ? owner.displayName + ' > ' : '') + displayName;
var stats = aggregatedStats[key];
-
if (!stats) {
affectedIDs[key] = {};
stats = aggregatedStats[key] = {
@@ -163,25 +159,27 @@ function getWasted(flushHistory = getFlushHistory()) {
renderCount: 0,
};
}
-
affectedIDs[key][instanceID] = true;
applyUpdate(stats);
}
flushHistory.forEach(flush => {
var {measurements, treeSnapshot, operations} = flush;
- var dirtyInstanceIDs = {};
+ var isDefinitelyNotWastedByID = {};
+ // Find native components associated with an operation in this batch.
+ // Mark all components in their parent tree as definitely not wasted.
operations.forEach(operation => {
var {instanceID} = operation;
-
var nextParentID = instanceID;
while (nextParentID) {
- dirtyInstanceIDs[nextParentID] = true;
+ isDefinitelyNotWastedByID[nextParentID] = true;
nextParentID = treeSnapshot[nextParentID].parentID;
}
});
+ // Find composite components that rendered in this batch.
+ // These are potential candidates for being wasted renders.
var renderedCompositeIDs = {};
measurements.forEach(measurement => {
var {instanceID, timerType} = measurement;
@@ -196,21 +194,31 @@ function getWasted(flushHistory = getFlushHistory()) {
if (timerType !== 'render') {
return;
}
+
+ // If there was a DOM update below this component, or it has just been
+ // mounted, its render() is not considered wasted.
var { updateCount } = treeSnapshot[instanceID];
- if (dirtyInstanceIDs[instanceID] || updateCount === 0) {
+ if (isDefinitelyNotWastedByID[instanceID] || updateCount === 0) {
return;
}
+
+ // We consider this render() wasted.
updateAggregatedStats(treeSnapshot, instanceID, stats => {
stats.renderCount++;
});
+
var nextParentID = instanceID;
while (nextParentID) {
- if (!renderedCompositeIDs[nextParentID]) {
- break;
+ // Any parents rendered during this batch are considered wasted
+ // unless we previously marked them as dirty.
+ var isWasted =
+ renderedCompositeIDs[nextParentID] &&
+ !isDefinitelyNotWastedByID[nextParentID];
+ if (isWasted) {
+ updateAggregatedStats(treeSnapshot, nextParentID, stats => {
+ stats.inclusiveRenderDuration += duration;
+ });
}
- updateAggregatedStats(treeSnapshot, nextParentID, stats => {
- stats.inclusiveRenderDuration += duration;
- });
nextParentID = treeSnapshot[nextParentID].parentID;
}
});
@@ -221,7 +229,9 @@ function getWasted(flushHistory = getFlushHistory()) {
...aggregatedStats[key],
instanceCount: Object.keys(affectedIDs[key]).length,
}))
- .sort((a, b) => b.inclusiveRenderDuration - a.inclusiveRenderDuration);
+ .sort((a, b) =>
+ b.inclusiveRenderDuration - a.inclusiveRenderDuration
+ );
}
function getOperations(flushHistory = getFlushHistory()) {
@@ -232,7 +242,7 @@ function getOperations(flushHistory = getFlushHistory()) {
var {instanceID, type, payload} = operation;
var {displayName, ownerID} = treeSnapshot[instanceID];
var owner = treeSnapshot[ownerID];
- var key = `${(owner ? owner.displayName : '(no owner)')} > ${displayName}`;
+ var key = (owner ? owner.displayName + ' > ' : '') + displayName;
stats.push({
flushIndex,
@@ -342,7 +352,7 @@ function stop() {
}
var ReactPerfAnalysis = {
- getFlushHistory,
+ getLastMeasurements: getFlushHistory,
getExclusive,
getInclusive,
getWasted,
diff --git a/src/test/__tests__/ReactDefaultPerf-test.js b/src/isomorphic/__tests__/ReactPerf-test.js
similarity index 63%
rename from src/test/__tests__/ReactDefaultPerf-test.js
rename to src/isomorphic/__tests__/ReactPerf-test.js
index 8019f0fe8e5..98df00938b0 100644
--- a/src/test/__tests__/ReactDefaultPerf-test.js
+++ b/src/isomorphic/__tests__/ReactPerf-test.js
@@ -11,13 +11,11 @@
'use strict';
-describe('ReactDefaultPerf', function() {
+describe('ReactPerf', function() {
var React;
var ReactDOM;
- var ReactDOMFeatureFlags;
- var ReactDefaultPerf;
+ var ReactPerf;
var ReactTestUtils;
- var ReactDefaultPerfAnalysis;
var App;
var Box;
@@ -36,10 +34,8 @@ describe('ReactDefaultPerf', function() {
React = require('React');
ReactDOM = require('ReactDOM');
- ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
- ReactDefaultPerf = require('ReactDefaultPerf');
+ ReactPerf = require('ReactPerf');
ReactTestUtils = require('ReactTestUtils');
- ReactDefaultPerfAnalysis = require('ReactDefaultPerfAnalysis');
App = React.createClass({
render: function() {
@@ -68,10 +64,10 @@ describe('ReactDefaultPerf', function() {
});
function measure(fn) {
- ReactDefaultPerf.start();
+ ReactPerf.start();
fn();
- ReactDefaultPerf.stop();
- return ReactDefaultPerf.getLastMeasurements().__unstable_this_format_will_change;
+ ReactPerf.stop();
+ return ReactPerf.getLastMeasurements();
}
it('should count no-op update as waste', function() {
@@ -81,20 +77,18 @@ describe('ReactDefaultPerf', function() {
ReactDOM.render(, container);
});
- var summary = ReactDefaultPerf.getWasted(measurements);
- expect(summary.length).toBe(2);
-
- /*eslint-disable dot-notation */
-
- expect(summary[0]['Owner > component']).toBe(' > App');
- expect(summary[0]['Wasted time (ms)']).not.toBe(0);
- expect(summary[0]['Instances']).toBe(1);
-
- expect(summary[1]['Owner > component']).toBe('App > Box');
- expect(summary[1]['Wasted time (ms)']).not.toBe(0);
- expect(summary[1]['Instances']).toBe(2);
-
- /*eslint-enable dot-notation */
+ var summary = ReactPerf.getWasted(measurements);
+ expect(summary).toEqual([{
+ key: 'App',
+ instanceCount: 1,
+ inclusiveRenderDuration: 3,
+ renderCount: 1,
+ }, {
+ key: 'App > Box',
+ instanceCount: 2,
+ inclusiveRenderDuration: 2,
+ renderCount: 2,
+ }]);
});
it('should count no-op update in child as waste', function() {
@@ -107,21 +101,18 @@ describe('ReactDefaultPerf', function() {
ReactDOM.render(, container);
});
- var summary = ReactDefaultPerf.getWasted(measurements);
- expect(summary.length).toBe(1);
-
- /*eslint-disable dot-notation */
-
- expect(summary[0]['Owner > component']).toBe('App > Box');
- expect(summary[0]['Wasted time (ms)']).not.toBe(0);
- expect(summary[0]['Instances']).toBe(1);
-
- /*eslint-enable dot-notation */
+ var summary = ReactPerf.getWasted(measurements);
+ expect(summary).toEqual([{
+ key: 'App > Box',
+ instanceCount: 1,
+ inclusiveRenderDuration: 1,
+ renderCount: 1,
+ }]);
});
function expectNoWaste(fn) {
var measurements = measure(fn);
- var summary = ReactDefaultPerf.getWasted(measurements);
+ var summary = ReactPerf.getWasted(measurements);
expect(summary).toEqual([]);
}
@@ -217,83 +208,31 @@ describe('ReactDefaultPerf', function() {
});
});
- it('putListener should not be instrumented', function() {
- var container = document.createElement('div');
- ReactDOM.render(hey
, container);
- var measurements = measure(() => {
- ReactDOM.render(hey
, container);
- });
-
- var summary = ReactDefaultPerfAnalysis.getDOMSummary(measurements);
- expect(summary).toEqual([]);
- });
-
- it('deleteListener should not be instrumented', function() {
- var container = document.createElement('div');
- ReactDOM.render(hey
, container);
- var measurements = measure(() => {
- ReactDOM.render(hey
, container);
- });
-
- var summary = ReactDefaultPerfAnalysis.getDOMSummary(measurements);
- expect(summary).toEqual([]);
- });
-
- it('should not fail on input change events', function() {
- var container = document.createElement('div');
- var onChange = () => {};
- var input = ReactDOM.render(
- ,
- container
- );
- expectNoWaste(() => {
- ReactTestUtils.Simulate.change(input);
- });
- });
-
- it('should print a table after calling printOperations', function() {
- var container = document.createElement('div');
- var measurements = measure(() => {
- ReactDOM.render(hey
, container);
- });
- spyOn(console, 'table');
- ReactDefaultPerf.printOperations(measurements);
- expect(console.table.calls.length).toBe(1);
- expect(console.table.argsForCall[0][0]).toEqual([{
- 'data-reactid': '',
- type: 'set innerHTML',
- args: ReactDOMFeatureFlags.useCreateElement ?
- '{"node":"","children":[],"html":null,"text":null}' :
- '"hey
"',
- }]);
- });
-
it('warns once when using getMeasurementsSummaryMap', function() {
var measurements = measure(() => {});
spyOn(console, 'error');
- ReactDefaultPerf.getMeasurementsSummaryMap(measurements);
+ ReactPerf.getMeasurementsSummaryMap(measurements);
expect(console.error.calls.length).toBe(1);
expect(console.error.argsForCall[0][0]).toContain(
'`ReactPerf.getMeasurementsSummaryMap(...)` is deprecated. Use ' +
'`ReactPerf.getWasted(...)` instead.'
);
- ReactDefaultPerf.getMeasurementsSummaryMap(measurements);
+ ReactPerf.getMeasurementsSummaryMap(measurements);
expect(console.error.calls.length).toBe(1);
});
it('warns once when using printDOM', function() {
var measurements = measure(() => {});
spyOn(console, 'error');
- ReactDefaultPerf.printDOM(measurements);
+ ReactPerf.printDOM(measurements);
expect(console.error.calls.length).toBe(1);
expect(console.error.argsForCall[0][0]).toContain(
'`ReactPerf.printDOM(...)` is deprecated. Use ' +
'`ReactPerf.printOperations(...)` instead.'
);
- ReactDefaultPerf.printDOM(measurements);
+ ReactPerf.printDOM(measurements);
expect(console.error.calls.length).toBe(1);
});
-
});
diff --git a/src/isomorphic/devtools/ReactComponentTreeDevtool.js b/src/isomorphic/devtools/ReactComponentTreeDevtool.js
index bdba5b378f3..57e85b39dfc 100644
--- a/src/isomorphic/devtools/ReactComponentTreeDevtool.js
+++ b/src/isomorphic/devtools/ReactComponentTreeDevtool.js
@@ -25,6 +25,7 @@ function updateTree(id, update) {
childIDs: [],
displayName: 'Unknown',
isMounted: false,
+ updateCount: 0,
};
}
update(tree[id]);
@@ -95,6 +96,10 @@ var ReactComponentTreeDevtool = {
rootIDs.push(id);
},
+ onUpdateComponent(id) {
+ updateTree(id, item => item.updateCount++);
+ },
+
onUnmountComponent(id) {
updateTree(id, item => item.isMounted = false);
rootIDs = rootIDs.filter(rootID => rootID !== id);
@@ -136,6 +141,11 @@ var ReactComponentTreeDevtool = {
return item ? item.text : null;
},
+ getUpdateCount(id) {
+ var item = tree[id];
+ return item ? item.updateCount : 0;
+ },
+
getRootIDs() {
return rootIDs;
},
diff --git a/src/isomorphic/devtools/__tests__/ReactComponentTreeDevtool-test.js b/src/isomorphic/devtools/__tests__/ReactComponentTreeDevtool-test.js
index 2ff1a58abb8..106307d0d25 100644
--- a/src/isomorphic/devtools/__tests__/ReactComponentTreeDevtool-test.js
+++ b/src/isomorphic/devtools/__tests__/ReactComponentTreeDevtool-test.js
@@ -1697,6 +1697,31 @@ describe('ReactComponentTreeDevtool', () => {
});
});
+ it('reports update counts', () => {
+ var node = document.createElement('div');
+
+ ReactDOM.render(, node);
+ var divID = ReactComponentTreeDevtool.getRootIDs()[0];
+ expect(ReactComponentTreeDevtool.getUpdateCount(divID)).toEqual(0);
+
+ ReactDOM.render(, node);
+ var spanID = ReactComponentTreeDevtool.getRootIDs()[0];
+ expect(ReactComponentTreeDevtool.getUpdateCount(divID)).toEqual(0);
+ expect(ReactComponentTreeDevtool.getUpdateCount(spanID)).toEqual(0);
+
+ ReactDOM.render(, node);
+ expect(ReactComponentTreeDevtool.getUpdateCount(divID)).toEqual(0);
+ expect(ReactComponentTreeDevtool.getUpdateCount(spanID)).toEqual(1);
+
+ ReactDOM.render(, node);
+ expect(ReactComponentTreeDevtool.getUpdateCount(divID)).toEqual(0);
+ expect(ReactComponentTreeDevtool.getUpdateCount(spanID)).toEqual(2);
+
+ ReactDOM.unmountComponentAtNode(node);
+ expect(ReactComponentTreeDevtool.getUpdateCount(divID)).toEqual(0);
+ expect(ReactComponentTreeDevtool.getUpdateCount(spanID)).toEqual(2);
+ });
+
it('does not report top-level wrapper as a root', () => {
var node = document.createElement('div');
diff --git a/src/isomorphic/devtools/__tests__/ReactComponentTreeDevtool-test.native.js b/src/isomorphic/devtools/__tests__/ReactComponentTreeDevtool-test.native.js
index 4da93ab911a..3113d6fcad8 100644
--- a/src/isomorphic/devtools/__tests__/ReactComponentTreeDevtool-test.native.js
+++ b/src/isomorphic/devtools/__tests__/ReactComponentTreeDevtool-test.native.js
@@ -1685,6 +1685,29 @@ describe('ReactComponentTreeDevtool', () => {
});
});
+ it('reports update counts', () => {
+ ReactNative.render(, 1);
+ var viewID = ReactComponentTreeDevtool.getRootIDs()[0];
+ expect(ReactComponentTreeDevtool.getUpdateCount(viewID)).toEqual(0);
+
+ ReactNative.render(, 1);
+ var imageID = ReactComponentTreeDevtool.getRootIDs()[0];
+ expect(ReactComponentTreeDevtool.getUpdateCount(viewID)).toEqual(0);
+ expect(ReactComponentTreeDevtool.getUpdateCount(imageID)).toEqual(0);
+
+ ReactNative.render(, 1);
+ expect(ReactComponentTreeDevtool.getUpdateCount(viewID)).toEqual(0);
+ expect(ReactComponentTreeDevtool.getUpdateCount(imageID)).toEqual(1);
+
+ ReactNative.render(, 1);
+ expect(ReactComponentTreeDevtool.getUpdateCount(viewID)).toEqual(0);
+ expect(ReactComponentTreeDevtool.getUpdateCount(imageID)).toEqual(2);
+
+ ReactNative.unmountComponentAtNode(1);
+ expect(ReactComponentTreeDevtool.getUpdateCount(viewID)).toEqual(0);
+ expect(ReactComponentTreeDevtool.getUpdateCount(imageID)).toEqual(2);
+ });
+
it('does not report top-level wrapper as a root', () => {
ReactNative.render(, 1);
expect(getRootDisplayNames()).toEqual(['View']);
diff --git a/src/renderers/dom/ReactDOM.js b/src/renderers/dom/ReactDOM.js
index 75644b1209d..7e7fbe46397 100644
--- a/src/renderers/dom/ReactDOM.js
+++ b/src/renderers/dom/ReactDOM.js
@@ -16,7 +16,6 @@
var ReactDOMComponentTree = require('ReactDOMComponentTree');
var ReactDefaultInjection = require('ReactDefaultInjection');
var ReactMount = require('ReactMount');
-var ReactPerf = require('ReactPerf');
var ReactReconciler = require('ReactReconciler');
var ReactUpdates = require('ReactUpdates');
var ReactVersion = require('ReactVersion');
@@ -28,11 +27,9 @@ var warning = require('warning');
ReactDefaultInjection.inject();
-var render = ReactPerf.measure('React', 'render', ReactMount.render);
-
var React = {
findDOMNode: findDOMNode,
- render: render,
+ render: ReactMount.render,
unmountComponentAtNode: ReactMount.unmountComponentAtNode,
version: ReactVersion,
diff --git a/src/renderers/dom/client/ReactDOMIDOperations.js b/src/renderers/dom/client/ReactDOMIDOperations.js
index cb03d3f06ad..fd8c16797b1 100644
--- a/src/renderers/dom/client/ReactDOMIDOperations.js
+++ b/src/renderers/dom/client/ReactDOMIDOperations.js
@@ -13,7 +13,6 @@
var DOMChildrenOperations = require('DOMChildrenOperations');
var ReactDOMComponentTree = require('ReactDOMComponentTree');
-var ReactPerf = require('ReactPerf');
/**
* Operations used to process updates to DOM nodes.
@@ -32,8 +31,4 @@ var ReactDOMIDOperations = {
},
};
-ReactPerf.measureMethods(ReactDOMIDOperations, 'ReactDOMIDOperations', {
- dangerouslyProcessChildrenUpdates: 'dangerouslyProcessChildrenUpdates',
-});
-
module.exports = ReactDOMIDOperations;
diff --git a/src/renderers/dom/client/ReactMount.js b/src/renderers/dom/client/ReactMount.js
index 564edc7e1a3..eebc607c131 100644
--- a/src/renderers/dom/client/ReactMount.js
+++ b/src/renderers/dom/client/ReactMount.js
@@ -22,7 +22,6 @@ var ReactElement = require('ReactElement');
var ReactFeatureFlags = require('ReactFeatureFlags');
var ReactInstrumentation = require('ReactInstrumentation');
var ReactMarkupChecksum = require('ReactMarkupChecksum');
-var ReactPerf = require('ReactPerf');
var ReactReconciler = require('ReactReconciler');
var ReactUpdateQueue = require('ReactUpdateQueue');
var ReactUpdates = require('ReactUpdates');
@@ -711,9 +710,4 @@ var ReactMount = {
},
};
-ReactPerf.measureMethods(ReactMount, 'ReactMount', {
- _renderNewRootComponent: '_renderNewRootComponent',
- _mountImageIntoNode: '_mountImageIntoNode',
-});
-
module.exports = ReactMount;
diff --git a/src/renderers/dom/client/utils/DOMChildrenOperations.js b/src/renderers/dom/client/utils/DOMChildrenOperations.js
index 3072a8d5b5e..303cd94b305 100644
--- a/src/renderers/dom/client/utils/DOMChildrenOperations.js
+++ b/src/renderers/dom/client/utils/DOMChildrenOperations.js
@@ -16,7 +16,6 @@ var Danger = require('Danger');
var ReactMultiChildUpdateTypes = require('ReactMultiChildUpdateTypes');
var ReactDOMComponentTree = require('ReactDOMComponentTree');
var ReactInstrumentation = require('ReactInstrumentation');
-var ReactPerf = require('ReactPerf');
var createMicrosoftUnsafeLocalFunction = require('createMicrosoftUnsafeLocalFunction');
var setInnerHTML = require('setInnerHTML');
@@ -239,8 +238,4 @@ var DOMChildrenOperations = {
};
-ReactPerf.measureMethods(DOMChildrenOperations, 'DOMChildrenOperations', {
- replaceDelimitedText: 'replaceDelimitedText',
-});
-
module.exports = DOMChildrenOperations;
diff --git a/src/renderers/dom/shared/CSSPropertyOperations.js b/src/renderers/dom/shared/CSSPropertyOperations.js
index 721fb72a0f2..4a16d050e6a 100644
--- a/src/renderers/dom/shared/CSSPropertyOperations.js
+++ b/src/renderers/dom/shared/CSSPropertyOperations.js
@@ -14,7 +14,6 @@
var CSSProperty = require('CSSProperty');
var ExecutionEnvironment = require('ExecutionEnvironment');
var ReactInstrumentation = require('ReactInstrumentation');
-var ReactPerf = require('ReactPerf');
var camelizeStyleName = require('camelizeStyleName');
var dangerousStyleValue = require('dangerousStyleValue');
@@ -238,8 +237,4 @@ var CSSPropertyOperations = {
};
-ReactPerf.measureMethods(CSSPropertyOperations, 'CSSPropertyOperations', {
- setValueForStyles: 'setValueForStyles',
-});
-
module.exports = CSSPropertyOperations;
diff --git a/src/renderers/dom/shared/DOMPropertyOperations.js b/src/renderers/dom/shared/DOMPropertyOperations.js
index 9c67c50cfbf..eee9647ef62 100644
--- a/src/renderers/dom/shared/DOMPropertyOperations.js
+++ b/src/renderers/dom/shared/DOMPropertyOperations.js
@@ -15,7 +15,6 @@ var DOMProperty = require('DOMProperty');
var ReactDOMComponentTree = require('ReactDOMComponentTree');
var ReactDOMInstrumentation = require('ReactDOMInstrumentation');
var ReactInstrumentation = require('ReactInstrumentation');
-var ReactPerf = require('ReactPerf');
var quoteAttributeValueForBrowser = require('quoteAttributeValueForBrowser');
var warning = require('warning');
@@ -250,10 +249,4 @@ var DOMPropertyOperations = {
};
-ReactPerf.measureMethods(DOMPropertyOperations, 'DOMPropertyOperations', {
- setValueForProperty: 'setValueForProperty',
- setValueForAttribute: 'setValueForAttribute',
- deleteValueForProperty: 'deleteValueForProperty',
-});
-
module.exports = DOMPropertyOperations;
diff --git a/src/renderers/dom/shared/ReactComponentBrowserEnvironment.js b/src/renderers/dom/shared/ReactComponentBrowserEnvironment.js
index cf5df870d39..112c7d6241f 100644
--- a/src/renderers/dom/shared/ReactComponentBrowserEnvironment.js
+++ b/src/renderers/dom/shared/ReactComponentBrowserEnvironment.js
@@ -13,7 +13,6 @@
var DOMChildrenOperations = require('DOMChildrenOperations');
var ReactDOMIDOperations = require('ReactDOMIDOperations');
-var ReactPerf = require('ReactPerf');
/**
* Abstracts away all functionality of the reconciler that requires knowledge of
@@ -40,12 +39,4 @@ var ReactComponentBrowserEnvironment = {
};
-ReactPerf.measureMethods(
- ReactComponentBrowserEnvironment,
- 'ReactComponentBrowserEnvironment',
- {
- replaceNodeWithMarkup: 'replaceNodeWithMarkup',
- }
-);
-
module.exports = ReactComponentBrowserEnvironment;
diff --git a/src/renderers/dom/shared/ReactDOMComponent.js b/src/renderers/dom/shared/ReactDOMComponent.js
index 396371fb15c..b8fea43a024 100644
--- a/src/renderers/dom/shared/ReactDOMComponent.js
+++ b/src/renderers/dom/shared/ReactDOMComponent.js
@@ -34,7 +34,6 @@ var ReactDOMSelect = require('ReactDOMSelect');
var ReactDOMTextarea = require('ReactDOMTextarea');
var ReactInstrumentation = require('ReactInstrumentation');
var ReactMultiChild = require('ReactMultiChild');
-var ReactPerf = require('ReactPerf');
var ReactServerRenderingTransaction = require('ReactServerRenderingTransaction');
var emptyFunction = require('emptyFunction');
@@ -1129,11 +1128,6 @@ ReactDOMComponent.Mixin = {
};
-ReactPerf.measureMethods(ReactDOMComponent.Mixin, 'ReactDOMComponent', {
- mountComponent: 'mountComponent',
- receiveComponent: 'receiveComponent',
-});
-
Object.assign(
ReactDOMComponent.prototype,
ReactDOMComponent.Mixin,
diff --git a/src/renderers/dom/shared/ReactDOMTextComponent.js b/src/renderers/dom/shared/ReactDOMTextComponent.js
index 97ed919d78e..a46c188930f 100644
--- a/src/renderers/dom/shared/ReactDOMTextComponent.js
+++ b/src/renderers/dom/shared/ReactDOMTextComponent.js
@@ -15,7 +15,6 @@ var DOMChildrenOperations = require('DOMChildrenOperations');
var DOMLazyTree = require('DOMLazyTree');
var ReactDOMComponentTree = require('ReactDOMComponentTree');
var ReactInstrumentation = require('ReactInstrumentation');
-var ReactPerf = require('ReactPerf');
var escapeTextContentForBrowser = require('escapeTextContentForBrowser');
var invariant = require('invariant');
@@ -188,13 +187,4 @@ Object.assign(ReactDOMTextComponent.prototype, {
});
-ReactPerf.measureMethods(
- ReactDOMTextComponent.prototype,
- 'ReactDOMTextComponent',
- {
- mountComponent: 'mountComponent',
- receiveComponent: 'receiveComponent',
- }
-);
-
module.exports = ReactDOMTextComponent;
diff --git a/src/renderers/dom/shared/ReactDefaultInjection.js b/src/renderers/dom/shared/ReactDefaultInjection.js
index 09cbf25e485..f71a9b9dab5 100644
--- a/src/renderers/dom/shared/ReactDefaultInjection.js
+++ b/src/renderers/dom/shared/ReactDefaultInjection.js
@@ -15,7 +15,6 @@ var BeforeInputEventPlugin = require('BeforeInputEventPlugin');
var ChangeEventPlugin = require('ChangeEventPlugin');
var DefaultEventPluginOrder = require('DefaultEventPluginOrder');
var EnterLeaveEventPlugin = require('EnterLeaveEventPlugin');
-var ExecutionEnvironment = require('ExecutionEnvironment');
var HTMLDOMPropertyConfig = require('HTMLDOMPropertyConfig');
var ReactComponentBrowserEnvironment =
require('ReactComponentBrowserEnvironment');
@@ -91,14 +90,6 @@ function inject() {
);
ReactInjection.Component.injectEnvironment(ReactComponentBrowserEnvironment);
-
- if (__DEV__) {
- var url = (ExecutionEnvironment.canUseDOM && window.location.href) || '';
- if ((/[?&]react_perf\b/).test(url)) {
- var ReactDefaultPerf = require('ReactDefaultPerf');
- ReactDefaultPerf.start();
- }
- }
}
module.exports = {
diff --git a/src/renderers/dom/shared/ReactInjection.js b/src/renderers/dom/shared/ReactInjection.js
index 26085eb2f73..51fb065518a 100644
--- a/src/renderers/dom/shared/ReactInjection.js
+++ b/src/renderers/dom/shared/ReactInjection.js
@@ -19,7 +19,6 @@ var ReactClass = require('ReactClass');
var ReactEmptyComponent = require('ReactEmptyComponent');
var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter');
var ReactNativeComponent = require('ReactNativeComponent');
-var ReactPerf = require('ReactPerf');
var ReactUpdates = require('ReactUpdates');
var ReactInjection = {
@@ -31,7 +30,6 @@ var ReactInjection = {
EventPluginUtils: EventPluginUtils.injection,
EventEmitter: ReactBrowserEventEmitter.injection,
NativeComponent: ReactNativeComponent.injection,
- Perf: ReactPerf.injection,
Updates: ReactUpdates.injection,
};
diff --git a/src/renderers/native/ReactNativeDOMIDOperations.js b/src/renderers/native/ReactNativeDOMIDOperations.js
index 0bb92fef552..8d07d2d6abc 100644
--- a/src/renderers/native/ReactNativeDOMIDOperations.js
+++ b/src/renderers/native/ReactNativeDOMIDOperations.js
@@ -13,7 +13,6 @@
var ReactNativeComponentTree = require('ReactNativeComponentTree');
var ReactMultiChildUpdateTypes = require('ReactMultiChildUpdateTypes');
-var ReactPerf = require('ReactPerf');
var UIManager = require('UIManager');
/**
@@ -71,12 +70,7 @@ var dangerouslyProcessChildrenUpdates = function(inst, childrenUpdates) {
* `ReactComponent.DOMIDOperations`.
*/
var ReactNativeDOMIDOperations = {
- dangerouslyProcessChildrenUpdates: ReactPerf.measure(
- // FIXME(frantic): #4441289 Hack to avoid modifying react-tools
- 'ReactDOMIDOperations',
- 'dangerouslyProcessChildrenUpdates',
- dangerouslyProcessChildrenUpdates
- ),
+ dangerouslyProcessChildrenUpdates,
/**
* Replaces a view that exists in the document with markup.
@@ -84,14 +78,10 @@ var ReactNativeDOMIDOperations = {
* @param {string} id ID of child to be replaced.
* @param {string} markup Mount image to replace child with id.
*/
- dangerouslyReplaceNodeWithMarkupByID: ReactPerf.measure(
- 'ReactDOMIDOperations',
- 'dangerouslyReplaceNodeWithMarkupByID',
- function(id, mountImage) {
- var oldTag = id;
- UIManager.replaceExistingNonRootView(oldTag, mountImage);
- }
- ),
+ dangerouslyReplaceNodeWithMarkupByID: function(id, mountImage) {
+ var oldTag = id;
+ UIManager.replaceExistingNonRootView(oldTag, mountImage);
+ },
};
module.exports = ReactNativeDOMIDOperations;
diff --git a/src/renderers/native/ReactNativeMount.js b/src/renderers/native/ReactNativeMount.js
index 6800b49cb9a..cb4880e0d51 100644
--- a/src/renderers/native/ReactNativeMount.js
+++ b/src/renderers/native/ReactNativeMount.js
@@ -15,7 +15,6 @@ var ReactElement = require('ReactElement');
var ReactInstrumentation = require('ReactInstrumentation');
var ReactNativeContainerInfo = require('ReactNativeContainerInfo');
var ReactNativeTagHandles = require('ReactNativeTagHandles');
-var ReactPerf = require('ReactPerf');
var ReactReconciler = require('ReactReconciler');
var ReactUpdateQueue = require('ReactUpdateQueue');
var ReactUpdates = require('ReactUpdates');
@@ -143,6 +142,10 @@ var ReactNativeMount = {
// Mute future events from the top level wrapper.
// It is an implementation detail that devtools should not know about.
instance._debugID = 0;
+
+ if (__DEV__) {
+ ReactInstrumentation.debugTool.onBeginFlush();
+ }
}
// The initial render is synchronous but any updates that happen during
@@ -159,6 +162,7 @@ var ReactNativeMount = {
ReactInstrumentation.debugTool.onMountRootComponent(
instance._renderedComponent._debugID
);
+ ReactInstrumentation.debugTool.onEndFlush();
}
var component = instance.getPublicInstance();
if (callback) {
@@ -171,20 +175,15 @@ var ReactNativeMount = {
* @param {View} view View tree image.
* @param {number} containerViewID View to insert sub-view into.
*/
- _mountImageIntoNode: ReactPerf.measure(
- // FIXME(frantic): #4441289 Hack to avoid modifying react-tools
- 'ReactComponentBrowserEnvironment',
- 'mountImageIntoNode',
- function(mountImage, containerID) {
- // Since we now know that the `mountImage` has been mounted, we can
- // mark it as such.
- var childTag = mountImage;
- UIManager.setChildren(
- containerID,
- [childTag]
- );
- }
- ),
+ _mountImageIntoNode: function(mountImage, containerID) {
+ // Since we now know that the `mountImage` has been mounted, we can
+ // mark it as such.
+ var childTag = mountImage;
+ UIManager.setChildren(
+ containerID,
+ [childTag]
+ );
+ },
/**
* Standard unmounting of the component that is rendered into `containerID`,
@@ -242,10 +241,4 @@ var ReactNativeMount = {
};
-ReactNativeMount.renderComponent = ReactPerf.measure(
- 'ReactMount',
- '_renderNewRootComponent',
- ReactNativeMount.renderComponent
-);
-
module.exports = ReactNativeMount;
diff --git a/src/renderers/shared/reconciler/ReactCompositeComponent.js b/src/renderers/shared/reconciler/ReactCompositeComponent.js
index f1835938b96..120e5900a45 100644
--- a/src/renderers/shared/reconciler/ReactCompositeComponent.js
+++ b/src/renderers/shared/reconciler/ReactCompositeComponent.js
@@ -18,7 +18,6 @@ var ReactErrorUtils = require('ReactErrorUtils');
var ReactInstanceMap = require('ReactInstanceMap');
var ReactInstrumentation = require('ReactInstrumentation');
var ReactNodeTypes = require('ReactNodeTypes');
-var ReactPerf = require('ReactPerf');
var ReactPropTypeLocations = require('ReactPropTypeLocations');
var ReactPropTypeLocationNames = require('ReactPropTypeLocationNames');
var ReactReconciler = require('ReactReconciler');
@@ -395,7 +394,7 @@ var ReactCompositeComponentMixin = {
instanceOrElement = Component(publicProps, publicContext, ReactUpdateQueue);
if (__DEV__) {
if (this._debugID !== 0) {
- ReactInstrumentation.debugTool.onBeginLifeCycleTimer(
+ ReactInstrumentation.debugTool.onEndLifeCycleTimer(
this._debugID,
'render'
);
@@ -1210,16 +1209,6 @@ var ReactCompositeComponentMixin = {
};
-ReactPerf.measureMethods(
- ReactCompositeComponentMixin,
- 'ReactCompositeComponent',
- {
- mountComponent: 'mountComponent',
- updateComponent: 'updateComponent',
- _renderValidatedComponent: '_renderValidatedComponent',
- }
-);
-
var ReactCompositeComponent = {
Mixin: ReactCompositeComponentMixin,
diff --git a/src/renderers/shared/reconciler/ReactUpdates.js b/src/renderers/shared/reconciler/ReactUpdates.js
index 225d7c50f89..d8471372b7f 100644
--- a/src/renderers/shared/reconciler/ReactUpdates.js
+++ b/src/renderers/shared/reconciler/ReactUpdates.js
@@ -15,7 +15,6 @@ var CallbackQueue = require('CallbackQueue');
var PooledClass = require('PooledClass');
var ReactFeatureFlags = require('ReactFeatureFlags');
var ReactInstrumentation = require('ReactInstrumentation');
-var ReactPerf = require('ReactPerf');
var ReactReconciler = require('ReactReconciler');
var Transaction = require('Transaction');
@@ -222,11 +221,6 @@ var flushBatchedUpdates = function() {
ReactInstrumentation.debugTool.onEndFlush();
}
};
-flushBatchedUpdates = ReactPerf.measure(
- 'ReactUpdates',
- 'flushBatchedUpdates',
- flushBatchedUpdates
-);
/**
* Mark a component as needing a rerender, adding an optional callback to a
diff --git a/src/test/ReactDefaultPerf.js b/src/test/ReactDefaultPerf.js
deleted file mode 100644
index 5cb43e9048e..00000000000
--- a/src/test/ReactDefaultPerf.js
+++ /dev/null
@@ -1,361 +0,0 @@
-/**
- * Copyright 2013-present, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactDefaultPerf
- */
-
-'use strict';
-
-var DOMProperty = require('DOMProperty');
-var ReactDOMComponentTree = require('ReactDOMComponentTree');
-var ReactDefaultPerfAnalysis = require('ReactDefaultPerfAnalysis');
-var ReactMount = require('ReactMount');
-var ReactPerf = require('ReactPerf');
-
-var performanceNow = require('performanceNow');
-var warning = require('warning');
-
-function roundFloat(val) {
- return Math.floor(val * 100) / 100;
-}
-
-function addValue(obj, key, val) {
- obj[key] = (obj[key] || 0) + val;
-}
-
-// Composite/text components don't have any built-in ID: we have to make our own
-var compositeIDMap;
-var compositeIDCounter = 17000;
-function getIDOfComposite(inst) {
- if (!compositeIDMap) {
- compositeIDMap = new WeakMap();
- }
- if (compositeIDMap.has(inst)) {
- return compositeIDMap.get(inst);
- } else {
- var id = compositeIDCounter++;
- compositeIDMap.set(inst, id);
- return id;
- }
-}
-
-function getID(inst) {
- if (inst.hasOwnProperty('_rootNodeID')) {
- return inst._rootNodeID;
- } else {
- return getIDOfComposite(inst);
- }
-}
-
-function stripComplexValues(key, value) {
- if (typeof value !== 'object' || Array.isArray(value) || value == null) {
- return value;
- }
- var prototype = Object.getPrototypeOf(value);
- if (!prototype || prototype === Object.prototype) {
- return value;
- }
- return '';
-}
-
-// This implementation of ReactPerf is going away some time mid 15.x.
-// While we plan to keep most of the API, the actual format of measurements
-// will change dramatically. To signal this, we wrap them into an opaque-ish
-// object to discourage reaching into it until the API stabilizes.
-function wrapLegacyMeasurements(measurements) {
- return { __unstable_this_format_will_change: measurements };
-}
-function unwrapLegacyMeasurements(measurements) {
- return measurements && measurements.__unstable_this_format_will_change || measurements;
-}
-
-var warnedAboutPrintDOM = false;
-var warnedAboutGetMeasurementsSummaryMap = false;
-
-var ReactDefaultPerf = {
- _allMeasurements: [], // last item in the list is the current one
- _mountStack: [0],
- _compositeStack: [],
- _injected: false,
-
- start: function() {
- if (!ReactDefaultPerf._injected) {
- ReactPerf.injection.injectMeasure(ReactDefaultPerf.measure);
- }
-
- ReactDefaultPerf._allMeasurements.length = 0;
- ReactPerf.enableMeasure = true;
- },
-
- stop: function() {
- ReactPerf.enableMeasure = false;
- },
-
- getLastMeasurements: function() {
- return wrapLegacyMeasurements(ReactDefaultPerf._allMeasurements);
- },
-
- printExclusive: function(measurements) {
- measurements = unwrapLegacyMeasurements(measurements || ReactDefaultPerf._allMeasurements);
- var summary = ReactDefaultPerfAnalysis.getExclusiveSummary(measurements);
- console.table(summary.map(function(item) {
- return {
- 'Component class name': item.componentName,
- 'Total inclusive time (ms)': roundFloat(item.inclusive),
- 'Exclusive mount time (ms)': roundFloat(item.exclusive),
- 'Exclusive render time (ms)': roundFloat(item.render),
- 'Mount time per instance (ms)': roundFloat(item.exclusive / item.count),
- 'Render time per instance (ms)': roundFloat(item.render / item.count),
- 'Instances': item.count,
- };
- }));
- // TODO: ReactDefaultPerfAnalysis.getTotalTime() does not return the correct
- // number.
- },
-
- printInclusive: function(measurements) {
- measurements = unwrapLegacyMeasurements(measurements || ReactDefaultPerf._allMeasurements);
- var summary = ReactDefaultPerfAnalysis.getInclusiveSummary(measurements);
- console.table(summary.map(function(item) {
- return {
- 'Owner > component': item.componentName,
- 'Inclusive time (ms)': roundFloat(item.time),
- 'Instances': item.count,
- };
- }));
- console.log(
- 'Total time:',
- ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms'
- );
- },
-
- getMeasurementsSummaryMap: function(measurements) {
- warning(
- warnedAboutGetMeasurementsSummaryMap,
- '`ReactPerf.getMeasurementsSummaryMap(...)` is deprecated. Use ' +
- '`ReactPerf.getWasted(...)` instead.'
- );
- warnedAboutGetMeasurementsSummaryMap = true;
- return ReactDefaultPerf.getWasted(measurements);
- },
-
- getWasted: function(measurements) {
- measurements = unwrapLegacyMeasurements(measurements);
- var summary = ReactDefaultPerfAnalysis.getInclusiveSummary(
- measurements,
- true
- );
- return summary.map(function(item) {
- return {
- 'Owner > component': item.componentName,
- 'Wasted time (ms)': item.time,
- 'Instances': item.count,
- };
- });
- },
-
- printWasted: function(measurements) {
- measurements = unwrapLegacyMeasurements(measurements || ReactDefaultPerf._allMeasurements);
- console.table(ReactDefaultPerf.getWasted(measurements));
- console.log(
- 'Total time:',
- ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms'
- );
- },
-
- printDOM: function(measurements) {
- warning(
- warnedAboutPrintDOM,
- '`ReactPerf.printDOM(...)` is deprecated. Use ' +
- '`ReactPerf.printOperations(...)` instead.'
- );
- warnedAboutPrintDOM = true;
- return ReactDefaultPerf.printOperations(measurements);
- },
-
- printOperations: function(measurements) {
- measurements = unwrapLegacyMeasurements(measurements || ReactDefaultPerf._allMeasurements);
- var summary = ReactDefaultPerfAnalysis.getDOMSummary(measurements);
- console.table(summary.map(function(item) {
- var result = {};
- result[DOMProperty.ID_ATTRIBUTE_NAME] = item.id;
- result.type = item.type;
- result.args = JSON.stringify(item.args, stripComplexValues);
- return result;
- }));
- console.log(
- 'Total time:',
- ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms'
- );
- },
-
- _recordWrite: function(id, fnName, totalTime, args) {
- // TODO: totalTime isn't that useful since it doesn't count paints/reflows
- var entry =
- ReactDefaultPerf
- ._allMeasurements[ReactDefaultPerf._allMeasurements.length - 1];
- var writes = entry.writes;
- writes[id] = writes[id] || [];
- writes[id].push({
- type: fnName,
- time: totalTime,
- args: args,
- });
- },
-
- measure: function(moduleName, fnName, func) {
- return function(...args) {
- var totalTime;
- var rv;
- var start;
-
- var entry = ReactDefaultPerf._allMeasurements[
- ReactDefaultPerf._allMeasurements.length - 1
- ];
-
- if (fnName === '_renderNewRootComponent' ||
- fnName === 'flushBatchedUpdates') {
- // A "measurement" is a set of metrics recorded for each flush. We want
- // to group the metrics for a given flush together so we can look at the
- // components that rendered and the DOM operations that actually
- // happened to determine the amount of "wasted work" performed.
- ReactDefaultPerf._allMeasurements.push(entry = {
- exclusive: {},
- inclusive: {},
- render: {},
- counts: {},
- writes: {},
- displayNames: {},
- hierarchy: {},
- totalTime: 0,
- created: {},
- });
- start = performanceNow();
- rv = func.apply(this, args);
- entry.totalTime = performanceNow() - start;
- return rv;
- } else if (fnName === '_mountImageIntoNode' ||
- moduleName === 'ReactDOMIDOperations' ||
- moduleName === 'CSSPropertyOperations' ||
- moduleName === 'DOMChildrenOperations' ||
- moduleName === 'DOMPropertyOperations' ||
- moduleName === 'ReactComponentBrowserEnvironment') {
- start = performanceNow();
- rv = func.apply(this, args);
- totalTime = performanceNow() - start;
-
- if (fnName === '_mountImageIntoNode') {
- ReactDefaultPerf._recordWrite('', fnName, totalTime, args[0]);
- } else if (fnName === 'dangerouslyProcessChildrenUpdates') {
- // special format
- args[1].forEach(function(update) {
- var writeArgs = {};
- if (update.fromIndex !== null) {
- writeArgs.fromIndex = update.fromIndex;
- }
- if (update.toIndex !== null) {
- writeArgs.toIndex = update.toIndex;
- }
- if (update.content !== null) {
- writeArgs.content = update.content;
- }
- ReactDefaultPerf._recordWrite(
- args[0]._rootNodeID,
- update.type,
- totalTime,
- writeArgs
- );
- });
- } else {
- // basic format
- var id = args[0];
- if (moduleName === 'EventPluginHub') {
- id = id._rootNodeID;
- } else if (fnName === 'replaceNodeWithMarkup') {
- // Old node is already unmounted; can't get its instance
- id = ReactDOMComponentTree.getInstanceFromNode(args[1].node)._rootNodeID;
- } else if (fnName === 'replaceDelimitedText') {
- id = getID(ReactDOMComponentTree.getInstanceFromNode(args[0]));
- } else if (typeof id === 'object') {
- id = getID(ReactDOMComponentTree.getInstanceFromNode(args[0]));
- }
- ReactDefaultPerf._recordWrite(
- id,
- fnName,
- totalTime,
- Array.prototype.slice.call(args, 1)
- );
- }
- return rv;
- } else if (moduleName === 'ReactCompositeComponent' && (
- fnName === 'mountComponent' ||
- fnName === 'updateComponent' || // TODO: receiveComponent()?
- fnName === '_renderValidatedComponent')) {
-
- if (this._currentElement.type === ReactMount.TopLevelWrapper) {
- return func.apply(this, args);
- }
-
- var rootNodeID = getIDOfComposite(this);
- var isRender = fnName === '_renderValidatedComponent';
- var isMount = fnName === 'mountComponent';
-
- var mountStack = ReactDefaultPerf._mountStack;
-
- if (isRender) {
- addValue(entry.counts, rootNodeID, 1);
- } else if (isMount) {
- entry.created[rootNodeID] = true;
- mountStack.push(0);
- }
-
- ReactDefaultPerf._compositeStack.push(rootNodeID);
-
- start = performanceNow();
- rv = func.apply(this, args);
- totalTime = performanceNow() - start;
-
- ReactDefaultPerf._compositeStack.pop();
-
- if (isRender) {
- addValue(entry.render, rootNodeID, totalTime);
- } else if (isMount) {
- var subMountTime = mountStack.pop();
- mountStack[mountStack.length - 1] += totalTime;
- addValue(entry.exclusive, rootNodeID, totalTime - subMountTime);
- addValue(entry.inclusive, rootNodeID, totalTime);
- } else {
- addValue(entry.inclusive, rootNodeID, totalTime);
- }
-
- entry.displayNames[rootNodeID] = {
- current: this.getName(),
- owner: this._currentElement._owner ?
- this._currentElement._owner.getName() :
- '',
- };
-
- return rv;
- } else if (
- (moduleName === 'ReactDOMComponent' ||
- moduleName === 'ReactDOMTextComponent') &&
- (fnName === 'mountComponent' ||
- fnName === 'receiveComponent')) {
-
- rv = func.apply(this, args);
- entry.hierarchy[getID(this)] =
- ReactDefaultPerf._compositeStack.slice();
- return rv;
- } else {
- return func.apply(this, args);
- }
- };
- },
-};
-
-module.exports = ReactDefaultPerf;
diff --git a/src/test/ReactDefaultPerfAnalysis.js b/src/test/ReactDefaultPerfAnalysis.js
deleted file mode 100644
index bb5a35e2d0e..00000000000
--- a/src/test/ReactDefaultPerfAnalysis.js
+++ /dev/null
@@ -1,214 +0,0 @@
-/**
- * Copyright 2013-present, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactDefaultPerfAnalysis
- */
-
-'use strict';
-
-
-// Don't try to save users less than 1.2ms (a number I made up)
-var DONT_CARE_THRESHOLD = 1.2;
-var DOM_OPERATION_TYPES = {
- '_mountImageIntoNode': 'set innerHTML',
- INSERT_MARKUP: 'set innerHTML',
- MOVE_EXISTING: 'move',
- REMOVE_NODE: 'remove',
- SET_MARKUP: 'set innerHTML',
- TEXT_CONTENT: 'set textContent',
- 'setValueForProperty': 'update attribute',
- 'setValueForAttribute': 'update attribute',
- 'deleteValueForProperty': 'remove attribute',
- 'setValueForStyles': 'update styles',
- 'replaceNodeWithMarkup': 'replace',
- 'replaceDelimitedText': 'replace',
-};
-
-function getTotalTime(measurements) {
- // TODO: return number of DOM ops? could be misleading.
- // TODO: measure dropped frames after reconcile?
- // TODO: log total time of each reconcile and the top-level component
- // class that triggered it.
- var totalTime = 0;
- for (var i = 0; i < measurements.length; i++) {
- var measurement = measurements[i];
- totalTime += measurement.totalTime;
- }
- return totalTime;
-}
-
-function getDOMSummary(measurements) {
- var items = [];
- measurements.forEach(function(measurement) {
- Object.keys(measurement.writes).forEach(function(id) {
- measurement.writes[id].forEach(function(write) {
- items.push({
- id: id,
- type: DOM_OPERATION_TYPES[write.type] || write.type,
- args: write.args,
- });
- });
- });
- });
- return items;
-}
-
-function getExclusiveSummary(measurements) {
- var candidates = {};
- var displayName;
-
- for (var i = 0; i < measurements.length; i++) {
- var measurement = measurements[i];
- var allIDs = Object.assign(
- {},
- measurement.exclusive,
- measurement.inclusive
- );
-
- for (var id in allIDs) {
- displayName = measurement.displayNames[id].current;
-
- candidates[displayName] = candidates[displayName] || {
- componentName: displayName,
- inclusive: 0,
- exclusive: 0,
- render: 0,
- count: 0,
- };
- if (measurement.render[id]) {
- candidates[displayName].render += measurement.render[id];
- }
- if (measurement.exclusive[id]) {
- candidates[displayName].exclusive += measurement.exclusive[id];
- }
- if (measurement.inclusive[id]) {
- candidates[displayName].inclusive += measurement.inclusive[id];
- }
- if (measurement.counts[id]) {
- candidates[displayName].count += measurement.counts[id];
- }
- }
- }
-
- // Now make a sorted array with the results.
- var arr = [];
- for (displayName in candidates) {
- if (candidates[displayName].exclusive >= DONT_CARE_THRESHOLD) {
- arr.push(candidates[displayName]);
- }
- }
-
- arr.sort(function(a, b) {
- return b.exclusive - a.exclusive;
- });
-
- return arr;
-}
-
-function getInclusiveSummary(measurements, onlyClean) {
- var candidates = {};
- var inclusiveKey;
-
- for (var i = 0; i < measurements.length; i++) {
- var measurement = measurements[i];
- var allIDs = Object.assign(
- {},
- measurement.exclusive,
- measurement.inclusive
- );
- var cleanComponents;
-
- if (onlyClean) {
- cleanComponents = getUnchangedComponents(measurement);
- }
-
- for (var id in allIDs) {
- if (onlyClean && !cleanComponents[id]) {
- continue;
- }
-
- var displayName = measurement.displayNames[id];
-
- // Inclusive time is not useful for many components without knowing where
- // they are instantiated. So we aggregate inclusive time with both the
- // owner and current displayName as the key.
- inclusiveKey = displayName.owner + ' > ' + displayName.current;
-
- candidates[inclusiveKey] = candidates[inclusiveKey] || {
- componentName: inclusiveKey,
- time: 0,
- count: 0,
- };
-
- if (measurement.inclusive[id]) {
- candidates[inclusiveKey].time += measurement.inclusive[id];
- }
- if (measurement.counts[id]) {
- candidates[inclusiveKey].count += measurement.counts[id];
- }
- }
- }
-
- // Now make a sorted array with the results.
- var arr = [];
- for (inclusiveKey in candidates) {
- if (candidates[inclusiveKey].time >= DONT_CARE_THRESHOLD) {
- arr.push(candidates[inclusiveKey]);
- }
- }
-
- arr.sort(function(a, b) {
- return b.time - a.time;
- });
-
- return arr;
-}
-
-function getUnchangedComponents(measurement) {
- // For a given reconcile, look at which components did not actually
- // render anything to the DOM and return a mapping of their ID to
- // the amount of time it took to render the entire subtree.
- var cleanComponents = {};
- var writes = measurement.writes;
- var hierarchy = measurement.hierarchy;
- var dirtyComposites = {};
- Object.keys(writes).forEach(function(id) {
- writes[id].forEach(function(write) {
- // Root mounting (innerHTML set) is recorded with an ID of ''
- if (id !== '' && hierarchy.hasOwnProperty(id)) {
- hierarchy[id].forEach((c) => dirtyComposites[c] = true);
- }
- });
- });
- var allIDs = Object.assign({}, measurement.exclusive, measurement.inclusive);
-
- for (var id in allIDs) {
- var isDirty = false;
- // See if any of the DOM operations applied to this component's subtree.
- if (dirtyComposites[id]) {
- isDirty = true;
- }
- // check if component newly created
- if (measurement.created[id]) {
- isDirty = true;
- }
- if (!isDirty && measurement.counts[id] > 0) {
- cleanComponents[id] = true;
- }
- }
- return cleanComponents;
-}
-
-var ReactDefaultPerfAnalysis = {
- getExclusiveSummary: getExclusiveSummary,
- getInclusiveSummary: getInclusiveSummary,
- getDOMSummary: getDOMSummary,
- getTotalTime: getTotalTime,
-};
-
-module.exports = ReactDefaultPerfAnalysis;
diff --git a/src/test/ReactPerf.js b/src/test/ReactPerf.js
deleted file mode 100644
index a8e6679311b..00000000000
--- a/src/test/ReactPerf.js
+++ /dev/null
@@ -1,100 +0,0 @@
-/**
- * Copyright 2013-present, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactPerf
- */
-
-'use strict';
-
-/**
- * ReactPerf is a general AOP system designed to measure performance. This
- * module only has the hooks: see ReactDefaultPerf for the analysis tool.
- * See also https://facebook.github.io/react/docs/perf.html
- */
-var ReactPerf = {
- /**
- * Boolean to enable/disable measurement. Set to false by default to prevent
- * accidental logging and perf loss.
- */
- enableMeasure: false,
-
- /**
- * Holds onto the measure function in use. By default, don't measure
- * anything, but we'll override this if we inject a measure function.
- */
- storedMeasure: _noMeasure,
-
- /**
- * @param {object} object
- * @param {string} objectName
- * @param {object} methodNames
- */
- measureMethods: function(object, objectName, methodNames) {
- if (__DEV__) {
- for (var key in methodNames) {
- if (!methodNames.hasOwnProperty(key)) {
- continue;
- }
- object[key] = ReactPerf.measure(
- objectName,
- methodNames[key],
- object[key]
- );
- }
- }
- },
-
- /**
- * Use this to wrap methods you want to measure. Zero overhead in production.
- *
- * @param {string} objName
- * @param {string} fnName
- * @param {function} func
- * @return {function}
- */
- measure: function(objName, fnName, func) {
- if (__DEV__) {
- var measuredFunc = null;
- var wrapper = function() {
- if (ReactPerf.enableMeasure) {
- if (!measuredFunc) {
- measuredFunc = ReactPerf.storedMeasure(objName, fnName, func);
- }
- return measuredFunc.apply(this, arguments);
- }
- return func.apply(this, arguments);
- };
- wrapper.displayName = objName + '_' + fnName;
- return wrapper;
- }
- return func;
- },
-
- injection: {
- /**
- * @param {function} measure
- */
- injectMeasure: function(measure) {
- ReactPerf.storedMeasure = measure;
- },
- },
-};
-
-/**
- * Simply passes through the measured function, without measuring it.
- *
- * @param {string} objName
- * @param {string} fnName
- * @param {function} func
- * @return {function}
- */
-function _noMeasure(objName, fnName, func) {
- return func;
-}
-
-module.exports = ReactPerf;