From 889fc6cc5f112f62f2dd73421ca2b7786264cad6 Mon Sep 17 00:00:00 2001 From: linhandev Date: Sat, 28 Dec 2024 14:33:38 +0800 Subject: [PATCH 001/115] tester: add performance benchmark Signed-off-by: linhandev --- tester/App.tsx | 197 +++++++++--------- tester/benchmarks/index.ts | 1 + tester/benchmarks/stresstest/LICENSE | 19 ++ .../stresstest/MeasureComponent.tsx | 43 ++++ tester/benchmarks/stresstest/StressTest.tsx | 137 ++++++++++++ tester/package.json | 1 + 6 files changed, 302 insertions(+), 96 deletions(-) create mode 100644 tester/benchmarks/stresstest/LICENSE create mode 100644 tester/benchmarks/stresstest/MeasureComponent.tsx create mode 100644 tester/benchmarks/stresstest/StressTest.tsx diff --git a/tester/App.tsx b/tester/App.tsx index de461166..0392abf4 100644 --- a/tester/App.tsx +++ b/tester/App.tsx @@ -15,114 +15,119 @@ import { } from 'react-native'; import * as exampleByName from './examples'; import {NavigationContainer, Page} from './components'; -import {Benchmarker, DeepTree, SierpinskiTriangle} from './benchmarks'; +import { + Benchmarker, + DeepTree, + SierpinskiTriangle, + StressTest, +} from './benchmarks'; import {PortalHost, PortalProvider} from '@gorhom/portal'; import * as testSuiteByName from './tests'; import {Tester} from '@rnoh/testerino'; -import {Environment} from './contexts'; const {TesterExample, ...remainingExampleByName} = exampleByName; function App() { return ( // - - - - - - - - - - - - - {Object.keys(testSuiteByName).map(testSuiteName => { - const TestSuite = - testSuiteByName[ - testSuiteName as keyof typeof testSuiteByName - ]; + + + + + + + + + + + + + + + + {Object.keys(testSuiteByName).map(testSuiteName => { + const TestSuite = + testSuiteByName[testSuiteName as keyof typeof testSuiteByName]; + return ( + + + + + + + + ); + })} + + + refreshKey % 2 === 0 ? ( + + ) : null + } + /> + + + + refreshKey % 2 === 0 ? ( + + ) : null + } + /> + + + ( + + )} + /> + + + ( + + )} + /> + + {Object.entries(remainingExampleByName).map( + ([exampleName, Example]) => { return ( - - - - - - + + ); - })} - - - refreshKey % 2 === 0 ? ( - - ) : null - } - /> - - - - refreshKey % 2 === 0 ? ( - - ) : null - } - /> - - - ( - - )} - /> - - - ( - - )} - /> - - {Object.entries(remainingExampleByName).map( - ([exampleName, Example]) => { - return ( - - - - ); - }, - )} - - - - - - - + }, + )} + + + + + + + // ); } diff --git a/tester/benchmarks/index.ts b/tester/benchmarks/index.ts index 1727fb1e..c6722cac 100644 --- a/tester/benchmarks/index.ts +++ b/tester/benchmarks/index.ts @@ -8,3 +8,4 @@ export * from './DeepTree'; export * from './Benchmarker'; export * from './SierpinskiTriangle'; +export * from './stresstest/StressTest'; diff --git a/tester/benchmarks/stresstest/LICENSE b/tester/benchmarks/stresstest/LICENSE new file mode 100644 index 00000000..d3f7ffb3 --- /dev/null +++ b/tester/benchmarks/stresstest/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2022 Nicola Corti + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/tester/benchmarks/stresstest/MeasureComponent.tsx b/tester/benchmarks/stresstest/MeasureComponent.tsx new file mode 100644 index 00000000..1fdf31a3 --- /dev/null +++ b/tester/benchmarks/stresstest/MeasureComponent.tsx @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2024 Huawei Technologies Co., Ltd. + * + * This source code is licensed under the MIT license found in the + * LICENSE-MIT file in the root directory of this source tree. + */ + +import React from 'react'; +import {DeviceEventEmitter, Systrace, View, Alert} from 'react-native'; + +let drawnTss: number[] = []; // timestamps of when this component's native draw event fired + +DeviceEventEmitter.addListener('benchmarkComponentDrawn', e => { + Systrace.beginEvent('benchmarkComponentDrawn'); + // TODO: performance.now only have ms level accuracy, no decimals, sub ms accuracy solutions? + drawnTss.push(performance.now()); + Systrace.endEvent(); +}); + +export default function MeasureComponent(props: { + children: React.ReactNode; + title: string; + startTime: number; +}): JSX.Element { + // alert test result + setTimeout(() => { + let took = (drawnTss[1] - props.startTime).toFixed(3); + Systrace.beginEvent(`benchmarkAlerting: ${took}`); + drawnTss.sort(); + Alert.alert(props.title, took + ' ms', [{text: 'OK'}]); + drawnTss = []; + Systrace.endEvent(); + }, 1500); + + return ( + + + {props.children} + + ); +} diff --git a/tester/benchmarks/stresstest/StressTest.tsx b/tester/benchmarks/stresstest/StressTest.tsx new file mode 100644 index 00000000..193ba860 --- /dev/null +++ b/tester/benchmarks/stresstest/StressTest.tsx @@ -0,0 +1,137 @@ +/** + * Copyright (c) 2024 Huawei Technologies Co., Ltd. + * + * This source code is licensed under the MIT license found in the + * LICENSE-MIT file in the root directory of this source tree. + */ + +import React from 'react'; +import {useState} from 'react'; +import { + Systrace, + ScrollView, + Pressable, + StyleSheet, + Text, + View, + Image, +} from 'react-native'; +import MeasureComponent from './MeasureComponent'; + +interface Scenario { + count: number; + elementType: string; +} + +export function StressTest() { + const [scenario, setScenario] = useState(null); + const elementTypes: string[] = ['View', 'Text', 'Image']; + const counts: number[] = [1500, 5000]; + const getTestCaseTitle = (count: number, elementType: string) => + `Render ${count} ${elementType}s`; + + return ( + + {scenario === null ? ( + elementTypes.map(elementType => + counts.map(count => ( + + ) + } +} + +export default class App extends React.PureComponent { + constructor(props) { + super(props) + this.state = { count: 0} + console.log("app constructor"); + this.onBindClick = this.clickAction.bind(this) + + } + clickAction = () => { + console.log("clickAction"); + } + increment = () => { + const { count } = this.state + const newCount = count < 5 ? count + 1 : count + console.log('App Button click newCount', newCount) + this.setState({ count: newCount }) + } + + render(): React.ReactNode { + const { count } = this.state + console.log('render') + return ( + <> + {count} +