diff --git a/benchmark/react/cases/004-various-update/index.tsx b/benchmark/react/cases/004-various-update/index.tsx new file mode 100644 index 0000000000..e828593dc5 --- /dev/null +++ b/benchmark/react/cases/004-various-update/index.tsx @@ -0,0 +1,204 @@ +// Copyright 2025 The Lynx Authors. All rights reserved. +// Licensed under the Apache License Version 2.0 that can be found in the +// LICENSE file in the root directory of this source tree. + +import { root, useEffect, useState } from '@lynx-js/react'; +import { SnapshotInstance } from '@lynx-js/react/internal'; +import type { CSSProperties, MainThread, NodesRef } from '@lynx-js/types'; + +import { hook, isMainThread } from '../../src/hook.js'; + +if (__MAIN_THREAD__) { + hook( + SnapshotInstance.prototype, + 'setAttribute', + function(this: SnapshotInstance, old, key, value) { + if (!this.__elements) { + // skip when there is no underlying FiberElement + return old!.call(this, key, value); + } + + let name = ''; + switch (key) { + case 0: + name = 'Attr'; + break; + case 1: + name = 'Dataset'; + break; + case 2: + name = 'Event'; + break; + case 3: + name = 'MT_Event'; + break; + case 4: + name = 'StyleString'; + break; + case 5: + name = 'StyleObject'; + break; + case 6: + name = 'Class'; + break; + case 7: + name = 'Id'; + break; + case 8: + name = 'Ref'; + break; + case 9: + name = 'TimingFlag'; + break; + case 10: + name = 'MT_Ref'; + break; + case 11: + name = 'ListItemPlatformInfo'; + break; + case 12: + name = 'ListItemPlatformInfoSpread'; + break; + case 13: + name = 'Spread'; + break; + case 'values': + name = 'BatchedValues'; + break; + } + + if (!name) { + // skip what we are not concerned + return old!.call(this, key, value); + } + + Codspeed.startBenchmark(); + const ret = old!.call(this, key, value); + Codspeed.stopBenchmark(); + Codspeed.setExecutedBenchmark( + `${__REPO_FILEPATH__}::${__webpack_chunkname__}-setAttribute__${name}`, + ); + + return ret; + }, + ); +} + +function F() { + const [stopBenchmark, setStopBenchmark] = useState(false); + const [values, setValues] = useState( + [ + 'some-exposure-id' as string, + 'some-dataset' as string, + () => {}, + () => { + 'main thread'; + }, + 'width: 100rpx; height: 100rpx; background-color: #FACE00;' as string, + { + width: '100rpx', + height: '100rpx', + backgroundColor: '#FACE00', + } as CSSProperties, + 'some-css-class' as string, + 'some-id' as string, + (_e: NodesRef) => {}, + 'some_lynx_timing_flag' as string, + (_e: MainThread.Element) => { + 'main thread'; + }, + 'some-item-key' as string, + ] as const, + ); + + useEffect(() => { + setValues([ + 'some-other-exposure-id', + 'some-other-dataset', + () => {}, + () => { + 'main thread'; + }, + 'width: 200rpx; height: 100rpx; background-color: #FACE00;', + { + width: '200rpx', + height: '100rpx', + backgroundColor: '#FACE00', + }, + 'some-other-css-class', + 'some-other-id', + (_e: NodesRef) => {}, + 'some_other_lynx_timing_flag', + (_e: MainThread.Element) => { + 'main thread'; + }, + 'some-other-item-key', + ]); + setStopBenchmark(true); + }, []); + + if (isMainThread) { + return null; + } + + return ( + + + + + + + + + + + + + + + + + + + ); +} + +root.render( + , +); diff --git a/benchmark/react/lynx.config.js b/benchmark/react/lynx.config.js index 80d0974327..451c28de76 100644 --- a/benchmark/react/lynx.config.js +++ b/benchmark/react/lynx.config.js @@ -37,6 +37,9 @@ export default defineConfig({ './src/patchUpdateListCallbacks.ts', './cases/003-hello-list/index.tsx', ], + '004-various-update': [ + './cases/004-various-update/index.tsx', + ], }, }, plugins: [ diff --git a/benchmark/react/package.json b/benchmark/react/package.json index 99ca743eeb..e7a854c345 100644 --- a/benchmark/react/package.json +++ b/benchmark/react/package.json @@ -8,12 +8,14 @@ "bench:001-fib": "benchx_cli run dist/001-fib.lynx.bundle", "bench:002-hello-reactLynx": "benchx_cli run dist/002-hello-reactLynx.lynx.bundle --wait-for-id=stop-benchmark-true", "bench:003-hello-list": "benchx_cli run dist/003-hello-list.lynx.bundle --wait-for-id=stop-benchmark-true", + "bench:004-various-update": "benchx_cli run dist/004-various-update.lynx.bundle --wait-for-id=stop-benchmark-true", "build": "rspeedy build", "dev": "rspeedy dev", "perfetto": "pnpm run --sequential --stream --aggregate-output '/^perfetto:.*/'", "perfetto:001-fib": "benchx_cli -o dist/001-fib.ptrace run dist/001-fib.lynx.bundle", "perfetto:002-hello-reactLynx": "benchx_cli -o dist/002-hello-reactLynx.ptrace run dist/002-hello-reactLynx.lynx.bundle --wait-for-id=stop-benchmark-true", "perfetto:003-hello-list": "benchx_cli -o dist/003-hello-list.ptrace run dist/003-hello-list.lynx.bundle --wait-for-id=stop-benchmark-true", + "perfetto:004-various-update": "benchx_cli -o dist/004-various-update.ptrace run dist/004-various-update.lynx.bundle --wait-for-id=stop-benchmark-true", "test": "echo 'No tests specified'" }, "dependencies": { diff --git a/benchmark/react/src/hook.ts b/benchmark/react/src/hook.ts index 492c02de1c..5254c17d3e 100644 --- a/benchmark/react/src/hook.ts +++ b/benchmark/react/src/hook.ts @@ -16,3 +16,7 @@ export function hook( } export const PREFIX = __REPO_FILEPATH__.split('/').slice(0, -2).join('/'); + +export const isMainThread = + // @ts-expect-error safely check + typeof __CreatePage === 'function';