[perf] Better inclusive measurements
Inclusive time is still not that helpful w/o looking at what actually resulted in DOM ops. However, this is better than what we have today and will serve as a building block. I blacklisted everything but composite components -- hopefully that's OK.
Pete Hunt committed
Feb 12, 2014 at 15:51 UTC
94ef6c51fb9145e0bc445145d394f3ef1b13804a
1 file changed
+88
-29
src/test/ReactDefaultPerf.js
+88
-29
@@ -26,11 +26,8 @@ var performanceNow = require('performanceNow');
26
// Don't try to save users less than 1.2ms (a number I made up)
27
var DONT_CARE_THRESHOLD = 1.2;
28
29
-function getSummary(measurements, sortInclusive) {
30
- var candidates = {};
29
+function getTotalDOMTime(measurements) {
30
var totalDOMTime = 0;
32
- var displayName;
33
-
31
for (var i = 0; i < measurements.length; i++) {
32
var measurement = measurements[i];
33
var id;
@@ -40,11 +37,21 @@ function getSummary(measurements, sortInclusive) {
37
totalDOMTime += write.time;
38
});
39
}
40
+ }
41
+ return totalDOMTime;
42
+}
43
+
44
+function getExclusiveSummary(measurements) {
45
+ var candidates = {};
46
+ var displayName;
47
48
+ for (var i = 0; i < measurements.length; i++) {
49
+ var measurement = measurements[i];
50
var allIDs = merge(measurement.exclusive, measurement.inclusive);
51
46
- for (id in allIDs) {
47
- displayName = measurement.displayNames[id];
52
+ for (var id in allIDs) {
53
+ displayName = measurement.displayNames[id].current;
54
+
55
candidates[displayName] = candidates[displayName] || {
56
inclusive: 0,
57
exclusive: 0
@@ -61,7 +68,7 @@ function getSummary(measurements, sortInclusive) {
68
// Now make a sorted array with the results.
69
var arr = [];
70
for (displayName in candidates) {
64
- if (candidates[displayName] < DONT_CARE_THRESHOLD) {
71
+ if (candidates[displayName].exclusiveTime < DONT_CARE_THRESHOLD) {
72
continue;
73
}
74
arr.push({
@@ -71,17 +78,55 @@ function getSummary(measurements, sortInclusive) {
78
});
79
}
80
74
- if (sortInclusive) {
75
- arr.sort(function(a, b) {
76
- return b.inclusiveTime - a.inclusiveTime;
77
- });
78
- } else {
79
- arr.sort(function(a, b) {
80
- return b.exclusiveTime - a.exclusiveTime;
81
+ arr.sort(function(a, b) {
82
+ return b.exclusiveTime - a.exclusiveTime;
83
+ });
84
+
85
+ return arr;
86
+}
87
+
88
+function getInclusiveSummary(measurements) {
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
+
96
+
97
+ for (var id in allIDs) {
98
+ displayName = measurement.displayNames[id];
99
+
100
+ // Inclusive time is not useful for many components without knowing where
101
+ // they are instantiated. So we aggregate inclusive time with both the
102
+ // owner and current displayName as the key.
103
+ var inclusiveKey = displayName.owner + ' > ' + displayName.current;
104
+
105
+ inclusiveTimes[inclusiveKey] = inclusiveTimes[inclusiveKey] || 0;
106
+
107
+ if (measurement.inclusive[id]) {
108
+ inclusiveTimes[inclusiveKey] += measurement.inclusive[id];
109
+ }
110
+ }
111
+ }
112
+
113
+ // Now make a sorted array with the results.
114
+ var arr = [];
115
+ for (displayName in inclusiveTimes) {
116
+ if (inclusiveTimes[displayName] < DONT_CARE_THRESHOLD) {
117
+ continue;
118
+ }
119
+ arr.push({
120
+ componentName: displayName,
121
+ inclusiveTime: inclusiveTimes[displayName]
122
});
123
}
124
84
- return {componentClasses: arr, totalDOMTime: totalDOMTime};
125
+ arr.sort(function(a, b) {
126
+ return b.inclusiveTime - a.inclusiveTime;
127
+ });
128
+
129
+ return arr;
130
}
131
132
var ReactDefaultPerf = {
@@ -106,24 +151,34 @@ var ReactDefaultPerf = {
151
},
152
153
printByExclusive: function(measurements) {
109
- ReactDefaultPerf.print(measurements, false);
154
+ measurements = measurements || ReactDefaultPerf._allMeasurements;
155
+ var summary = getExclusiveSummary(measurements);
156
+ console.table(summary.map(function(item) {
157
+ return {
158
+ 'Component class name': item.componentName,
159
+ 'Exclusive time': item.exclusiveTime.toFixed(2) + ' ms',
160
+ 'Inclusive time': item.inclusiveTime.toFixed(2) + ' ms'
161
+ };
162
+ }));
163
+ console.log(
164
+ 'Total DOM time:',
165
+ getTotalDOMTime(measurements).toFixed(2) + ' ms'
166
+ );
167
},
168
169
printByInclusive: function(measurements) {
113
- ReactDefaultPerf.print(measurements, true);
114
- },
115
-
116
- print: function(measurements, sortInclusive) {
170
measurements = measurements || ReactDefaultPerf._allMeasurements;
118
- var summary = getSummary(measurements, sortInclusive);
119
- console.table(summary.componentClasses.map(function(item) {
171
+ var summary = getInclusiveSummary(measurements);
172
+ console.table(summary.map(function(item) {
173
return {
121
- 'Component class name': item.componentName,
122
- 'Inclusive time': item.inclusiveTime.toFixed(2) + ' ms',
123
- 'Exclusive time': item.exclusiveTime.toFixed(2) + ' ms'
174
+ 'Owner > component': item.componentName,
175
+ 'Inclusive time': item.inclusiveTime.toFixed(2) + ' ms'
176
};
177
}));
126
- console.log('Total DOM time:', summary.totalDOMTime.toFixed(2) + ' ms');
178
+ console.log(
179
+ 'Total DOM time:',
180
+ getTotalDOMTime(measurements).toFixed(2) + ' ms'
181
+ );
182
},
183
184
_recordWrite: function(id, fnName, totalTime) {
@@ -176,8 +231,9 @@ var ReactDefaultPerf = {
231
ReactDefaultPerf._recordWrite(args[0], fnName, totalTime);
232
}
233
return rv;
179
- } else if (fnName === 'updateComponent' ||
180
- fnName === '_renderValidatedComponent') {
234
+ } else if (moduleName === 'ReactCompositeComponent' && (
235
+ fnName === 'updateComponent' ||
236
+ fnName === '_renderValidatedComponent')) {
237
var isInclusive = fnName === 'updateComponent';
238
var entry = ReactDefaultPerf._allMeasurements[
239
ReactDefaultPerf._allMeasurements.length - 1
@@ -196,7 +252,10 @@ var ReactDefaultPerf = {
252
typeOfLog[this._rootNodeID] = typeOfLog[this._rootNodeID] || 0;
253
typeOfLog[this._rootNodeID] += totalTime;
254
199
- entry.displayNames[this._rootNodeID] = this.constructor.displayName;
255
+ entry.displayNames[this._rootNodeID] = {
256
+ current: this.constructor.displayName,
257
+ owner: this._owner ? this._owner.constructor.displayName : '<root>'
258
+ };
259
260
return rv;
261
} else {