diff --git a/packages/react-native/Libraries/Components/View/__tests__/View-vs-ViewNativeComponent-benchmark-itest.js b/packages/react-native/Libraries/Components/View/__tests__/View-vs-ViewNativeComponent-benchmark-itest.js new file mode 100644 index 00000000000..1d9370309d9 --- /dev/null +++ b/packages/react-native/Libraries/Components/View/__tests__/View-vs-ViewNativeComponent-benchmark-itest.js @@ -0,0 +1,60 @@ +/** + * 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-local + * @format + */ + +import '@react-native/fantom/src/setUpDefaultReactNativeEnvironment'; + +import measureRenderTime from '../../../../src/private/__tests__/utilities/measureRenderTime'; +import ViewNativeComponent from '../ViewNativeComponent'; +import * as Fantom from '@react-native/fantom'; +import * as React from 'react'; +import {View} from 'react-native'; + +let root; +let testViews: React.MixedElement; + +const NUMBER_OF_VIEWS = 100; +const NUMBER_OF_ITERATIONS = 1000; + +component Noop(children: React.Node, style?: mixed) { + return children; +} + +Noop.displayName = 'Noop'; + +Fantom.unstable_benchmark + .suite('View vs. ViewNativeComponent', {minIterations: NUMBER_OF_ITERATIONS}) + .test.each( + [Noop, ViewNativeComponent, View], + Component => + `render ${NUMBER_OF_VIEWS} views (${Component.displayName ?? Component.name ?? 'ViewNativeComponent'})`, + () => { + return { + overriddenDuration: measureRenderTime(root, testViews), + }; + }, + Component => ({ + beforeAll: () => { + let views: React.Node = null; + for (let i = 0; i < NUMBER_OF_VIEWS; i++) { + views = ( + {views} + ); + } + // $FlowExpectedError[incompatible-type] + testViews = views; + }, + beforeEach: () => { + root = Fantom.createRoot(); + }, + afterEach: () => { + root.destroy(); + }, + }), + ); diff --git a/packages/react-native/src/private/__tests__/utilities/measureRenderTime.js b/packages/react-native/src/private/__tests__/utilities/measureRenderTime.js new file mode 100644 index 00000000000..938a85d3bf1 --- /dev/null +++ b/packages/react-native/src/private/__tests__/utilities/measureRenderTime.js @@ -0,0 +1,46 @@ +/** + * 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-local + * @format + * @oncall react_native + */ + +import * as Fantom from '@react-native/fantom'; +import nullthrows from 'nullthrows'; + +const now = Fantom.unstable_benchmark.now; + +export default function measureRenderTime( + root: Fantom.Root, + elements: React.MixedElement, +): number { + let startTime: ?number; + let endTime: ?number; + + function RecordStart() { + startTime ??= now(); + return null; + } + + function RecordEnd() { + endTime = now(); + return null; + } + + Fantom.runTask(() => { + // React renders nodes using a depth-first algorithm. + root.render( + <> + + {elements} + + , + ); + }); + + return nullthrows(endTime) - nullthrows(startTime); +}