@samitouri / QOS-React-2 / commits / 75b58d2ad2

[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