From 118521c20bcbc7f12bcc337f653d551b5992da05 Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Thu, 8 Mar 2018 23:33:06 -0800 Subject: [PATCH] RN: Prettify Systrace Reviewed By: TheSavior Differential Revision: D7207468 fbshipit-source-id: 05ae6e003ae3e55bc2d3a905f41c28f7041dd7f0 --- Libraries/Performance/Systrace.js | 268 ++++++++++++++++-------------- 1 file changed, 141 insertions(+), 127 deletions(-) diff --git a/Libraries/Performance/Systrace.js b/Libraries/Performance/Systrace.js index 1abedee7c..8b4aa1fc6 100644 --- a/Libraries/Performance/Systrace.js +++ b/Libraries/Performance/Systrace.js @@ -6,7 +6,9 @@ * * @providesModule Systrace * @flow + * @format */ + 'use strict'; const invariant = require('fbjs/lib/invariant'); @@ -14,18 +16,17 @@ const invariant = require('fbjs/lib/invariant'); type RelayProfiler = { attachProfileHandler( name: string, - handler: (name: string, state?: any) => () => void + handler: (name: string, state?: any) => () => void, ): void, attachAggregateHandler( name: string, - handler: (name: string, callback: () => void) => void + handler: (name: string, callback: () => void) => void, ): void, }; -/* eslint no-bitwise: 0 */ -const TRACE_TAG_REACT_APPS = 1 << 17; -const TRACE_TAG_JS_VM_CALLS = 1 << 27; +const TRACE_TAG_REACT_APPS = 1 << 17; // eslint-disable-line no-bitwise +const TRACE_TAG_JS_VM_CALLS = 1 << 27; // eslint-disable-line no-bitwise let _enabled = false; let _asyncCookie = 0; @@ -36,66 +37,68 @@ let _canInstallReactHook = false; // Implements a subset of User Timing API necessary for React measurements. // https://developer.mozilla.org/en-US/docs/Web/API/User_Timing_API const REACT_MARKER = '\u269B'; -const userTimingPolyfill = __DEV__ ? { - mark(markName: string) { - if (_enabled) { - _markStackIndex++; - _markStack[_markStackIndex] = markName; - let systraceLabel = markName; - // Since perf measurements are a shared namespace in User Timing API, - // we prefix all React results with a React emoji. - if (markName[0] === REACT_MARKER) { - // This is coming from React. - // Removing component IDs keeps trace colors stable. - const indexOfId = markName.lastIndexOf(' (#'); - const cutoffIndex = indexOfId !== -1 ? indexOfId : markName.length; - // Also cut off the emoji because it breaks Systrace - systraceLabel = markName.slice(2, cutoffIndex); - } - Systrace.beginEvent(systraceLabel); - } - }, - measure(measureName: string, startMark: ?string, endMark: ?string) { - if (_enabled) { - invariant( - typeof measureName === 'string' && - typeof startMark === 'string' && - typeof endMark === 'undefined', - 'Only performance.measure(string, string) overload is supported.' - ); - const topMark = _markStack[_markStackIndex]; - invariant( - startMark === topMark, - 'There was a mismatching performance.measure() call. ' + - 'Expected "%s" but got "%s."', - topMark, - startMark, - ); - _markStackIndex--; - // We can't use more descriptive measureName because Systrace doesn't - // let us edit labels post factum. - Systrace.endEvent(); - } - }, - clearMarks(markName: string) { - if (_enabled) { - if (_markStackIndex === -1) { - return; - } - if (markName === _markStack[_markStackIndex]) { - // React uses this for "cancelling" started measurements. - // Systrace doesn't support deleting measurements, so we just stop them. - if (userTimingPolyfill != null) { - userTimingPolyfill.measure(markName, markName); +const userTimingPolyfill = __DEV__ + ? { + mark(markName: string) { + if (_enabled) { + _markStackIndex++; + _markStack[_markStackIndex] = markName; + let systraceLabel = markName; + // Since perf measurements are a shared namespace in User Timing API, + // we prefix all React results with a React emoji. + if (markName[0] === REACT_MARKER) { + // This is coming from React. + // Removing component IDs keeps trace colors stable. + const indexOfId = markName.lastIndexOf(' (#'); + const cutoffIndex = indexOfId !== -1 ? indexOfId : markName.length; + // Also cut off the emoji because it breaks Systrace + systraceLabel = markName.slice(2, cutoffIndex); + } + Systrace.beginEvent(systraceLabel); } - } + }, + measure(measureName: string, startMark: ?string, endMark: ?string) { + if (_enabled) { + invariant( + typeof measureName === 'string' && + typeof startMark === 'string' && + typeof endMark === 'undefined', + 'Only performance.measure(string, string) overload is supported.', + ); + const topMark = _markStack[_markStackIndex]; + invariant( + startMark === topMark, + 'There was a mismatching performance.measure() call. ' + + 'Expected "%s" but got "%s."', + topMark, + startMark, + ); + _markStackIndex--; + // We can't use more descriptive measureName because Systrace doesn't + // let us edit labels post factum. + Systrace.endEvent(); + } + }, + clearMarks(markName: string) { + if (_enabled) { + if (_markStackIndex === -1) { + return; + } + if (markName === _markStack[_markStackIndex]) { + // React uses this for "cancelling" started measurements. + // Systrace doesn't support deleting measurements, so we just stop them. + if (userTimingPolyfill != null) { + userTimingPolyfill.measure(markName, markName); + } + } + } + }, + clearMeasures() { + // React calls this to avoid memory leaks in browsers, but we don't keep + // measurements anyway. + }, } - }, - clearMeasures() { - // React calls this to avoid memory leaks in browsers, but we don't keep - // measurements anyway. - }, -} : null; + : null; const Systrace = { installReactHook() { @@ -111,9 +114,11 @@ const Systrace = { if (_enabled !== enabled) { if (__DEV__) { if (enabled) { - global.nativeTraceBeginLegacy && global.nativeTraceBeginLegacy(TRACE_TAG_JS_VM_CALLS); + global.nativeTraceBeginLegacy && + global.nativeTraceBeginLegacy(TRACE_TAG_JS_VM_CALLS); } else { - global.nativeTraceEndLegacy && global.nativeTraceEndLegacy(TRACE_TAG_JS_VM_CALLS); + global.nativeTraceEndLegacy && + global.nativeTraceEndLegacy(TRACE_TAG_JS_VM_CALLS); } if (_canInstallReactHook) { if (enabled && global.performance === undefined) { @@ -131,11 +136,11 @@ const Systrace = { /** * beginEvent/endEvent for starting and then ending a profile within the same call stack frame - **/ + **/ beginEvent(profileName?: any, args?: any) { if (_enabled) { - profileName = typeof profileName === 'function' ? - profileName() : profileName; + profileName = + typeof profileName === 'function' ? profileName() : profileName; global.nativeTraceBeginSection(TRACE_TAG_REACT_APPS, profileName, args); } }, @@ -150,33 +155,41 @@ const Systrace = { * beginAsyncEvent/endAsyncEvent for starting and then ending a profile where the end can either * occur on another thread or out of the current stack frame, eg await * the returned cookie variable should be used as input into the endAsyncEvent call to end the profile - **/ + **/ beginAsyncEvent(profileName?: any): any { const cookie = _asyncCookie; if (_enabled) { _asyncCookie++; - profileName = typeof profileName === 'function' ? - profileName() : profileName; - global.nativeTraceBeginAsyncSection(TRACE_TAG_REACT_APPS, profileName, cookie); + profileName = + typeof profileName === 'function' ? profileName() : profileName; + global.nativeTraceBeginAsyncSection( + TRACE_TAG_REACT_APPS, + profileName, + cookie, + ); } return cookie; }, endAsyncEvent(profileName?: any, cookie?: any) { if (_enabled) { - profileName = typeof profileName === 'function' ? - profileName() : profileName; - global.nativeTraceEndAsyncSection(TRACE_TAG_REACT_APPS, profileName, cookie); + profileName = + typeof profileName === 'function' ? profileName() : profileName; + global.nativeTraceEndAsyncSection( + TRACE_TAG_REACT_APPS, + profileName, + cookie, + ); } }, /** * counterEvent registers the value to the profileName on the systrace timeline - **/ + **/ counterEvent(profileName?: any, value?: any) { if (_enabled) { - profileName = typeof profileName === 'function' ? - profileName() : profileName; + profileName = + typeof profileName === 'function' ? profileName() : profileName; global.nativeTraceCounter && global.nativeTraceCounter(TRACE_TAG_REACT_APPS, profileName, value); } @@ -185,7 +198,7 @@ const Systrace = { /** * Relay profiles use await calls, so likely occur out of current stack frame * therefore async variant of profiling is used - **/ + **/ attachToRelayProfiler(relayProfiler: RelayProfiler) { relayProfiler.attachProfileHandler('*', (name, state?) => { if (state != null && state.queryName !== undefined) { @@ -207,60 +220,61 @@ const Systrace = { /* This is not called by default due to perf overhead but it's useful if you want to find traces which spend too much time in JSON. */ swizzleJSON() { - Systrace.measureMethods(JSON, 'JSON', [ - 'parse', - 'stringify' - ]); + Systrace.measureMethods(JSON, 'JSON', ['parse', 'stringify']); }, - /** - * Measures multiple methods of a class. For example, you can do: - * Systrace.measureMethods(JSON, 'JSON', ['parse', 'stringify']); - * - * @param object - * @param objectName - * @param methodNames Map from method names to method display names. - */ - measureMethods(object: any, objectName: string, methodNames: Array): void { - if (!__DEV__) { - return; - } + /** + * Measures multiple methods of a class. For example, you can do: + * Systrace.measureMethods(JSON, 'JSON', ['parse', 'stringify']); + * + * @param object + * @param objectName + * @param methodNames Map from method names to method display names. + */ + measureMethods( + object: any, + objectName: string, + methodNames: Array, + ): void { + if (!__DEV__) { + return; + } - methodNames.forEach(methodName => { - object[methodName] = Systrace.measure( - objectName, - methodName, - object[methodName] - ); - }); - }, + methodNames.forEach(methodName => { + object[methodName] = Systrace.measure( + objectName, + methodName, + object[methodName], + ); + }); + }, - /** - * Returns an profiled version of the input function. For example, you can: - * JSON.parse = Systrace.measure('JSON', 'parse', JSON.parse); - * - * @param objName - * @param fnName - * @param {function} func - * @return {function} replacement function - */ - measure(objName: string, fnName: string, func: any): any { - if (!__DEV__) { - return func; - } + /** + * Returns an profiled version of the input function. For example, you can: + * JSON.parse = Systrace.measure('JSON', 'parse', JSON.parse); + * + * @param objName + * @param fnName + * @param {function} func + * @return {function} replacement function + */ + measure(objName: string, fnName: string, func: any): any { + if (!__DEV__) { + return func; + } - const profileName = `${objName}.${fnName}`; - return function() { - if (!_enabled) { - return func.apply(this, arguments); - } + const profileName = `${objName}.${fnName}`; + return function() { + if (!_enabled) { + return func.apply(this, arguments); + } - Systrace.beginEvent(profileName); - const ret = func.apply(this, arguments); - Systrace.endEvent(); - return ret; - }; - }, + Systrace.beginEvent(profileName); + const ret = func.apply(this, arguments); + Systrace.endEvent(); + return ret; + }; + }, }; if (__DEV__) {