Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,14 @@ declare module 'tinybench' {
beforeEach?: (this: Task) => void | Promise<void>,
};

export type Fn = () => Promise<mixed> | mixed;
export interface FnReturnedObject {
overriddenDuration?: number;
}

export type Fn = () =>
| Promise<void | FnReturnedObject>
| void
| FnReturnedObject;

declare export class Bench extends EventTarget {
concurrency: null | 'task' | 'bench';
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@
"signedsource": "^1.0.0",
"supports-color": "^7.1.0",
"temp-dir": "^2.0.0",
"tinybench": "^3.1.0",
"tinybench": "^4.1.0",
"typescript": "5.8.3",
"ws": "^6.2.3"
},
Expand Down
Original file line number Diff line number Diff line change
@@ -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 = (
<Component style={{width: i + 1, height: i + 1}}>{views}</Component>
);
}
// $FlowExpectedError[incompatible-type]
testViews = views;
},
beforeEach: () => {
root = Fantom.createRoot();
},
afterEach: () => {
root.destroy();
},
}),
);
Original file line number Diff line number Diff line change
@@ -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(
<>
<RecordStart />
{elements}
<RecordEnd />
</>,
);
});

return nullthrows(endTime) - nullthrows(startTime);
}
29 changes: 15 additions & 14 deletions private/react-native-fantom/src/Benchmark.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import NativeCPUTime from 'react-native/src/private/testing/fantom/specs/NativeC
import {
Bench,
type BenchOptions,
type Fn,
type FnOptions,
type TaskResult,
} from 'tinybench';
Expand Down Expand Up @@ -65,20 +66,20 @@ interface ParameterizedTestFunction {
<TestArgType>(
testArgs: $ReadOnlyArray<TestArgType>,
name: TestWithArgName<TestArgType>,
fn: (testArg: TestArgType) => void,
fn: (testArg: TestArgType) => ReturnType<Fn>,
options?: TestWithArgOptions<TestArgType>,
): SuiteAPI;
only: <TestArgType>(
testArgs: $ReadOnlyArray<TestArgType>,
name: TestWithArgName<TestArgType>,
fn: (testArg: TestArgType) => void,
fn: (testArg: TestArgType) => ReturnType<Fn>,
options?: TestWithArgOptions<TestArgType>,
) => SuiteAPI;
}

interface TestFunction {
(name: string, fn: () => void, options?: FnOptions): SuiteAPI;
only: (name: string, fn: () => void, options?: FnOptions) => SuiteAPI;
(name: string, fn: Fn, options?: FnOptions): SuiteAPI;
only: (name: string, fn: Fn, options?: FnOptions) => SuiteAPI;
// `each` allows to run the same test multiple times with different arguments, provided as an array of values:
each: ParameterizedTestFunction;
}
Expand All @@ -90,10 +91,14 @@ interface SuiteAPI {

interface TestTask {
name: string;
fn: () => void;
fn: Fn;
options: InternalTestOptions | void;
}

export function now(): number {
return NativeCPUTime.getCPUTimeNanos() / 1000000;
}

export function suite(
suiteName: string,
suiteOptions?: SuiteOptions = {},
Expand Down Expand Up @@ -127,7 +132,7 @@ export function suite(

benchOptions.name = suiteName;
benchOptions.throws = true;
benchOptions.now = () => NativeCPUTime.getCPUTimeNanos() / 1000000;
benchOptions.now = now;

if (!isTestOnly) {
if (suiteOptions.minIterations != null) {
Expand Down Expand Up @@ -197,24 +202,20 @@ export function suite(
reportBenchmarkResult(createBenchmarkResultsObject(bench, tasks));
});

const test = (
name: string,
fn: () => void,
options?: FnOptions,
): SuiteAPI => {
const test = (name: string, fn: Fn, options?: FnOptions): SuiteAPI => {
tasks.push({name, fn, options});
return suiteAPI;
};

test.only = (name: string, fn: () => void, options?: FnOptions): SuiteAPI => {
test.only = (name: string, fn: Fn, options?: FnOptions): SuiteAPI => {
tasks.push({name, fn, options: {...options, only: true}});
return suiteAPI;
};

const testWithArg = <TestArgType>(
testArg: TestArgType,
name: TestWithArgName<TestArgType>,
fn: (testArg: TestArgType) => void,
fn: (testArg: TestArgType) => ReturnType<Fn>,
options?: TestWithArgOptions<TestArgType>,
only?: boolean = false,
): TestTask => {
Expand All @@ -232,7 +233,7 @@ export function suite(
const testEach: ParameterizedTestFunction = <TestArgType>(
testArgs: $ReadOnlyArray<TestArgType>,
name: TestWithArgName<TestArgType>,
fn: (testArg: TestArgType) => void,
fn: (testArg: TestArgType) => ReturnType<Fn>,
options?: TestWithArgOptions<TestArgType>,
): SuiteAPI => {
for (const testArg of testArgs) {
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -9121,10 +9121,10 @@ through@^2.3.6:
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==

tinybench@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/tinybench/-/tinybench-3.1.0.tgz#ec68451ff05233cf3de12c46f39f06011897109a"
integrity sha512-Km+oMh2xqNCxuyoUsqbRmHgFSd8sATh7v7xreP+kHN6x67w28Pawr83WmBxcaORvxkc0Ex6zgqK951yBnTFaaQ==
tinybench@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/tinybench/-/tinybench-4.1.0.tgz#090118e51159eb105f3cc2ef5cf371f3f8adc7bf"
integrity sha512-8JZoQRJgWWEIIeAmpiNmMHIREmUY3oGX8GRmlmNapLr/qtgMe+K76vM2qabh85hNScnE2lqTVTajVETjuD9Ixg==

tmp@^0.0.33:
version "0.0.33"
Expand Down
Loading