[perf] Wasted time metrics
This logs DOM ops for a given reconcile. Based on which components rendered and which ones *actually* caused DOM updates we can find opportunities to add shouldComponentUpdate() methods.
Pete Hunt committed
Feb 12, 2014 at 15:52 UTC
75b58d2ad2c2111aeb73e5915fad8d717ec69703
1 file changed
+49
-1
src/test/ReactDefaultPerf.js
+49
-1
@@ -85,16 +85,24 @@ function getExclusiveSummary(measurements) {
85
return arr;
86
}
87
88
-function getInclusiveSummary(measurements) {
88
+function getInclusiveSummary(measurements, onlyClean) {
89
var inclusiveTimes = {};
90
var displayName;
91
92
for (var i = 0; i < measurements.length; i++) {
93
var measurement = measurements[i];
94
var allIDs = merge(measurement.exclusive, measurement.inclusive);
95
+ var cleanComponents;
96
97
+ if (onlyClean) {
98
+ cleanComponents = getCleanComponents(measurement);
99
+ }
100
101
for (var id in allIDs) {
102
+ if (onlyClean && !cleanComponents[id]) {
103
+ continue;
104
+ }
105
+
106
displayName = measurement.displayNames[id];
107
108
// Inclusive time is not useful for many components without knowing where
@@ -129,6 +137,31 @@ function getInclusiveSummary(measurements) {
137
return arr;
138
}
139
140
+function getCleanComponents(measurement) {
141
+ // For a given reconcile, look at which components did not actually
142
+ // render anything to the DOM and return a mapping of their ID to
143
+ // the amount of time it took to render the entire subtree.
144
+ var cleanComponents = {};
145
+ var dirtyLeafIDs = Object.keys(measurement.writes);
146
+ var allIDs = merge(measurement.exclusive, measurement.inclusive);
147
+
148
+ for (var id in allIDs) {
149
+ var isDirty = false;
150
+ // For each component that rendered, see if a component that triggerd
151
+ // a DOM op is in its subtree.
152
+ for (var i = 0; i < dirtyLeafIDs.length; i++) {
153
+ if (dirtyLeafIDs[i].indexOf(id) === 0) {
154
+ isDirty = true;
155
+ break;
156
+ }
157
+ }
158
+ if (!isDirty && measurement.counts[id] > 0) {
159
+ cleanComponents[id] = true;
160
+ }
161
+ }
162
+ return cleanComponents;
163
+}
164
+
165
var ReactDefaultPerf = {
166
_allMeasurements: null, // last item in the list is the current one
167
_injected: false,
@@ -181,6 +214,21 @@ var ReactDefaultPerf = {
214
);
215
},
216
217
+ printByWasted: function(measurements) {
218
+ measurements = measurements || ReactDefaultPerf._allMeasurements;
219
+ var summary = getInclusiveSummary(measurements, true);
220
+ console.table(summary.map(function(item) {
221
+ return {
222
+ 'Owner > component': item.componentName,
223
+ 'Wasted time': item.inclusiveTime.toFixed(2) + ' ms'
224
+ };
225
+ }));
226
+ console.log(
227
+ 'Total DOM time:',
228
+ getTotalDOMTime(measurements).toFixed(2) + ' ms'
229
+ );
230
+ },
231
+
232
_recordWrite: function(id, fnName, totalTime) {
233
var writes =
234
ReactDefaultPerf