Files
react-native/private/react-native-fantom/src/Benchmark.js
Rubén NorteandFacebook GitHub Bot 6bfc1187a8 Improve formatting for benchmark output (#52106)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/52106

Changelog: [internal]

This slightly improves the formatting of the output produced by benchmarks, so we can just copy&paste the result to share it as valid Markdown.

Reviewed By: christophpurrer

Differential Revision: D76898244

fbshipit-source-id: dc1040ee3787c7f0dcb747c9fba8eb14086a0087
2025-06-18 09:36:36 -07:00

184 lines
4.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-local
* @format
*/
import {getConstants} from './index';
import nullthrows from 'nullthrows';
import NativeCPUTime from 'react-native/src/private/testing/fantom/specs/NativeCPUTime';
import {
Bench,
type BenchOptions,
type FnOptions,
type TaskResult,
} from 'tinybench';
type SuiteOptions = $ReadOnly<{
minIterations?: number,
minDuration?: number,
warmup?: boolean,
minWarmupDuration?: number,
minWarmupIterations?: number,
disableOptimizedBuildCheck?: boolean,
testOnly?: boolean,
}>;
type TestOptions = $ReadOnly<{
...FnOptions,
only?: boolean,
}>;
type SuiteResults = Array<$ReadOnly<TaskResult>>;
interface TestFunction {
(name: string, fn: () => void, options?: FnOptions): SuiteAPI;
only: (name: string, fn: () => void, options?: FnOptions) => SuiteAPI;
}
interface SuiteAPI {
+test: TestFunction;
verify(fn: (results: SuiteResults) => void): SuiteAPI;
}
export function suite(
suiteName: string,
suiteOptions?: SuiteOptions = {},
): SuiteAPI {
const tasks: Array<{
name: string,
fn: () => void,
options: TestOptions | void,
}> = [];
const verifyFns = [];
global.it(suiteName, () => {
if (tasks.length === 0) {
throw new Error('No benchmark tests defined');
}
const {isRunningFromCI} = getConstants();
// If we're running from CI and there's no verification function, there's
// no point in running the benchmark.
// We still run a single iteration of each test just to make sure that the
// logic in the benchmark doesn't break.
const isTestOnly =
suiteOptions.testOnly === true ||
(isRunningFromCI && verifyFns.length === 0);
const benchOptions: BenchOptions = isTestOnly
? {
warmup: false,
iterations: 1,
time: 0,
}
: {};
benchOptions.name = suiteName;
benchOptions.throws = true;
benchOptions.now = () => NativeCPUTime.getCPUTimeNanos() / 1000000;
if (!isTestOnly) {
if (suiteOptions.minIterations != null) {
benchOptions.iterations = suiteOptions.minIterations;
}
if (suiteOptions.minDuration != null) {
benchOptions.time = suiteOptions.minDuration;
}
if (suiteOptions.warmup != null) {
benchOptions.warmup = suiteOptions.warmup;
}
if (suiteOptions.minWarmupDuration != null) {
benchOptions.warmupTime = suiteOptions.minWarmupDuration;
}
if (suiteOptions.minWarmupIterations != null) {
benchOptions.warmupIterations = suiteOptions.minWarmupIterations;
}
}
const bench = new Bench(benchOptions);
const isFocused = tasks.find(task => task.options?.only === true) != null;
for (const task of tasks) {
if (isFocused && task.options?.only !== true) {
continue;
}
const {only, ...options} = task.options ?? {};
bench.add(task.name, task.fn, options);
}
bench.runSync();
if (!isTestOnly) {
printBenchmarkResults(bench);
}
for (const verify of verifyFns) {
verify(bench.results);
}
if (!isTestOnly && !NativeCPUTime.hasAccurateCPUTimeNanosForBenchmarks()) {
throw new Error(
'`NativeCPUTime` module does not provide accurate CPU time information in this environment. Please run the benchmarks in an environment where it does.',
);
}
if (__DEV__ && suiteOptions.disableOptimizedBuildCheck !== true) {
throw new Error('Benchmarks should not be run in development mode');
}
if (isFocused) {
throw new Error(
'Failing focused test to prevent it from being committed',
);
}
});
const test = (
name: string,
fn: () => void,
options?: FnOptions,
): SuiteAPI => {
tasks.push({name, fn, options});
return suiteAPI;
};
test.only = (name: string, fn: () => void, options?: FnOptions): SuiteAPI => {
tasks.push({name, fn, options: {...options, only: true}});
return suiteAPI;
};
const suiteAPI = {
test,
verify(fn: (results: SuiteResults) => void): SuiteAPI {
verifyFns.push(fn);
return suiteAPI;
},
};
return suiteAPI;
}
function printBenchmarkResults(bench: Bench) {
const {fantomConfigSummary} = getConstants();
const benchmarkName =
(bench.name ?? 'Benchmark') +
(fantomConfigSummary ? ` (${fantomConfigSummary})` : '');
console.log('');
console.log(`### ${benchmarkName} ###`);
console.table(nullthrows(bench.table()));
console.log('');
}