@samitouri / QOS-React-2 / commits / 439bca78ed

[perf] New ReactDefaultPerf

Simplified version of https://github.com/facebook/react/pull/962. More goodies coming soon since the inclusive time isn't very helpful right now.

Pete Hunt committed Feb 12, 2014 at 12:25 UTC 439bca78ed6482a068c29fe04f714a744c5cfbe2
2 files changed +228 -435
src/browser/ReactComponentBrowserEnvironment.js
+64 -58
@@ -23,6 +23,7 @@
23 var ReactDOMIDOperations = require('ReactDOMIDOperations');
24 var ReactMarkupChecksum = require('ReactMarkupChecksum');
25 var ReactMount = require('ReactMount');
26 +var ReactPerf = require('ReactPerf');
27 var ReactReconcileTransaction = require('ReactReconcileTransaction');
28
29 var getReactRootElementInContainer = require('getReactRootElementInContainer');
@@ -79,71 +80,76 @@ var ReactComponentBrowserEnvironment = {
80 * @param {boolean} shouldReuseMarkup Should reuse the existing markup in the
81 * container if possible.
82 */
82 - mountImageIntoNode: function(markup, container, shouldReuseMarkup) {
83 - invariant(
84 - container && (
85 - container.nodeType === ELEMENT_NODE_TYPE ||
86 - container.nodeType === DOC_NODE_TYPE
87 - ),
88 - 'mountComponentIntoNode(...): Target container is not valid.'
89 - );
90 -
91 - if (shouldReuseMarkup) {
92 - if (ReactMarkupChecksum.canReuseMarkup(
93 - markup,
94 - getReactRootElementInContainer(container))) {
95 - return;
96 - } else {
97 - invariant(
98 - container.nodeType !== DOC_NODE_TYPE,
99 - 'You\'re trying to render a component to the document using ' +
100 - 'server rendering but the checksum was invalid. This usually ' +
101 - 'means you rendered a different component type or props on ' +
102 - 'the client from the one on the server, or your render() methods ' +
103 - 'are impure. React cannot handle this case due to cross-browser ' +
104 - 'quirks by rendering at the document root. You should look for ' +
105 - 'environment dependent code in your components and ensure ' +
106 - 'the props are the same client and server side.'
107 - );
108 -
109 - if (__DEV__) {
110 - console.warn(
111 - 'React attempted to use reuse markup in a container but the ' +
112 - 'checksum was invalid. This generally means that you are using ' +
113 - 'server rendering and the markup generated on the server was ' +
114 - 'not what the client was expecting. React injected new markup ' +
115 - 'to compensate which works but you have lost many of the ' +
116 - 'benefits of server rendering. Instead, figure out why the ' +
117 - 'markup being generated is different on the client or server.'
83 + mountImageIntoNode: ReactPerf.measure(
84 + 'ReactComponentBrowserEnvironment',
85 + 'mountImageIntoNode',
86 + function(markup, container, shouldReuseMarkup) {
87 + invariant(
88 + container && (
89 + container.nodeType === ELEMENT_NODE_TYPE ||
90 + container.nodeType === DOC_NODE_TYPE
91 + ),
92 + 'mountComponentIntoNode(...): Target container is not valid.'
93 + );
94 +
95 + if (shouldReuseMarkup) {
96 + if (ReactMarkupChecksum.canReuseMarkup(
97 + markup,
98 + getReactRootElementInContainer(container))) {
99 + return;
100 + } else {
101 + invariant(
102 + container.nodeType !== DOC_NODE_TYPE,
103 + 'You\'re trying to render a component to the document using ' +
104 + 'server rendering but the checksum was invalid. This usually ' +
105 + 'means you rendered a different component type or props on ' +
106 + 'the client from the one on the server, or your render() ' +
107 + 'methods are impure. React cannot handle this case due to ' +
108 + 'cross-browser quirks by rendering at the document root. You ' +
109 + 'should look for environment dependent code in your components ' +
110 + 'and ensure the props are the same client and server side.'
111 );
112 +
113 + if (__DEV__) {
114 + console.warn(
115 + 'React attempted to use reuse markup in a container but the ' +
116 + 'checksum was invalid. This generally means that you are ' +
117 + 'using server rendering and the markup generated on the ' +
118 + 'server was not what the client was expecting. React injected' +
119 + 'new markup to compensate which works but you have lost many ' +
120 + 'of the benefits of server rendering. Instead, figure out ' +
121 + 'why the markup being generated is different on the client ' +
122 + 'or server.'
123 + );
124 + }
125 }
126 }
121 - }
127
123 - invariant(
124 - container.nodeType !== DOC_NODE_TYPE,
125 - 'You\'re trying to render a component to the document but ' +
126 - 'you didn\'t use server rendering. We can\'t do this ' +
127 - 'without using server rendering due to cross-browser quirks. ' +
128 - 'See renderComponentToString() for server rendering.'
129 - );
130 -
131 - // Asynchronously inject markup by ensuring that the container is not in
132 - // the document when settings its `innerHTML`.
133 - var parent = container.parentNode;
134 - if (parent) {
135 - var next = container.nextSibling;
136 - parent.removeChild(container);
137 - container.innerHTML = markup;
138 - if (next) {
139 - parent.insertBefore(container, next);
128 + invariant(
129 + container.nodeType !== DOC_NODE_TYPE,
130 + 'You\'re trying to render a component to the document but ' +
131 + 'you didn\'t use server rendering. We can\'t do this ' +
132 + 'without using server rendering due to cross-browser quirks. ' +
133 + 'See renderComponentToString() for server rendering.'
134 + );
135 +
136 + // Asynchronously inject markup by ensuring that the container is not in
137 + // the document when settings its `innerHTML`.
138 + var parent = container.parentNode;
139 + if (parent) {
140 + var next = container.nextSibling;
141 + parent.removeChild(container);
142 + container.innerHTML = markup;
143 + if (next) {
144 + parent.insertBefore(container, next);
145 + } else {
146 + parent.appendChild(container);
147 + }
148 } else {
141 - parent.appendChild(container);
149 + container.innerHTML = markup;
150 }
143 - } else {
144 - container.innerHTML = markup;
151 }
146 - }
152 + )
153 };
154
155 module.exports = ReactComponentBrowserEnvironment;
src/test/ReactDefaultPerf.js
+164 -377
@@ -17,406 +17,193 @@
17 * @typechecks static-only
18 */
19
20 -"use strict";
21 -
20 +var ReactMount = require('ReactMount');
21 var ReactPerf = require('ReactPerf');
22
23 +var merge = require('merge');
24 var performanceNow = require('performanceNow');
25
26 -var ReactDefaultPerf = {};
27 -
28 -if (__DEV__) {
29 - ReactDefaultPerf = {
30 - _injected: false,
31 -
32 - start: function() {
33 - if (!ReactDefaultPerf._injected) {
34 - ReactPerf.injection.injectMeasure(ReactDefaultPerf.measure);
35 - }
36 - ReactPerf.enableMeasure = true;
37 - },
38 -
39 - stop: function() {
40 - ReactPerf.enableMeasure = false;
41 - },
42 -
43 - /**
44 - * Gets the stored information for a given object's function.
45 - *
46 - * @param {string} objName
47 - * @param {string} fnName
48 - * @return {?object}
49 - */
50 - getInfo: function(objName, fnName) {
51 - if (!this.info[objName] || !this.info[objName][fnName]) {
52 - return null;
53 - }
54 - return this.info[objName][fnName];
55 - },
56 -
57 - /**
58 - * Gets the logs pertaining to a given object's function.
59 - *
60 - * @param {string} objName
61 - * @param {string} fnName
62 - * @return {?array<object>}
63 - */
64 - getLogs: function(objName, fnName) {
65 - if (!this.getInfo(objName, fnName)) {
66 - return null;
67 - }
68 - return this.logs.filter(function(log) {
69 - return log.objName === objName && log.fnName === fnName;
70 - });
71 - },
72 -
73 - /**
74 - * Runs through the logs and builds an array of arrays, where each array
75 - * walks through the mounting/updating of each component underneath.
76 - *
77 - * @param {string} rootID The reactID of the root node, e.g. '.0'
78 - * @return {array<array>}
79 - */
80 - getRawRenderHistory: function(rootID) {
81 - var history = [];
82 - /**
83 - * Since logs are added after the method returns, the logs are in a sense
84 - * upside-down: the inner-most elements from mounting/updating are logged
85 - * first, and the last addition to the log is the top renderComponent.
86 - * Therefore, we flip the logs upside down for ease of processing, and
87 - * reverse the history array at the end so the earliest event has index 0.
88 - */
89 - var logs = this.logs.filter(function(log) {
90 - return log.reactID.indexOf(rootID) === 0;
91 - }).reverse();
92 -
93 - var subHistory = [];
94 - logs.forEach(function(log, i) {
95 - if (i && log.reactID === rootID && logs[i - 1].reactID !== rootID) {
96 - subHistory.length && history.push(subHistory);
97 - subHistory = [];
98 - }
99 - subHistory.push(log);
100 - });
101 - if (subHistory.length) {
102 - history.push(subHistory);
103 - }
104 - return history.reverse();
105 - },
26 +// Don't try to save users less than 1.2ms (a number I made up)
27 +var DONT_CARE_THRESHOLD = 1.2;
28
107 - /**
108 - * Runs through the logs and builds an array of strings, where each string
109 - * is a multiline formatted way of walking through the mounting/updating
110 - * underneath.
111 - *
112 - * @param {string} rootID The reactID of the root node, e.g. '.0'
113 - * @return {array<string>}
114 - */
115 - getRenderHistory: function(rootID) {
116 - var history = this.getRawRenderHistory(rootID);
29 +function getSummary(measurements, sortInclusive) {
30 + var candidates = {};
31 + var totalDOMTime = 0;
32 + var displayName;
33
118 - return history.map(function(subHistory) {
119 - var headerString = (
120 - 'log# Component (execution time) [bloat from logging]\n' +
121 - '================================================================\n'
122 - );
123 - return headerString + subHistory.map(function(log) {
124 - // Add two spaces for every layer in the reactID.
125 - var indents = '\t' + Array(log.reactID.split('.').length).join(' ');
126 - var delta = _microTime(log.timing.delta);
127 - var bloat = _microTime(log.timing.timeToLog);
34 + for (var i = 0; i < measurements.length; i++) {
35 + var measurement = measurements[i];
36 + var id;
37
129 - return log.index + indents + log.name + ' (' + delta + 'ms)' +
130 - ' [' + bloat + 'ms]';
131 - }).join('\n');
38 + for (id in measurement.writes) {
39 + measurement.writes[id].forEach(function(write) {
40 + totalDOMTime += write.time;
41 });
133 - },
134 -
135 - /**
136 - * Print the render history from `getRenderHistory` using console.log.
137 - * This is currently the best way to display perf data from
138 - * any React component; working on that.
139 - *
140 - * @param {string} rootID The reactID of the root node, e.g. '.0'
141 - * @param {number} index
142 - */
143 - printRenderHistory: function(rootID, index) {
144 - var history = this.getRenderHistory(rootID);
145 - if (!history[index]) {
146 - console.warn(
147 - 'Index', index, 'isn\'t available! ' +
148 - 'The render history is', history.length, 'long.'
149 - );
150 - return;
151 - }
152 - console.log(
153 - 'Loading render history #' + (index + 1) +
154 - ' of ' + history.length + ':\n' + history[index]
155 - );
156 - },
157 -
158 - /**
159 - * Prints the heatmap legend to console, showing how the colors correspond
160 - * with render times. This relies on console.log styles.
161 - */
162 - printHeatmapLegend: function() {
163 - if (!this.options.heatmap.enabled) {
164 - return;
165 - }
166 - var max = this.info.React
167 - && this.info.React.renderComponent
168 - && this.info.React.renderComponent.max;
169 - if (max) {
170 - var logStr = 'Heatmap: ';
171 - for (var ii = 0; ii <= 10 * max; ii += max) {
172 - logStr += '%c ' + (Math.round(ii) / 10) + 'ms ';
173 - }
174 - console.log(
175 - logStr,
176 - 'background-color: hsla(100, 100%, 50%, 0.6);',
177 - 'background-color: hsla( 90, 100%, 50%, 0.6);',
178 - 'background-color: hsla( 80, 100%, 50%, 0.6);',
179 - 'background-color: hsla( 70, 100%, 50%, 0.6);',
180 - 'background-color: hsla( 60, 100%, 50%, 0.6);',
181 - 'background-color: hsla( 50, 100%, 50%, 0.6);',
182 - 'background-color: hsla( 40, 100%, 50%, 0.6);',
183 - 'background-color: hsla( 30, 100%, 50%, 0.6);',
184 - 'background-color: hsla( 20, 100%, 50%, 0.6);',
185 - 'background-color: hsla( 10, 100%, 50%, 0.6);',
186 - 'background-color: hsla( 0, 100%, 50%, 0.6);'
187 - );
188 - }
189 - },
190 -
191 - /**
192 - * Measure a given function with logging information, and calls a callback
193 - * if there is one.
194 - *
195 - * @param {string} objName
196 - * @param {string} fnName
197 - * @param {function} func
198 - * @return {function}
199 - */
200 - measure: function(objName, fnName, func) {
201 - var info = _getNewInfo(objName, fnName);
202 -
203 - var fnArgs = _getFnArguments(func);
204 -
205 - return function(...args) {
206 - var timeBeforeFn = performanceNow();
207 - var fnReturn = func.apply(this, args);
208 - var timeAfterFn = performanceNow();
209 -
210 - /**
211 - * Hold onto arguments in a readable way: args[1] -> args.component.
212 - * args is also passed to the callback, so if you want to save an
213 - * argument in the log, do so in the callback.
214 - */
215 - var argsObject = {};
216 - for (var i = 0; i < args.length; i++) {
217 - argsObject[fnArgs[i]] = args[i];
218 - }
219 -
220 - var log = {
221 - index: ReactDefaultPerf.logs.length,
222 - fnName: fnName,
223 - objName: objName,
224 - timing: {
225 - before: timeBeforeFn,
226 - after: timeAfterFn,
227 - delta: timeAfterFn - timeBeforeFn
228 - }
229 - };
230 -
231 - ReactDefaultPerf.logs.push(log);
232 -
233 - /**
234 - * The callback gets:
235 - * - this (the component)
236 - * - the original method's arguments
237 - * - what the method returned
238 - * - the log object, and
239 - * - the wrapped method's info object.
240 - */
241 - var callback = _getCallback(objName, fnName);
242 - callback && callback(this, argsObject, fnReturn, log, info);
42 + }
43
244 - log.timing.timeToLog = performanceNow() - timeAfterFn;
44 + var allIDs = merge(measurement.exclusive, measurement.inclusive);
45
246 - return fnReturn;
46 + for (id in allIDs) {
47 + displayName = measurement.displayNames[id];
48 + candidates[displayName] = candidates[displayName] || {
49 + inclusive: 0,
50 + exclusive: 0
51 };
248 - },
249 -
250 - /**
251 - * Holds information on wrapped objects/methods.
252 - * For instance, ReactDefaultPerf.info.React.renderComponent
253 - */
254 - info: {},
255 -
256 - /**
257 - * Holds all of the logs. Filter this to pull desired information.
258 - */
259 - logs: [],
260 -
261 - /**
262 - * Toggle settings for ReactDefaultPerf
263 - */
264 - options: {
265 - /**
266 - * The heatmap sets the background color of the React containers
267 - * according to how much total time has been spent rendering them.
268 - * The most temporally expensive component is set as pure red,
269 - * and the others are colored from green to red as a fraction
270 - * of that max component time.
271 - */
272 - heatmap: {
273 - enabled: true
52 + if (measurement.exclusive[id]) {
53 + candidates[displayName].exclusive += measurement.exclusive[id];
54 + }
55 + if (measurement.inclusive[id]) {
56 + candidates[displayName].inclusive += measurement.inclusive[id];
57 }
58 }
276 - };
59 + }
60
278 - /**
279 - * Gets a info area for a given object's function, adding a new one if
280 - * necessary.
281 - *
282 - * @param {string} objName
283 - * @param {string} fnName
284 - * @return {object}
285 - */
286 - var _getNewInfo = function(objName, fnName) {
287 - var info = ReactDefaultPerf.getInfo(objName, fnName);
288 - if (info) {
289 - return info;
61 + // Now make a sorted array with the results.
62 + var arr = [];
63 + for (displayName in candidates) {
64 + if (candidates[displayName] < DONT_CARE_THRESHOLD) {
65 + continue;
66 }
291 - ReactDefaultPerf.info[objName] = ReactDefaultPerf.info[objName] || {};
292 -
293 - return ReactDefaultPerf.info[objName][fnName] = {
294 - getLogs: function() {
295 - return ReactDefaultPerf.getLogs(objName, fnName);
296 - }
297 - };
298 - };
67 + arr.push({
68 + componentName: displayName,
69 + exclusiveTime: candidates[displayName].exclusive,
70 + inclusiveTime: candidates[displayName].inclusive
71 + });
72 + }
73 +
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 + });
82 + }
83 +
84 + return {componentClasses: arr, totalDOMTime: totalDOMTime};
85 +}
86
300 - /**
301 - * Gets a list of the argument names from a function's definition.
302 - * This is useful for storing arguments by their names within wrapFn().
303 - *
304 - * @param {function} fn
305 - * @return {array<string>}
306 - */
307 - var _getFnArguments = function(fn) {
308 - var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
309 - var fnStr = fn.toString().replace(STRIP_COMMENTS, '');
310 - fnStr = fnStr.slice(fnStr.indexOf('(') + 1, fnStr.indexOf(')'));
311 - return fnStr.match(/([^\s,]+)/g) || [];
312 - };
87 +var ReactDefaultPerf = {
88 + _allMeasurements: null, // last item in the list is the current one
89 + _injected: false,
90
314 - /**
315 - * Store common callbacks within ReactDefaultPerf.
316 - *
317 - * @param {string} objName
318 - * @param {string} fnName
319 - * @return {?function}
320 - */
321 - var _getCallback = function(objName, fnName) {
322 - switch (objName + '.' + fnName) {
323 - case 'React.renderComponent':
324 - return _renderComponentCallback;
325 - case 'ReactDOMComponent.mountComponent':
326 - case 'ReactDOMComponent.updateComponent':
327 - return _nativeComponentCallback;
328 - case 'ReactCompositeComponent.mountComponent':
329 - case 'ReactCompositeComponent.updateComponent':
330 - return _compositeComponentCallback;
331 - default:
332 - return null;
91 + start: function() {
92 + if (!ReactDefaultPerf._injected) {
93 + ReactPerf.injection.injectMeasure(ReactDefaultPerf.measure);
94 }
334 - };
335 -
336 - /**
337 - * Callback function for React.renderComponent
338 - *
339 - * @param {object} component
340 - * @param {object} args
341 - * @param {?object} fnReturn
342 - * @param {object} log
343 - * @param {object} info
344 - */
345 - var _renderComponentCallback =
346 - function(component, args, fnReturn, log, info) {
347 - log.name = args.nextComponent.constructor.displayName || '[unknown]';
348 - log.reactID = fnReturn._rootNodeID || null;
95
350 - if (ReactDefaultPerf.options.heatmap.enabled) {
351 - var container = args.container;
352 - if (!container.loggedByReactDefaultPerf) {
353 - container.loggedByReactDefaultPerf = true;
354 - info.components = info.components || [];
355 - info.components.push(container);
356 - }
357 -
358 - container.count = container.count || 0;
359 - container.count += log.timing.delta;
360 - info.max = info.max || 0;
361 - if (container.count > info.max) {
362 - info.max = container.count;
363 - info.components.forEach(function(component) {
364 - _setHue(component, 100 - 100 * component.count / info.max);
96 + ReactDefaultPerf._allMeasurements = [];
97 + ReactPerf.enableMeasure = true;
98 + },
99 +
100 + stop: function() {
101 + ReactPerf.enableMeasure = false;
102 + },
103 +
104 + getLastMeasurements: function() {
105 + return ReactDefaultPerf._allMeasurements;
106 + },
107 +
108 + printByExclusive: function(measurements) {
109 + ReactDefaultPerf.print(measurements, false);
110 + },
111 +
112 + printByInclusive: function(measurements) {
113 + ReactDefaultPerf.print(measurements, true);
114 + },
115 +
116 + print: function(measurements, sortInclusive) {
117 + measurements = measurements || ReactDefaultPerf._allMeasurements;
118 + var summary = getSummary(measurements, sortInclusive);
119 + console.table(summary.componentClasses.map(function(item) {
120 + return {
121 + 'Component class name': item.componentName,
122 + 'Inclusive time': item.inclusiveTime.toFixed(2) + ' ms',
123 + 'Exclusive time': item.exclusiveTime.toFixed(2) + ' ms'
124 + };
125 + }));
126 + console.log('Total DOM time:', summary.totalDOMTime.toFixed(2) + ' ms');
127 + },
128 +
129 + _recordWrite: function(id, fnName, totalTime) {
130 + var writes =
131 + ReactDefaultPerf
132 + ._allMeasurements[ReactDefaultPerf._allMeasurements.length - 1]
133 + .writes;
134 + writes[id] = writes[id] || [];
135 + writes[id].push({
136 + type: fnName,
137 + time: totalTime
138 + });
139 + },
140 +
141 + measure: function(moduleName, fnName, func) {
142 + return function(...args) {
143 + var totalTime;
144 + var rv;
145 + var start;
146 +
147 + if (fnName === 'flushBatchedUpdates') {
148 + // A "measurement" is a set of metrics recorded for each flush. We want
149 + // to group the metrics for a given flush together so we can look at the
150 + // components that rendered and the DOM operations that actually
151 + // happened to determine the amount of "wasted work" performed.
152 + ReactDefaultPerf._allMeasurements.push({
153 + exclusive: {},
154 + inclusive: {},
155 + counts: {},
156 + writes: {},
157 + displayNames: {}
158 });
366 - } else {
367 - _setHue(container, 100 - 100 * container.count / info.max);
368 - }
369 - }
370 - };
371 -
372 - /**
373 - * Callback function for ReactDOMComponent
374 - *
375 - * @param {object} component
376 - * @param {object} args
377 - * @param {?object} fnReturn
378 - * @param {object} log
379 - * @param {object} info
380 - */
381 - var _nativeComponentCallback =
382 - function(component, args, fnReturn, log, info) {
383 - log.name = component.tagName || '[unknown]';
384 - log.reactID = component._rootNodeID;
385 - };
159 + return func.apply(this, args);
160 + } else if (moduleName === 'ReactDOMIDOperations' ||
161 + moduleName === 'ReactComponentBrowserEnvironment') {
162 + start = performanceNow();
163 + rv = func.apply(this, args);
164 + totalTime = performanceNow() - start;
165 +
166 + if (fnName === 'mountImageIntoNode') {
167 + var mountID = ReactMount.getID(args[1]);
168 + ReactDefaultPerf._recordWrite(mountID, fnName, totalTime);
169 + } else if (fnName === 'dangerouslyProcessChildrenUpdates') {
170 + // special format
171 + args[0].forEach(function(update) {
172 + ReactDefaultPerf._recordWrite(update.parentID, fnName, totalTime);
173 + });
174 + } else {
175 + // basic format
176 + ReactDefaultPerf._recordWrite(args[0], fnName, totalTime);
177 + }
178 + return rv;
179 + } else if (fnName === 'updateComponent' ||
180 + fnName === '_renderValidatedComponent') {
181 + var isInclusive = fnName === 'updateComponent';
182 + var entry = ReactDefaultPerf._allMeasurements[
183 + ReactDefaultPerf._allMeasurements.length - 1
184 + ];
185 + if (isInclusive) {
186 + // Since both updateComponent() and _renderValidatedComponent() are
187 + // called for each render, only record the count for one of them.
188 + entry.counts[this._rootNodeID] = entry.counts[this._rootNodeID] || 0;
189 + entry.counts[this._rootNodeID] += 1;
190 + }
191 + start = performanceNow();
192 + rv = func.apply(this, args);
193 + totalTime = performanceNow() - start;
194
387 - /**
388 - * Callback function for ReactCompositeComponent
389 - *
390 - * @param {object} component
391 - * @param {object} args
392 - * @param {?object} fnReturn
393 - * @param {object} log
394 - * @param {object} info
395 - */
396 - var _compositeComponentCallback =
397 - function(component, args, fnReturn, log, info) {
398 - log.name = component.constructor.displayName || '[unknown]';
399 - log.reactID = component._rootNodeID;
400 - };
195 + var typeOfLog = isInclusive ? entry.inclusive : entry.exclusive;
196 + typeOfLog[this._rootNodeID] = typeOfLog[this._rootNodeID] || 0;
197 + typeOfLog[this._rootNodeID] += totalTime;
198
402 - /**
403 - * Using the hsl() background-color attribute, colors an element.
404 - *
405 - * @param {DOMElement} el
406 - * @param {number} hue [0 for red, 120 for green, 240 for blue]
407 - */
408 - var _setHue = function(el, hue) {
409 - el.style.backgroundColor = 'hsla(' + hue + ', 100%, 50%, 0.6)';
410 - };
199 + entry.displayNames[this._rootNodeID] = this.constructor.displayName;
200
412 - /**
413 - * Round to the thousandth place.
414 - * @param {number} time
415 - * @return {number}
416 - */
417 - var _microTime = function(time) {
418 - return Math.round(time * 1000) / 1000;
419 - };
201 + return rv;
202 + } else {
203 + return func.apply(this, args);
204 + }
205 + };
206 + }
207 }
208
209 module.exports = ReactDefaultPerf;