From 2632895ed296f846f65d00c8c99c3493594ba946 Mon Sep 17 00:00:00 2001
From: Abhijeet Jha <74712637+iamAbhi-916@users.noreply.github.com>
Date: Thu, 12 Mar 2026 14:17:06 +0530
Subject: [PATCH 01/11] add native perf benchmarking infrastructure for Fabric
components
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
measures
rendering pipeline — JS reconciliation → Fabric → Yoga layout → Composition commit → frame
Missing Components: Button, Modal, Pressable, TouchableHighlight, TouchableOpacity, SectionList.
---
.github/workflows/perf-tests.yml | 11 +-
.../src/config/thresholdPresets.ts | 10 +
.../NativePerfBenchmarkExample.js | 228 +++++++++++++
.../src/js/utils/RNTesterList.windows.js | 5 +
.../jest.native-perf.config.js | 71 ++++
packages/e2e-test-app-fabric/package.json | 5 +-
.../test/NativePerfHelpers.ts | 112 ++++++
.../core/View.native-perf-test.ts | 78 +++++
...iew.native-perf-test.ts.perf-baseline.json | 320 ++++++++++++++++++
9 files changed, 838 insertions(+), 2 deletions(-)
create mode 100644 packages/@react-native-windows/tester/src/js/examples-win/NativePerfBenchmark/NativePerfBenchmarkExample.js
create mode 100644 packages/e2e-test-app-fabric/jest.native-perf.config.js
create mode 100644 packages/e2e-test-app-fabric/test/NativePerfHelpers.ts
create mode 100644 packages/e2e-test-app-fabric/test/__native_perf__/core/View.native-perf-test.ts
create mode 100644 packages/e2e-test-app-fabric/test/__native_perf__/core/__perf_snapshots__/View.native-perf-test.ts.perf-baseline.json
diff --git a/.github/workflows/perf-tests.yml b/.github/workflows/perf-tests.yml
index d29a71a3290..19f36f67b18 100644
--- a/.github/workflows/perf-tests.yml
+++ b/.github/workflows/perf-tests.yml
@@ -61,7 +61,14 @@ jobs:
RN_TARGET_PLATFORM: windows
run: yarn perf:ci
continue-on-error: true # Don't fail here — let comparison decide
-
+ - name: Run native perf tests
+ id: native-perf-run
+ working-directory: packages/e2e-test-app-fabric
+ env:
+ CI: 'true'
+ RN_TARGET_PLATFORM: windows
+ run: yarn perf:native:ci
+ continue-on-error: true
# ── Compare & Report ───────────────────────────────────
- name: Compare against baselines
id: compare
@@ -80,7 +87,9 @@ jobs:
name: perf-results
path: |
packages/e2e-test-app-fabric/.perf-results/
+ packages/e2e-test-app-fabric/.native-perf-results/
packages/e2e-test-app-fabric/test/__perf__/**/__perf_snapshots__/
+ packages/e2e-test-app-fabric/test/__native_perf__/**/__perf_snapshots__/
retention-days: 30
# ── Status Gate ────────────────────────────────────────
diff --git a/packages/@react-native-windows/perf-testing/src/config/thresholdPresets.ts b/packages/@react-native-windows/perf-testing/src/config/thresholdPresets.ts
index 3b1b260c488..02d6880c104 100644
--- a/packages/@react-native-windows/perf-testing/src/config/thresholdPresets.ts
+++ b/packages/@react-native-windows/perf-testing/src/config/thresholdPresets.ts
@@ -56,4 +56,14 @@ export const ThresholdPresets: Readonly<
maxCV: 0.6,
mode: 'track',
},
+
+ native: {
+ maxDurationIncrease: 15,
+ maxDuration: Infinity,
+ minAbsoluteDelta: 5,
+ maxRenderCount: 1,
+ minRuns: 10,
+ maxCV: 0.5,
+ mode: 'gate',
+ },
};
diff --git a/packages/@react-native-windows/tester/src/js/examples-win/NativePerfBenchmark/NativePerfBenchmarkExample.js b/packages/@react-native-windows/tester/src/js/examples-win/NativePerfBenchmark/NativePerfBenchmarkExample.js
new file mode 100644
index 00000000000..dab42e7b432
--- /dev/null
+++ b/packages/@react-native-windows/tester/src/js/examples-win/NativePerfBenchmark/NativePerfBenchmarkExample.js
@@ -0,0 +1,228 @@
+/**
+ * Copyright (c) Microsoft Corporation.
+ * Licensed under the MIT License.
+ * @format
+ */
+
+'use strict';
+
+const React = require('react');
+const {
+ View,
+ Text,
+ TextInput,
+ Image,
+ ScrollView,
+ FlatList,
+ Switch,
+ ActivityIndicator,
+ Pressable,
+ StyleSheet,
+} = require('react-native');
+
+const {useState, useRef, useCallback, useEffect} = React;
+
+const PHASE_IDLE = 'idle';
+const PHASE_CLEARING = 'clearing';
+const PHASE_MOUNTING = 'mounting';
+const PHASE_DONE = 'done';
+
+const COMPONENT_REGISTRY = {
+ View: () => ,
+ Text: () => Benchmark Text,
+ TextInput: () => (
+
+ ),
+ Image: () => (
+
+ ),
+ ScrollView: () => (
+
+ {Array.from({length: 20}, (_, i) => (
+
+ ))}
+
+ ),
+ FlatList: () => (
+ ({key: String(i)}))}
+ renderItem={({item}) => {item.key}}
+ />
+ ),
+ Switch: () => ,
+ ActivityIndicator: () => ,
+};
+
+function BenchmarkRunner() {
+ const [componentName, setComponentName] = useState('View');
+ const [runsInput, setRunsInput] = useState('15');
+ const [phase, setPhase] = useState(PHASE_IDLE);
+ const [showTarget, setShowTarget] = useState(false);
+ const [resultsJson, setResultsJson] = useState('');
+
+ const durationsRef = useRef([]);
+ const runIndexRef = useRef(0);
+ const totalRunsRef = useRef(15);
+ const markNameRef = useRef('');
+
+ const finishRun = useCallback(() => {
+ const markEnd = `perf-end-${runIndexRef.current}`;
+ performance.mark(markEnd);
+ try {
+ const measure = performance.measure(
+ `perf-run-${runIndexRef.current}`,
+ markNameRef.current,
+ markEnd,
+ );
+ durationsRef.current.push(measure.duration);
+ } catch (_) {}
+ performance.clearMarks(markNameRef.current);
+ performance.clearMarks(markEnd);
+ performance.clearMeasures(`perf-run-${runIndexRef.current}`);
+
+ runIndexRef.current++;
+ if (runIndexRef.current < totalRunsRef.current) {
+ setPhase(PHASE_CLEARING);
+ } else {
+ setShowTarget(false);
+ setResultsJson(
+ JSON.stringify({
+ componentName,
+ runs: durationsRef.current.length,
+ durations: durationsRef.current,
+ }),
+ );
+ setPhase(PHASE_DONE);
+ }
+ }, [componentName]);
+
+ useEffect(() => {
+ if (phase === PHASE_CLEARING) {
+ setShowTarget(false);
+ requestAnimationFrame(() => {
+ setPhase(PHASE_MOUNTING);
+ });
+ }
+ }, [phase]);
+
+ useEffect(() => {
+ if (phase === PHASE_MOUNTING) {
+ const markStart = `perf-start-${runIndexRef.current}`;
+ markNameRef.current = markStart;
+ performance.mark(markStart);
+ setShowTarget(true);
+ }
+ }, [phase]);
+
+ useEffect(() => {
+ if (phase === PHASE_MOUNTING && showTarget) {
+ requestAnimationFrame(() => {
+ finishRun();
+ });
+ }
+ }, [phase, showTarget, finishRun]);
+
+ const handleRun = useCallback(() => {
+ const runs = parseInt(runsInput, 10) || 15;
+ totalRunsRef.current = runs;
+ runIndexRef.current = 0;
+ durationsRef.current = [];
+ setResultsJson('');
+ setPhase(PHASE_CLEARING);
+ }, [runsInput]);
+
+ const ComponentFactory = COMPONENT_REGISTRY[componentName];
+
+ return (
+
+
+
+
+
+ Run Benchmark
+
+
+
+
+ {phase}
+
+
+
+ {showTarget && ComponentFactory ? : null}
+
+
+
+ {resultsJson}
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: {flex: 1, padding: 8},
+ controls: {flexDirection: 'row', gap: 8, marginBottom: 8},
+ input: {
+ borderWidth: 1,
+ borderColor: '#ccc',
+ padding: 6,
+ minWidth: 100,
+ fontSize: 14,
+ },
+ button: {
+ backgroundColor: '#0078D4',
+ paddingHorizontal: 16,
+ paddingVertical: 8,
+ borderRadius: 4,
+ justifyContent: 'center',
+ },
+ buttonText: {color: 'white', fontWeight: 'bold'},
+ status: {fontSize: 12, color: '#666', marginBottom: 4},
+ targetContainer: {
+ minHeight: 100,
+ borderWidth: 1,
+ borderColor: '#eee',
+ marginBottom: 8,
+ },
+ target: {width: 80, height: 80, backgroundColor: '#f0f0f0'},
+ targetInput: {width: 200, height: 40, borderWidth: 1, borderColor: '#999'},
+ targetImage: {width: 80, height: 80},
+ scrollItem: {height: 20, backgroundColor: '#ddd', marginBottom: 2},
+ results: {fontSize: 10, fontFamily: 'monospace', color: '#333'},
+});
+
+exports.displayName = 'NativePerfBenchmarkExample';
+exports.framework = 'React';
+exports.category = 'Basic';
+exports.title = 'Native Perf Benchmark';
+exports.description =
+ 'Measures native rendering pipeline via performance.mark/measure.';
+
+exports.examples = [
+ {
+ title: 'Benchmark Runner',
+ render: function () {
+ return ;
+ },
+ },
+];
diff --git a/packages/@react-native-windows/tester/src/js/utils/RNTesterList.windows.js b/packages/@react-native-windows/tester/src/js/utils/RNTesterList.windows.js
index c9c15047b6c..8237d6778af 100644
--- a/packages/@react-native-windows/tester/src/js/utils/RNTesterList.windows.js
+++ b/packages/@react-native-windows/tester/src/js/utils/RNTesterList.windows.js
@@ -212,6 +212,11 @@ const Components: Array = [
category: 'Basic',
module: require('../examples/Performance/PerformanceComparisonExample'),
},
+ {
+ key: 'NativePerfBenchmark',
+ category: 'Basic',
+ module: require('../examples-win/NativePerfBenchmark/NativePerfBenchmarkExample'),
+ },
...RNTesterListFbInternal.Components,
];
diff --git a/packages/e2e-test-app-fabric/jest.native-perf.config.js b/packages/e2e-test-app-fabric/jest.native-perf.config.js
new file mode 100644
index 00000000000..0b31ca9fb5e
--- /dev/null
+++ b/packages/e2e-test-app-fabric/jest.native-perf.config.js
@@ -0,0 +1,71 @@
+/**
+ * Copyright (c) Microsoft Corporation.
+ * Licensed under the MIT License.
+ * @format
+ * @ts-check
+ */
+
+const assetTransform = 'react-native-windows/jest/assetFileTransformer.js';
+
+module.exports = {
+ preset: '@rnx-kit/jest-preset',
+
+ roots: ['/test/'],
+ testMatch: ['**/__native_perf__/**/*.native-perf-test.{ts,tsx}'],
+
+ testEnvironment: '@react-native-windows/automation',
+
+ testTimeout: 180000,
+
+ maxWorkers: 1,
+
+ setupFilesAfterEnv: [
+ 'react-native-windows/jest/setup',
+ './jest.perf.setup.ts',
+ ],
+
+ testEnvironmentOptions: {
+ app: 'RNTesterApp-Fabric',
+ useRootSession: true,
+ rootLaunchApp: true,
+ enableAutomationChannel: true,
+ },
+
+ transform: {
+ '\\.(bmp|gif|jpg|jpeg|mp4|png|psd|svg|webp)$': assetTransform,
+ 'node_modules\\\\@?react-native\\\\.*': 'babel-jest',
+ '@react-native-windows\\\\tester\\\\.*': 'babel-jest',
+ '@react-native-windows\\\\perf-testing\\\\.*': 'babel-jest',
+ 'vnext\\\\.*': 'babel-jest',
+ '\\.[jt]sx?$': 'babel-jest',
+ },
+
+ transformIgnorePatterns: ['jest-runner', 'node_modules\\\\safe-buffer'],
+
+ moduleFileExtensions: [
+ 'js',
+ 'windows.js',
+ 'android.js',
+ 'mjs',
+ 'cjs',
+ 'jsx',
+ 'ts',
+ 'windows.ts',
+ 'tsx',
+ 'windows.tsx',
+ 'json',
+ 'node',
+ ],
+
+ verbose: true,
+
+ reporters: process.env.CI
+ ? [
+ 'default',
+ [
+ '@react-native-windows/perf-testing/lib-commonjs/ci/PerfJsonReporter',
+ {outputFile: '.native-perf-results/results.json'},
+ ],
+ ]
+ : ['default'],
+};
diff --git a/packages/e2e-test-app-fabric/package.json b/packages/e2e-test-app-fabric/package.json
index 673ec0fa80f..e217c70fc97 100644
--- a/packages/e2e-test-app-fabric/package.json
+++ b/packages/e2e-test-app-fabric/package.json
@@ -19,7 +19,10 @@
"perf:ci": "jest --config jest.perf.config.js --ci --forceExit",
"perf:ci:compare": "node ../../vnext/Scripts/perf/compare-results.js",
"perf:ci:report": "node ../../vnext/Scripts/perf/post-pr-comment.js",
- "perf:create": "node ../../vnext/Scripts/perf/create-perf-test.js"
+ "perf:create": "node ../../vnext/Scripts/perf/create-perf-test.js",
+ "perf:native": "jest --config jest.native-perf.config.js",
+ "perf:native:update": "jest --config jest.native-perf.config.js -u",
+ "perf:native:ci": "jest --config jest.native-perf.config.js --ci --forceExit"
},
"dependencies": {
"@react-native-windows/automation-channel": "0.0.0-canary.1035",
diff --git a/packages/e2e-test-app-fabric/test/NativePerfHelpers.ts b/packages/e2e-test-app-fabric/test/NativePerfHelpers.ts
new file mode 100644
index 00000000000..589d36b9163
--- /dev/null
+++ b/packages/e2e-test-app-fabric/test/NativePerfHelpers.ts
@@ -0,0 +1,112 @@
+/**
+ * Copyright (c) Microsoft Corporation.
+ * Licensed under the MIT License.
+ * @format
+ */
+
+import {app} from '@react-native-windows/automation';
+import {goToComponentExample} from './RNTesterNavigation';
+import {
+ mean,
+ median,
+ standardDeviation,
+} from '@react-native-windows/perf-testing';
+import type {PerfMetrics} from '@react-native-windows/perf-testing';
+
+export interface NativePerfOptions {
+ runs?: number;
+ warmupRuns?: number;
+}
+
+const DEFAULT_RUNS = 15;
+const DEFAULT_WARMUP = 2;
+
+export async function navigateToBenchmarkPage(): Promise {
+ const componentsTab = await app.findElementByTestID('components-tab');
+ await componentsTab.waitForDisplayed({timeout: 60000});
+
+ await goToComponentExample('Native Perf Benchmark');
+}
+
+export async function measureNativePerf(
+ componentName: string,
+ options?: NativePerfOptions,
+): Promise {
+ const runs = options?.runs ?? DEFAULT_RUNS;
+ const warmupRuns = options?.warmupRuns ?? DEFAULT_WARMUP;
+ const totalRuns = runs + warmupRuns;
+
+ const componentInput = await app.findElementByTestID('perf-component-input');
+ await componentInput.waitForDisplayed({timeout: 5000});
+
+ await app.waitUntil(
+ async () => {
+ await componentInput.setValue(componentName);
+ return (await componentInput.getText()) === componentName;
+ },
+ {
+ interval: 500,
+ timeout: 5000,
+ timeoutMsg: `Failed to set component: ${componentName}`,
+ },
+ );
+
+ const runsInput = await app.findElementByTestID('perf-runs-input');
+ const runsStr = String(totalRuns);
+ await app.waitUntil(
+ async () => {
+ await runsInput.setValue(runsStr);
+ return (await runsInput.getText()) === runsStr;
+ },
+ {interval: 500, timeout: 5000, timeoutMsg: 'Failed to set run count'},
+ );
+
+ const runBtn = await app.findElementByTestID('perf-run-btn');
+ await runBtn.waitForDisplayed({timeout: 5000});
+ await runBtn.click();
+
+ const statusEl = await app.findElementByTestID('perf-status');
+ await app.waitUntil(
+ async () => {
+ const text = await statusEl.getText();
+ return text === 'done';
+ },
+ {
+ interval: 1000,
+ timeout: 180000,
+ timeoutMsg: `Benchmark timed out for ${componentName}`,
+ },
+ );
+
+ const resultsEl = await app.findElementByTestID('perf-results');
+ const rawJson = await resultsEl.getText();
+ const parsed = JSON.parse(rawJson) as {
+ componentName: string;
+ runs: number;
+ durations: number[];
+ };
+
+ const durations = parsed.durations.slice(warmupRuns);
+
+ if (durations.length < runs) {
+ throw new Error(
+ `Expected ${runs} durations after discarding ${warmupRuns} warmup, got ${durations.length}`,
+ );
+ }
+
+ const meanDuration = mean(durations);
+ const medianDuration = median(durations);
+ const stdDev = standardDeviation(durations);
+
+ return {
+ name: `${componentName} native mount`,
+ meanDuration,
+ medianDuration,
+ stdDev,
+ renderCount: 1,
+ runs: durations.length,
+ durations,
+ timestamp: new Date().toISOString(),
+ nativeTimings: {fullPipeline: medianDuration},
+ };
+}
diff --git a/packages/e2e-test-app-fabric/test/__native_perf__/core/View.native-perf-test.ts b/packages/e2e-test-app-fabric/test/__native_perf__/core/View.native-perf-test.ts
new file mode 100644
index 00000000000..075642b1262
--- /dev/null
+++ b/packages/e2e-test-app-fabric/test/__native_perf__/core/View.native-perf-test.ts
@@ -0,0 +1,78 @@
+/**
+ * Copyright (c) Microsoft Corporation.
+ * Licensed under the MIT License.
+ * @format
+ */
+
+import {app} from '@react-native-windows/automation';
+import {ThresholdPresets} from '@react-native-windows/perf-testing';
+import {
+ navigateToBenchmarkPage,
+ measureNativePerf,
+} from '../../NativePerfHelpers';
+
+beforeAll(async () => {
+ await app.setWindowPosition(0, 0);
+ await app.setWindowSize(1000, 1250);
+ await navigateToBenchmarkPage();
+});
+
+const NATIVE = ThresholdPresets.native;
+
+describe('Core Components — Native Render Pipeline', () => {
+ test('View native mount', async () => {
+ const perf = await measureNativePerf('View', {runs: 15, warmupRuns: 2});
+ expect(perf).toMatchPerfSnapshot(NATIVE);
+ });
+
+ test('Text native mount', async () => {
+ const perf = await measureNativePerf('Text', {runs: 15, warmupRuns: 2});
+ expect(perf).toMatchPerfSnapshot(NATIVE);
+ });
+
+ test('TextInput native mount', async () => {
+ const perf = await measureNativePerf('TextInput', {
+ runs: 15,
+ warmupRuns: 2,
+ });
+ expect(perf).toMatchPerfSnapshot(NATIVE);
+ });
+
+ test('Image native mount', async () => {
+ const perf = await measureNativePerf('Image', {runs: 15, warmupRuns: 2});
+ expect(perf).toMatchPerfSnapshot(NATIVE);
+ });
+
+ test('Switch native mount', async () => {
+ const perf = await measureNativePerf('Switch', {runs: 15, warmupRuns: 2});
+ expect(perf).toMatchPerfSnapshot(NATIVE);
+ });
+
+ test('ActivityIndicator native mount', async () => {
+ const perf = await measureNativePerf('ActivityIndicator', {
+ runs: 15,
+ warmupRuns: 2,
+ });
+ expect(perf).toMatchPerfSnapshot(NATIVE);
+ });
+
+ test('ScrollView native mount', async () => {
+ const perf = await measureNativePerf('ScrollView', {
+ runs: 10,
+ warmupRuns: 2,
+ });
+ expect(perf).toMatchPerfSnapshot({...NATIVE, maxCV: 0.6});
+ });
+
+ test('FlatList native mount', async () => {
+ const perf = await measureNativePerf('FlatList', {
+ runs: 10,
+ warmupRuns: 2,
+ });
+ expect(perf).toMatchPerfSnapshot({
+ ...NATIVE,
+ maxDurationIncrease: 20,
+ maxCV: 0.6,
+ });
+ });
+});
diff --git a/packages/e2e-test-app-fabric/test/__native_perf__/core/__perf_snapshots__/View.native-perf-test.ts.perf-baseline.json b/packages/e2e-test-app-fabric/test/__native_perf__/core/__perf_snapshots__/View.native-perf-test.ts.perf-baseline.json
new file mode 100644
index 00000000000..1fc84e6f59e
--- /dev/null
+++ b/packages/e2e-test-app-fabric/test/__native_perf__/core/__perf_snapshots__/View.native-perf-test.ts.perf-baseline.json
@@ -0,0 +1,320 @@
+{
+ "Core Components — Native Render Pipeline View native mount 1": {
+ "metrics": {
+ "name": "View native mount",
+ "meanDuration": 7.965346668163935,
+ "medianDuration": 7.814400002360344,
+ "stdDev": 0.7503939989497768,
+ "renderCount": 1,
+ "runs": 15,
+ "durations": [
+ 9.190099999308586,
+ 7.984700009226799,
+ 7.7070000022649765,
+ 7.963699996471405,
+ 7.657600000500679,
+ 8.263199999928474,
+ 7.814400002360344,
+ 7.363900005817413,
+ 7.269499987363815,
+ 7.991300001740456,
+ 7.2847999930381775,
+ 7.353300005197525,
+ 7.56980000436306,
+ 8.03660000860691,
+ 10.030300006270409
+ ],
+ "timestamp": "2026-03-12T07:50:20.925Z",
+ "nativeTimings": {
+ "fullPipeline": 7.814400002360344
+ }
+ },
+ "threshold": {
+ "maxDurationIncrease": 15,
+ "maxDuration": null,
+ "minAbsoluteDelta": 5,
+ "maxRenderCount": 1,
+ "minRuns": 10,
+ "maxCV": 0.5,
+ "mode": "gate"
+ },
+ "capturedAt": "2026-03-12T07:50:20.926Z"
+ },
+ "Core Components — Native Render Pipeline Text native mount 1": {
+ "metrics": {
+ "name": "Text native mount",
+ "meanDuration": 8.775593332449596,
+ "medianDuration": 8.77089999616146,
+ "stdDev": 0.4363329788038993,
+ "renderCount": 1,
+ "runs": 15,
+ "durations": [
+ 8.25840000808239,
+ 9.665399998426437,
+ 8.581399992108345,
+ 8.77089999616146,
+ 9.273499995470047,
+ 9.550700008869171,
+ 8.49210000038147,
+ 8.254999995231628,
+ 8.475600004196167,
+ 8.775199994444847,
+ 8.822300001978874,
+ 8.951499998569489,
+ 8.40929999947548,
+ 8.890000000596046,
+ 8.462599992752075
+ ],
+ "timestamp": "2026-03-12T07:50:23.671Z",
+ "nativeTimings": {
+ "fullPipeline": 8.77089999616146
+ }
+ },
+ "threshold": {
+ "maxDurationIncrease": 15,
+ "maxDuration": null,
+ "minAbsoluteDelta": 5,
+ "maxRenderCount": 1,
+ "minRuns": 10,
+ "maxCV": 0.5,
+ "mode": "gate"
+ },
+ "capturedAt": "2026-03-12T07:50:23.673Z"
+ },
+ "Core Components — Native Render Pipeline TextInput native mount 1": {
+ "metrics": {
+ "name": "TextInput native mount",
+ "meanDuration": 11.196973330775897,
+ "medianDuration": 11.007999986410141,
+ "stdDev": 1.0020838707600381,
+ "renderCount": 1,
+ "runs": 15,
+ "durations": [
+ 10.245399996638298,
+ 11.007999986410141,
+ 11.696299999952316,
+ 10.852799996733665,
+ 11.64869999885559,
+ 11.229299992322922,
+ 13.262100011110306,
+ 12.7364000082016,
+ 10.52199999988079,
+ 10.773599997162819,
+ 11.078599989414215,
+ 10.190099999308586,
+ 10.107699990272522,
+ 10.069199994206429,
+ 12.534400001168251
+ ],
+ "timestamp": "2026-03-12T07:50:26.745Z",
+ "nativeTimings": {
+ "fullPipeline": 11.007999986410141
+ }
+ },
+ "threshold": {
+ "maxDurationIncrease": 15,
+ "maxDuration": null,
+ "minAbsoluteDelta": 5,
+ "maxRenderCount": 1,
+ "minRuns": 10,
+ "maxCV": 0.5,
+ "mode": "gate"
+ },
+ "capturedAt": "2026-03-12T07:50:26.749Z"
+ },
+ "Core Components — Native Render Pipeline Image native mount 1": {
+ "metrics": {
+ "name": "Image native mount",
+ "meanDuration": 10.385873334606488,
+ "medianDuration": 9.600000008940697,
+ "stdDev": 1.9376943291015232,
+ "renderCount": 1,
+ "runs": 15,
+ "durations": [
+ 13.439300000667572,
+ 10.480499997735023,
+ 9.600000008940697,
+ 10.026899993419647,
+ 10.172600001096725,
+ 9.45890000462532,
+ 9.476500004529953,
+ 9.03320001065731,
+ 8.662799999117851,
+ 9.664900004863739,
+ 8.988000005483627,
+ 8.744599997997284,
+ 9.567399993538857,
+ 13.752700001001358,
+ 14.719799995422363
+ ],
+ "timestamp": "2026-03-12T07:50:29.540Z",
+ "nativeTimings": {
+ "fullPipeline": 9.600000008940697
+ }
+ },
+ "threshold": {
+ "maxDurationIncrease": 15,
+ "maxDuration": null,
+ "minAbsoluteDelta": 5,
+ "maxRenderCount": 1,
+ "minRuns": 10,
+ "maxCV": 0.5,
+ "mode": "gate"
+ },
+ "capturedAt": "2026-03-12T07:50:29.542Z"
+ },
+ "Core Components — Native Render Pipeline Switch native mount 1": {
+ "metrics": {
+ "name": "Switch native mount",
+ "meanDuration": 8.576380000511806,
+ "medianDuration": 8.229400008916855,
+ "stdDev": 0.9039821852849624,
+ "renderCount": 1,
+ "runs": 15,
+ "durations": [
+ 8.542500004172325,
+ 7.743599995970726,
+ 8.209299996495247,
+ 8.209900006651878,
+ 8.184499993920326,
+ 8.811700001358986,
+ 8.229400008916855,
+ 10.605000004172325,
+ 7.775299996137619,
+ 9.013999998569489,
+ 8.496399998664856,
+ 10.643399998545647,
+ 8.300200000405312,
+ 8.071400001645088,
+ 7.8091000020504
+ ],
+ "timestamp": "2026-03-12T07:50:32.416Z",
+ "nativeTimings": {
+ "fullPipeline": 8.229400008916855
+ }
+ },
+ "threshold": {
+ "maxDurationIncrease": 15,
+ "maxDuration": null,
+ "minAbsoluteDelta": 5,
+ "maxRenderCount": 1,
+ "minRuns": 10,
+ "maxCV": 0.5,
+ "mode": "gate"
+ },
+ "capturedAt": "2026-03-12T07:50:32.418Z"
+ },
+ "Core Components — Native Render Pipeline ActivityIndicator native mount 1": {
+ "metrics": {
+ "name": "ActivityIndicator native mount",
+ "meanDuration": 9.51423999965191,
+ "medianDuration": 9.150399997830391,
+ "stdDev": 1.159785279255848,
+ "renderCount": 1,
+ "runs": 15,
+ "durations": [
+ 10.353200003504753,
+ 13.115099996328354,
+ 9.150399997830391,
+ 9.891000002622604,
+ 9.216000005602837,
+ 9.149099990725517,
+ 9.298500001430511,
+ 9.369599997997284,
+ 8.87389999628067,
+ 8.784400001168251,
+ 8.941699996590614,
+ 10.549700006842613,
+ 8.427299991250038,
+ 8.64869999885559,
+ 8.945000007748604
+ ],
+ "timestamp": "2026-03-12T07:50:35.939Z",
+ "nativeTimings": {
+ "fullPipeline": 9.150399997830391
+ }
+ },
+ "threshold": {
+ "maxDurationIncrease": 15,
+ "maxDuration": null,
+ "minAbsoluteDelta": 5,
+ "maxRenderCount": 1,
+ "minRuns": 10,
+ "maxCV": 0.5,
+ "mode": "gate"
+ },
+ "capturedAt": "2026-03-12T07:50:35.941Z"
+ },
+ "Core Components — Native Render Pipeline ScrollView native mount 1": {
+ "metrics": {
+ "name": "ScrollView native mount",
+ "meanDuration": 31.650409997999667,
+ "medianDuration": 30.47995000332594,
+ "stdDev": 2.871197652832321,
+ "renderCount": 1,
+ "runs": 10,
+ "durations": [
+ 39.441200003027916,
+ 31.205299988389015,
+ 33.09729999303818,
+ 30.64819999039173,
+ 30.543700009584427,
+ 30.41619999706745,
+ 30.345899999141693,
+ 30.254200011491776,
+ 30.3868999928236,
+ 30.165199995040894
+ ],
+ "timestamp": "2026-03-12T07:50:39.028Z",
+ "nativeTimings": {
+ "fullPipeline": 30.47995000332594
+ }
+ },
+ "threshold": {
+ "maxDurationIncrease": 15,
+ "maxDuration": null,
+ "minAbsoluteDelta": 5,
+ "maxRenderCount": 1,
+ "minRuns": 10,
+ "maxCV": 0.6,
+ "mode": "gate"
+ },
+ "capturedAt": "2026-03-12T07:50:39.030Z"
+ },
+ "Core Components — Native Render Pipeline FlatList native mount 1": {
+ "metrics": {
+ "name": "FlatList native mount",
+ "meanDuration": 42.573099999129774,
+ "medianDuration": 42.00689999759197,
+ "stdDev": 1.5275286028989794,
+ "renderCount": 1,
+ "runs": 10,
+ "durations": [
+ 45.16009999811649,
+ 42.16879999637604,
+ 41.925499990582466,
+ 41.383200004696846,
+ 44.674799993634224,
+ 42.08830000460148,
+ 41.30290000140667,
+ 41.59589999914169,
+ 44.304399996995926,
+ 41.12710000574589
+ ],
+ "timestamp": "2026-03-12T07:50:42.007Z",
+ "nativeTimings": {
+ "fullPipeline": 42.00689999759197
+ }
+ },
+ "threshold": {
+ "maxDurationIncrease": 20,
+ "maxDuration": null,
+ "minAbsoluteDelta": 5,
+ "maxRenderCount": 1,
+ "minRuns": 10,
+ "maxCV": 0.6,
+ "mode": "gate"
+ },
+ "capturedAt": "2026-03-12T07:50:42.010Z"
+ }
+}
From c17c4fb706bd0f95341c0ad1313bd42c4b229c7a Mon Sep 17 00:00:00 2001
From: Abhijeet Jha <74712637+iamAbhi-916@users.noreply.github.com>
Date: Thu, 12 Mar 2026 20:58:21 +0530
Subject: [PATCH 02/11] Added all 6 missing components
---
.../NativePerfBenchmarkExample.js | 37 ++
.../core/View.native-perf-test.ts | 46 ++
...iew.native-perf-test.ts.perf-baseline.json | 557 +++++++++++++-----
3 files changed, 482 insertions(+), 158 deletions(-)
diff --git a/packages/@react-native-windows/tester/src/js/examples-win/NativePerfBenchmark/NativePerfBenchmarkExample.js b/packages/@react-native-windows/tester/src/js/examples-win/NativePerfBenchmark/NativePerfBenchmarkExample.js
index dab42e7b432..d0f48ed7cc4 100644
--- a/packages/@react-native-windows/tester/src/js/examples-win/NativePerfBenchmark/NativePerfBenchmarkExample.js
+++ b/packages/@react-native-windows/tester/src/js/examples-win/NativePerfBenchmark/NativePerfBenchmarkExample.js
@@ -14,9 +14,14 @@ const {
Image,
ScrollView,
FlatList,
+ SectionList,
Switch,
ActivityIndicator,
+ Button,
+ Modal,
Pressable,
+ TouchableHighlight,
+ TouchableOpacity,
StyleSheet,
} = require('react-native');
@@ -53,8 +58,40 @@ const COMPONENT_REGISTRY = {
renderItem={({item}) => {item.key}}
/>
),
+ SectionList: () => (
+ {item}}
+ renderSectionHeader={({section}) => {section.title}}
+ />
+ ),
Switch: () => ,
ActivityIndicator: () => ,
+ Button: () =>