From ba788c2dadef58b8ab26fc61b6bc70426eaeeae7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Norte?= Date: Fri, 22 May 2026 04:45:50 -0700 Subject: [PATCH] Add `trace` helper to Systrace (#56936) Summary: Adds a new `trace` helper to the `Systrace` module that wraps a function call between `beginEvent` and `endEvent`, ensuring the trace section is closed even if the function throws. Usage: ``` Systrace.trace('name', () => { // logic to trace }); ``` The implementation is guarded with `isEnabled()` and inlines `beginEvent`/`endEvent` so that the no-op path avoids redundant work when tracing is disabled. Changelog: [General][Added] - Add `Systrace.trace` helper that wraps a function with begin/end events using try/finally Reviewed By: javache Differential Revision: D106071568 --- .../Libraries/Performance/Systrace.js | 28 +++++++++++++++++++ packages/react-native/ReactNativeApi.d.ts | 10 +++++-- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/packages/react-native/Libraries/Performance/Systrace.js b/packages/react-native/Libraries/Performance/Systrace.js index 4e1be11ce6f5..8b636f13f345 100644 --- a/packages/react-native/Libraries/Performance/Systrace.js +++ b/packages/react-native/Libraries/Performance/Systrace.js @@ -65,6 +65,33 @@ export function endEvent(args?: EventArgs): void { } } +/** + * Traces the execution of the given function by marking its start with + * `beginEvent` and its end with `endEvent`, even if the function throws. + * + * @example + * Systrace.trace('myEvent', () => { + * // logic to trace + * }); + */ +export function trace( + eventName: EventName, + fn: () => T, + args?: EventArgs, +): T { + if (isEnabled()) { + const eventNameString = + typeof eventName === 'function' ? eventName() : eventName; + global.nativeTraceBeginSection(TRACE_TAG_REACT, eventNameString, args); + try { + return fn(); + } finally { + global.nativeTraceEndSection(TRACE_TAG_REACT); + } + } + return fn(); +} + /** * Marks the start of a potentially asynchronous event. The end of this event * should be marked calling the `endAsyncEvent` function with the cookie @@ -128,6 +155,7 @@ if (__DEV__) { setEnabled, beginEvent, endEvent, + trace, beginAsyncEvent, endAsyncEvent, counterEvent, diff --git a/packages/react-native/ReactNativeApi.d.ts b/packages/react-native/ReactNativeApi.d.ts index 12b2066109a4..abd52ddb4370 100644 --- a/packages/react-native/ReactNativeApi.d.ts +++ b/packages/react-native/ReactNativeApi.d.ts @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<7f88fbd0bea021db8f52ca8ef3709d9e>> + * @generated SignedSource<<08dd369849273136812ea5edbda6e1df>> * * This file was generated by scripts/js-api/build-types/index.js. */ @@ -5041,6 +5041,7 @@ declare namespace Systrace { setEnabled, beginEvent, endEvent, + trace, beginAsyncEvent, endAsyncEvent, counterEvent, @@ -5628,6 +5629,11 @@ declare type TouchEventProps = { readonly onTouchStart?: (e: GestureResponderEvent) => void readonly onTouchStartCapture?: (e: GestureResponderEvent) => void } +declare function trace( + eventName: EventName, + fn: () => T, + args?: EventArgs, +): T declare type TransformsStyle = ____TransformStyle_Internal declare interface TurboModule extends DEPRECATED_RCTExport {} declare namespace TurboModuleRegistry { @@ -6217,7 +6223,7 @@ export { Switch, // 015be3f7 SwitchChangeEvent, // 63e9c50b SwitchProps, // 0dbf23ea - Systrace, // b5aa21fc + Systrace, // 626d178c TVViewPropsIOS, // 330ce7b5 TargetedEvent, // 16e98910 TaskProvider, // 266dedf2