Files
react-native/Libraries/Performance/Systrace.js
T
Rubén Norte a0f56adb07 Refactor Systrace module
Summary:
This refactors the systrace module to:
1) Migrate it to ESM
2) Fix the typing of certain parameters (e.g.: `eventName` and `cookie` shouldn't be optional)
2) Fix TypeScript definitions
3) Add inline documentation for methods
4) Add args (metadata) to all methods where it's supported in fbsystrace (`endEvent` and `endAsyncEvent`).
5) Make `setEnabled` a no-op. The only place where this method is called is from native, when starting a profile session. The problem is that implementation for Systrace in OSS (https://github.com/facebook/react-native/blob/main/ReactAndroid/src/main/java/com/facebook/systrace/Systrace.java#L40-L42) doesn't support listeners, so this wouldn't work correctly there. It also doesn't get called with Venice, so instead of fixing it for Venice with the same Meta-internal behavior, I decided to fix it for everyone with the synchronous method.

I'm not considering this a change in the public API of systrace because this module has been broken in OSS for ages and I'm assuming no one's using it at this point.

Changelog: [internal]

Reviewed By: rshest

Differential Revision: D40095842

fbshipit-source-id: fee41b2b7ae23aefe059e390c55d139db75247c5
2022-10-05 15:17:53 -07:00

133 lines
3.6 KiB
JavaScript

/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import * as Systrace from './Systrace';
const TRACE_TAG_REACT_APPS = 1 << 17; // eslint-disable-line no-bitwise
let _enabled = false;
let _asyncCookie = 0;
type EventName = string | (() => string);
type EventArgs = ?{[string]: string};
/**
* Indicates if the application is currently being traced.
*
* Calling methods on this module when the application isn't being traced is
* cheap, but this method can be used to avoid computing expensive values for
* those functions.
*
* @example
* if (Systrace.isEnabled()) {
* const expensiveArgs = computeExpensiveArgs();
* Systrace.beginEvent('myEvent', expensiveArgs);
* }
*/
export function isEnabled(): boolean {
return _enabled;
}
/**
* @deprecated This function is now a no-op but it's left for backwards
* compatibility. `isEnabled` will now synchronously check if we're actively
* profiling or not. This is necessary because we don't have callbacks to know
* when profiling has started/stopped on Android APIs.
*/
export function setEnabled(_doEnable: boolean): void {}
/**
* Marks the start of a synchronous event that should end in the same stack
* frame. The end of this event should be marked using the `endEvent` function.
*/
export function beginEvent(eventName: EventName, args?: EventArgs): void {
if (_enabled) {
const eventNameString =
typeof eventName === 'function' ? eventName() : eventName;
global.nativeTraceBeginSection(TRACE_TAG_REACT_APPS, eventNameString, args);
}
}
/**
* Marks the end of a synchronous event started in the same stack frame.
*/
export function endEvent(args?: EventArgs): void {
if (_enabled) {
global.nativeTraceEndSection(TRACE_TAG_REACT_APPS, args);
}
}
/**
* Marks the start of a potentially asynchronous event. The end of this event
* should be marked calling the `endAsyncEvent` function with the cookie
* returned by this function.
*/
export function beginAsyncEvent(
eventName: EventName,
args?: EventArgs,
): number {
const cookie = _asyncCookie;
if (_enabled) {
_asyncCookie++;
const eventNameString =
typeof eventName === 'function' ? eventName() : eventName;
global.nativeTraceBeginAsyncSection(
TRACE_TAG_REACT_APPS,
eventNameString,
cookie,
args,
);
}
return cookie;
}
/**
* Marks the end of a potentially asynchronous event, which was started with
* the given cookie.
*/
export function endAsyncEvent(
eventName: EventName,
cookie: number,
args?: EventArgs,
): void {
if (_enabled) {
const eventNameString =
typeof eventName === 'function' ? eventName() : eventName;
global.nativeTraceEndAsyncSection(
TRACE_TAG_REACT_APPS,
eventNameString,
cookie,
args,
);
}
}
/**
* Registers a new value for a counter event.
*/
export function counterEvent(eventName: EventName, value: number): void {
if (_enabled) {
const eventNameString =
typeof eventName === 'function' ? eventName() : eventName;
global.nativeTraceCounter &&
global.nativeTraceCounter(TRACE_TAG_REACT_APPS, eventNameString, value);
}
}
if (__DEV__) {
// The metro require polyfill can not have dependencies (true for all polyfills).
// Ensure that `Systrace` is available in polyfill by exposing it globally.
global[(global.__METRO_GLOBAL_PREFIX__ || '') + '__SYSTRACE'] = Systrace;
}
if (global.__RCTProfileIsProfiling) {
_enabled = true;
}