Date: Fri, 13 Sep 2024 05:53:33 -0500
Subject: [PATCH 12/45] docs: update results in readme
---
README.md | 22 ++++++++++++++++++++--
1 file changed, 20 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 5f167c7..94802bd 100644
--- a/README.md
+++ b/README.md
@@ -18,6 +18,26 @@ Current reactivity benchmarks ([S.js](https://github.com/adamhaile/S/blob/master
We're also working on enabling consistent logging and efficient tracking of GC time across all benchmarks.
+## Frameworks
+
+- [Angular Signals](https://angular.dev/guide/signals/)
+- [Compostate](https://github.com/lxsmnsyc/compostate)
+- [Kairo]()
+- [MobX](https://mobx.js.org) is not included in the average benchmark results because it fails to run some of the deeper, dynamic benchmarks.
+- [mol wire](https://www.npmjs.com/package/mol_wire_lib)
+- [Oby](https://github.com/vobyjs/oby)
+- [Preact Signals](https://github.com/preactjs/signals)
+- [Reactively](https://github.com/milomg/reactively)
+- [S.js](https://github.com/adamhaile/S)
+- [Signia](https://github.com/tldraw/signia)
+- [Solid](https://github.com/solidjs/solid)
+- [TC39 Signals Proposal](https://github.com/tc39/proposal-signals) [polyfill](https://github.com/proposal-signals/signal-polyfill)
+- [uSignal](https://github.com/WebReflection/usignal)
+- [Vue Reactivity](https://vuejs.org/guide/essentials/reactivity-fundamentals.html)
+- [x-reactivity](https://www.npmjs.com/package/@solidjs/reactivity)
+
+## Results
+
Raw results CSV
@@ -37,5 +57,3 @@ That said, there's learning here to improve performance of all the frameworks.

-
-[^mobx]: [MobX](https://mobx.js.org) is not included in the average benchmark results because it fails to run some of the deeper, dynamic benchmarks.
From 1daae2a8c3c420ce6aad0fcdf8c69559cfc0d186 Mon Sep 17 00:00:00 2001
From: Travis Fischer
Date: Fri, 13 Sep 2024 05:54:41 -0500
Subject: [PATCH 13/45] docs: update results in readme
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 94802bd..1862d30 100644
--- a/README.md
+++ b/README.md
@@ -22,8 +22,8 @@ We're also working on enabling consistent logging and efficient tracking of GC t
- [Angular Signals](https://angular.dev/guide/signals/)
- [Compostate](https://github.com/lxsmnsyc/compostate)
-- [Kairo]()
-- [MobX](https://mobx.js.org) is not included in the average benchmark results because it fails to run some of the deeper, dynamic benchmarks.
+- [Kairo](https://github.com/3Shain/kairo)
+- [MobX](https://mobx.js.org) (not included in the average benchmark results because it fails to run some tests)
- [mol wire](https://www.npmjs.com/package/mol_wire_lib)
- [Oby](https://github.com/vobyjs/oby)
- [Preact Signals](https://github.com/preactjs/signals)
From e7b3872a3e4df94b5d04afcdf094c91e2d21507e Mon Sep 17 00:00:00 2001
From: Travis Fischer
Date: Fri, 13 Sep 2024 05:56:43 -0500
Subject: [PATCH 14/45] docs: update results in readme
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 1862d30..4dea72a 100644
--- a/README.md
+++ b/README.md
@@ -40,7 +40,7 @@ We're also working on enabling consistent logging and efficient tracking of GC t
- Raw results CSV
+ Raw results CSV (last updated September 2024 on a M3 Macbook Pro)
From 165cac808d7482b59d326d050b002b0e132f03ff Mon Sep 17 00:00:00 2001
From: Travis Fischer
Date: Fri, 13 Sep 2024 05:57:09 -0500
Subject: [PATCH 15/45] docs: update results in readme
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 4dea72a..d7f013e 100644
--- a/README.md
+++ b/README.md
@@ -40,7 +40,7 @@ We're also working on enabling consistent logging and efficient tracking of GC t
- Raw results CSV (last updated September 2024 on a M3 Macbook Pro)
+ Raw results CSV (last updated September 2024 on a M3 Macbook Pro)
From f898c3a9013f55ef6bc8b32a2b6d2a02b79467d4 Mon Sep 17 00:00:00 2001
From: Travis Fischer
Date: Fri, 13 Sep 2024 05:57:20 -0500
Subject: [PATCH 16/45] docs: update results in readme
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index d7f013e..4603fba 100644
--- a/README.md
+++ b/README.md
@@ -40,7 +40,7 @@ We're also working on enabling consistent logging and efficient tracking of GC t
- Raw results CSV (last updated September 2024 on a M3 Macbook Pro)
+ Raw results CSV (last updated September 2024 on an M3 Macbook Pro)
From c931f71116315a9fe7276b91ee9504993f67e974 Mon Sep 17 00:00:00 2001
From: Travis Fischer
Date: Fri, 13 Sep 2024 06:09:09 -0500
Subject: [PATCH 17/45] chore: remove extra debug logs
---
src/cellxBench.ts | 4 ----
1 file changed, 4 deletions(-)
diff --git a/src/cellxBench.ts b/src/cellxBench.ts
index a2bd379..b6a8631 100644
--- a/src/cellxBench.ts
+++ b/src/cellxBench.ts
@@ -52,13 +52,10 @@ const cellx = (framework: ReactiveFramework, layers: number) => {
] as const;
framework.withBatch(() => {
- // console.log(framework.name, 'batch', 0)
start.prop1.write(4);
- // console.log(framework.name, 'batch', 1)
start.prop2.write(3);
start.prop3.write(2);
start.prop4.write(1);
- // console.log(framework.name, 'batch', 2)
});
const after = [
@@ -68,7 +65,6 @@ const cellx = (framework: ReactiveFramework, layers: number) => {
end.prop4.read(),
] as const;
- // console.log(framework.name, 4)
const endTime = performance.now();
const elapsedTime = endTime - startTime;
From c5ff95a8a9ad367e9336cdd184e44c3f9d82987f Mon Sep 17 00:00:00 2001
From: Travis Fischer
Date: Sat, 14 Sep 2024 19:50:26 -0500
Subject: [PATCH 18/45] feat: add valtio framework
---
README.md | 7 ++++-
package.json | 4 ++-
pnpm-lock.yaml | 50 +++++++++++++++++++++++++++++++++++
src/config.ts | 7 ++++-
src/frameworks/valtio.ts | 57 ++++++++++++++++++++++++++++++++++++++++
5 files changed, 122 insertions(+), 3 deletions(-)
create mode 100644 src/frameworks/valtio.ts
diff --git a/README.md b/README.md
index 4603fba..81b7843 100644
--- a/README.md
+++ b/README.md
@@ -33,6 +33,7 @@ We're also working on enabling consistent logging and efficient tracking of GC t
- [Solid](https://github.com/solidjs/solid)
- [TC39 Signals Proposal](https://github.com/tc39/proposal-signals) [polyfill](https://github.com/proposal-signals/signal-polyfill)
- [uSignal](https://github.com/WebReflection/usignal)
+- [Valtio](https://github.com/pmndrs/valtio)
- [Vue Reactivity](https://vuejs.org/guide/essentials/reactivity-fundamentals.html)
- [x-reactivity](https://www.npmjs.com/package/@solidjs/reactivity)
@@ -40,9 +41,13 @@ We're also working on enabling consistent logging and efficient tracking of GC t
- Raw results CSV (last updated September 2024 on an M3 Macbook Pro)
+ Raw results CSV (lower times are better)
+Note that MobX and Valtio are not included in the average results summary because they fail to run some of the benchmark tests.
+
+These results were last updated _September 2024_ on an M3 Macbook Pro.
+
Old results
diff --git a/package.json b/package.json
index 168c225..58bda74 100644
--- a/package.json
+++ b/package.json
@@ -22,11 +22,13 @@
"mol_wire_lib": "^1.0.1155",
"oby": "15.1.2",
"preact": "^10.23.2",
+ "react": "^18.3.1",
"s-js": "^0.4.9",
"signal-polyfill": "^0.1.0",
"signia": "^0.1.5",
"solid-js": "^1.8.22",
- "usignal": "^0.9.0"
+ "usignal": "^0.9.0",
+ "valtio": "^2.0.0"
},
"devDependencies": {
"@types/node": "^22.5.4",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 4ea53f3..0763e56 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -41,6 +41,9 @@ importers:
preact:
specifier: ^10.23.2
version: 10.23.2
+ react:
+ specifier: ^18.3.1
+ version: 18.3.1
s-js:
specifier: ^0.4.9
version: 0.4.9
@@ -56,6 +59,9 @@ importers:
usignal:
specifier: ^0.9.0
version: 0.9.0
+ valtio:
+ specifier: ^2.0.0
+ version: 2.0.0(react@18.3.1)
devDependencies:
'@types/node':
specifier: ^22.5.4
@@ -823,6 +829,9 @@ packages:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
+ js-tokens@4.0.0:
+ resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+
kairo@0.6.0-rc.0:
resolution: {integrity: sha512-8yWTOujaeU5a6FtFCQnRhljxo8KaxQVDV6xJFxEpkCKd2azlMBmc5ARazaQUb/KJ2PWzsVdiXRbvFmreP6pbFA==}
@@ -836,6 +845,10 @@ packages:
lodash.throttle@4.1.1:
resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==}
+ loose-envify@1.4.0:
+ resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
+ hasBin: true
+
loupe@3.1.1:
resolution: {integrity: sha512-edNu/8D5MKVfGVFRhFf8aAxiTM6Wumfz5XsaatSxlD3w4R1d/WEKUTydCdPGbl9K7QG/Ca3GnDV2sIKIpXRQcw==}
@@ -908,6 +921,13 @@ packages:
engines: {node: '>=14'}
hasBin: true
+ proxy-compare@3.0.0:
+ resolution: {integrity: sha512-y44MCkgtZUCT9tZGuE278fB7PWVf7fRYy0vbRXAts2o5F0EfC4fIQrvQQGBJo1WJbFcVLXzApOscyJuZqHQc1w==}
+
+ react@18.3.1:
+ resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==}
+ engines: {node: '>=0.10.0'}
+
readdirp@3.6.0:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
engines: {node: '>=8.10.0'}
@@ -1022,6 +1042,18 @@ packages:
resolution: {integrity: sha512-CVNliz6KF2yet3HBIkbFJKZmjlt95C8dsNZDnwoS6X98+QJRpsSz9uxo3TziBqdyJQkWwfD3VG9lRzsQNvF24Q==}
engines: {node: '>= 0.6.0'}
+ valtio@2.0.0:
+ resolution: {integrity: sha512-SzUU5UUK/vBRfHWXihwkJE55YNj8zhOkzxPOexcz0xIIT6Oux5VLynCmzyME2bYuEWcktW2NTaaLbpUydEsHiw==}
+ engines: {node: '>=12.20.0'}
+ peerDependencies:
+ '@types/react': '>=18.0.0'
+ react: '>=18.0.0'
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ react:
+ optional: true
+
vite-node@2.1.0:
resolution: {integrity: sha512-+ybYqBVUjYyIscoLzMWodus2enQDZOpGhcU6HdOVD6n8WZdk12w1GFL3mbnxLs7hPtRtqs1Wo5YF6/Tsr6fmhg==}
engines: {node: ^18.0.0 || >=20.0.0}
@@ -1635,6 +1667,8 @@ snapshots:
is-number@7.0.0: {}
+ js-tokens@4.0.0: {}
+
kairo@0.6.0-rc.0: {}
locate-path@3.0.0:
@@ -1646,6 +1680,10 @@ snapshots:
lodash.throttle@4.1.1: {}
+ loose-envify@1.4.0:
+ dependencies:
+ js-tokens: 4.0.0
+
loupe@3.1.1:
dependencies:
get-func-name: 2.0.2
@@ -1698,6 +1736,12 @@ snapshots:
prettier@3.3.3: {}
+ proxy-compare@3.0.0: {}
+
+ react@18.3.1:
+ dependencies:
+ loose-envify: 1.4.0
+
readdirp@3.6.0:
dependencies:
picomatch: 2.3.1
@@ -1802,6 +1846,12 @@ snapshots:
v8-natives@1.2.5: {}
+ valtio@2.0.0(react@18.3.1):
+ dependencies:
+ proxy-compare: 3.0.0
+ optionalDependencies:
+ react: 18.3.1
+
vite-node@2.1.0(@types/node@22.5.4):
dependencies:
cac: 6.7.14
diff --git a/src/config.ts b/src/config.ts
index 275e0df..0f485de 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -15,10 +15,12 @@ import { usignalFramework } from "./frameworks/uSignal";
import { vueReactivityFramework } from "./frameworks/vueReactivity";
import { xReactivityFramework } from "./frameworks/xReactivity";
import { signiaFramework } from "./frameworks/signia";
+import { valtioFramework } from "./frameworks/valtio";
export const frameworkInfo: FrameworkInfo[] = [
{ framework: angularFramework, testPullCounts: true },
{ framework: compostateFramework, testPullCounts: true },
+ // NOTE: MobX currently hangs on some of the dynamic tests, so disable it if you want to run them.
{ framework: mobxFramework },
{ framework: tc39SignalsProposalStage0, testPullCounts: true },
// { framework: kairoFramework, testPullCounts: true },
@@ -28,8 +30,11 @@ export const frameworkInfo: FrameworkInfo[] = [
{ framework: reactivelyFramework, testPullCounts: true },
{ framework: signiaFramework, testPullCounts: true },
{ framework: sFramework },
- { framework: solidFramework }, // solid can't testPullCounts because batch executes all leaf nodes even if unread
+ // Solid can't testPullCounts because batch executes all leaf nodes even if unread
+ { framework: solidFramework },
{ framework: usignalFramework, testPullCounts: true },
+ // NOTE: Valtio currently hangs on some of the dynamic tests, so disable it if you want to run them.
+ { framework: valtioFramework },
{ framework: vueReactivityFramework, testPullCounts: true },
{ framework: xReactivityFramework, testPullCounts: true },
];
diff --git a/src/frameworks/valtio.ts b/src/frameworks/valtio.ts
new file mode 100644
index 0000000..0cc8e63
--- /dev/null
+++ b/src/frameworks/valtio.ts
@@ -0,0 +1,57 @@
+import { ReactiveFramework } from "../util/reactiveFramework";
+import { proxy } from "valtio/vanilla";
+import { watch } from "valtio/utils";
+
+type WatchGet = (proxyObject: T) => T;
+
+// stack of watch getters because Valtio doesn't auto-track dependency reads
+let watchGet: Array = [];
+
+export const valtioFramework: ReactiveFramework = {
+ name: "Valtio",
+ signal: (initialValue) => {
+ const s = proxy({ value: initialValue });
+ return {
+ write: (v) => (s.value = v),
+ read: () => {
+ const get = watchGet.at(-1);
+ if (get) {
+ return get(s).value;
+ } else {
+ return s.value;
+ }
+ },
+ };
+ },
+ computed: (fn) => {
+ const c = proxy({
+ get value() {
+ return fn();
+ },
+ });
+ return {
+ read: () => {
+ const get = watchGet.at(-1);
+ if (get) {
+ return get(c).value;
+ } else {
+ return c.value;
+ }
+ },
+ };
+ },
+ effect: (fn) => {
+ return watch(
+ (get) => {
+ watchGet.push(get);
+ fn();
+ watchGet.pop();
+ },
+ {
+ sync: true,
+ }
+ );
+ },
+ withBatch: (fn) => fn(),
+ withBuild: (fn) => fn(),
+};
From 9197a2f57670be1ba2e45d59262a9e99a712e7d7 Mon Sep 17 00:00:00 2001
From: Travis Fischer
Date: Sun, 15 Sep 2024 02:05:37 -0500
Subject: [PATCH 19/45] feat: remove v8 native code to further simplify repro
cases
---
package.json | 14 ++-
pnpm-lock.yaml | 183 +++++++++++++++++-------------------
src/config.ts | 46 +++++----
src/dynamicBench.ts | 2 -
src/util/benchRepeat.ts | 18 ++--
src/util/garbageTracking.ts | 56 -----------
src/util/perfLogging.ts | 3 -
src/util/perfTests.ts | 1 -
src/v8-natives.d.ts | 39 --------
9 files changed, 123 insertions(+), 239 deletions(-)
delete mode 100644 src/util/garbageTracking.ts
delete mode 100644 src/v8-natives.d.ts
diff --git a/package.json b/package.json
index 58bda74..084d0c5 100644
--- a/package.json
+++ b/package.json
@@ -5,7 +5,7 @@
"main": "index.js",
"scripts": {
"test": "vitest run",
- "bench": "esbuild src/index.ts --external:v8-natives --bundle --format=cjs --platform=node | node --allow-natives-syntax"
+ "bench": "esbuild src/index.ts --bundle --format=cjs --platform=node | node --expose-gc"
},
"keywords": [],
"author": "",
@@ -15,13 +15,13 @@
"@preact/signals": "^1.3.0",
"@reactively/core": "^0.0.8",
"@solidjs/reactivity": "^0.0.9",
- "@vue/reactivity": "^3.5.4",
+ "@vue/reactivity": "^3.5.5",
"compostate": "0.5.1",
"kairo": "0.6.0-rc.0",
"mobx": "^6.13.2",
- "mol_wire_lib": "^1.0.1155",
+ "mol_wire_lib": "^1.0.1158",
"oby": "15.1.2",
- "preact": "^10.23.2",
+ "preact": "^10.24.0",
"react": "^18.3.1",
"s-js": "^0.4.9",
"signal-polyfill": "^0.1.0",
@@ -31,11 +31,9 @@
"valtio": "^2.0.0"
},
"devDependencies": {
- "@types/node": "^22.5.4",
+ "@types/node": "^22.5.5",
"esbuild": "^0.23.1",
"prettier": "^3.3.3",
- "rxjs": "^7.8.1",
- "v8-natives": "^1.2.5",
- "vitest": "^2.1.0"
+ "vitest": "^2.1.1"
}
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 0763e56..f11ad7c 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -13,7 +13,7 @@ importers:
version: 18.2.4(rxjs@7.8.1)(zone.js@0.15.0)
'@preact/signals':
specifier: ^1.3.0
- version: 1.3.0(preact@10.23.2)
+ version: 1.3.0(preact@10.24.0)
'@reactively/core':
specifier: ^0.0.8
version: 0.0.8
@@ -21,8 +21,8 @@ importers:
specifier: ^0.0.9
version: 0.0.9
'@vue/reactivity':
- specifier: ^3.5.4
- version: 3.5.4
+ specifier: ^3.5.5
+ version: 3.5.5
compostate:
specifier: 0.5.1
version: 0.5.1
@@ -33,14 +33,14 @@ importers:
specifier: ^6.13.2
version: 6.13.2
mol_wire_lib:
- specifier: ^1.0.1155
- version: 1.0.1155
+ specifier: ^1.0.1158
+ version: 1.0.1158
oby:
specifier: 15.1.2
version: 15.1.2
preact:
- specifier: ^10.23.2
- version: 10.23.2
+ specifier: ^10.24.0
+ version: 10.24.0
react:
specifier: ^18.3.1
version: 18.3.1
@@ -64,23 +64,17 @@ importers:
version: 2.0.0(react@18.3.1)
devDependencies:
'@types/node':
- specifier: ^22.5.4
- version: 22.5.4
+ specifier: ^22.5.5
+ version: 22.5.5
esbuild:
specifier: ^0.23.1
version: 0.23.1
prettier:
specifier: ^3.3.3
version: 3.3.3
- rxjs:
- specifier: ^7.8.1
- version: 7.8.1
- v8-natives:
- specifier: ^1.2.5
- version: 1.2.5
vitest:
- specifier: ^2.1.0
- version: 2.1.0(@types/node@22.5.4)
+ specifier: ^2.1.1
+ version: 2.1.1(@types/node@22.5.5)
packages/bench:
devDependencies:
@@ -635,16 +629,16 @@ packages:
'@types/node@18.14.0':
resolution: {integrity: sha512-5EWrvLmglK+imbCJY0+INViFWUHg1AHel1sq4ZVSfdcNqGy9Edv3UB9IIzzg+xPaUcAgZYcfVs2fBcwDeZzU0A==}
- '@types/node@22.5.4':
- resolution: {integrity: sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==}
+ '@types/node@22.5.5':
+ resolution: {integrity: sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==}
- '@vitest/expect@2.1.0':
- resolution: {integrity: sha512-N3/xR4fSu0+6sVZETEtPT1orUs2+Y477JOXTcU3xKuu3uBlsgbD7/7Mz2LZ1Jr1XjwilEWlrIgSCj4N1+5ZmsQ==}
+ '@vitest/expect@2.1.1':
+ resolution: {integrity: sha512-YeueunS0HiHiQxk+KEOnq/QMzlUuOzbU1Go+PgAsHvvv3tUkJPm9xWt+6ITNTlzsMXUjmgm5T+U7KBPK2qQV6w==}
- '@vitest/mocker@2.1.0':
- resolution: {integrity: sha512-ZxENovUqhzl+QiOFpagiHUNUuZ1qPd5yYTCYHomGIZOFArzn4mgX2oxZmiAItJWAaXHG6bbpb/DpSPhlk5DgtA==}
+ '@vitest/mocker@2.1.1':
+ resolution: {integrity: sha512-LNN5VwOEdJqCmJ/2XJBywB11DLlkbY0ooDJW3uRX5cZyYCrc4PI/ePX0iQhE3BiEGiQmK4GE7Q/PqCkkaiPnrA==}
peerDependencies:
- '@vitest/spy': 2.1.0
+ '@vitest/spy': 2.1.1
msw: ^2.3.5
vite: ^5.0.0
peerDependenciesMeta:
@@ -653,26 +647,26 @@ packages:
vite:
optional: true
- '@vitest/pretty-format@2.1.0':
- resolution: {integrity: sha512-7sxf2F3DNYatgmzXXcTh6cq+/fxwB47RIQqZJFoSH883wnVAoccSRT6g+dTKemUBo8Q5N4OYYj1EBXLuRKvp3Q==}
+ '@vitest/pretty-format@2.1.1':
+ resolution: {integrity: sha512-SjxPFOtuINDUW8/UkElJYQSFtnWX7tMksSGW0vfjxMneFqxVr8YJ979QpMbDW7g+BIiq88RAGDjf7en6rvLPPQ==}
- '@vitest/runner@2.1.0':
- resolution: {integrity: sha512-D9+ZiB8MbMt7qWDRJc4CRNNUlne/8E1X7dcKhZVAbcOKG58MGGYVDqAq19xlhNfMFZsW0bpVKgztBwks38Ko0w==}
+ '@vitest/runner@2.1.1':
+ resolution: {integrity: sha512-uTPuY6PWOYitIkLPidaY5L3t0JJITdGTSwBtwMjKzo5O6RCOEncz9PUN+0pDidX8kTHYjO0EwUIvhlGpnGpxmA==}
- '@vitest/snapshot@2.1.0':
- resolution: {integrity: sha512-x69CygGMzt9VCO283K2/FYQ+nBrOj66OTKpsPykjCR4Ac3lLV+m85hj9reaIGmjBSsKzVvbxWmjWE3kF5ha3uQ==}
+ '@vitest/snapshot@2.1.1':
+ resolution: {integrity: sha512-BnSku1WFy7r4mm96ha2FzN99AZJgpZOWrAhtQfoxjUU5YMRpq1zmHRq7a5K9/NjqonebO7iVDla+VvZS8BOWMw==}
- '@vitest/spy@2.1.0':
- resolution: {integrity: sha512-IXX5NkbdgTYTog3F14i2LgnBc+20YmkXMx0IWai84mcxySUDRgm0ihbOfR4L0EVRBDFG85GjmQQEZNNKVVpkZw==}
+ '@vitest/spy@2.1.1':
+ resolution: {integrity: sha512-ZM39BnZ9t/xZ/nF4UwRH5il0Sw93QnZXd9NAZGRpIgj0yvVwPpLd702s/Cx955rGaMlyBQkZJ2Ir7qyY48VZ+g==}
- '@vitest/utils@2.1.0':
- resolution: {integrity: sha512-rreyfVe0PuNqJfKYUwfPDfi6rrp0VSu0Wgvp5WBqJonP+4NvXHk48X6oBam1Lj47Hy6jbJtnMj3OcRdrkTP0tA==}
+ '@vitest/utils@2.1.1':
+ resolution: {integrity: sha512-Y6Q9TsI+qJ2CC0ZKj6VBb+T8UPz593N113nnUykqwANqhgf3QkZeHFlusgKLTqrnVHbj/XDKZcDHol+dxVT+rQ==}
- '@vue/reactivity@3.5.4':
- resolution: {integrity: sha512-HKKbEuP7tYSGCq4e4nK6ZW6l5hyG66OUetefBp4budUyjvAYsnQDf+bgFzg2RAgnH0CInyqXwD9y47jwJEHrQw==}
+ '@vue/reactivity@3.5.5':
+ resolution: {integrity: sha512-V4tTWElZQhT73PSK3Wnax9R9m4qvMX+LeKHnfylZc6SLh4Jc5/BPakp6e3zEhKWi5AN8TDzRkGnLkp8OqycYng==}
- '@vue/shared@3.5.4':
- resolution: {integrity: sha512-L2MCDD8l7yC62Te5UUyPVpmexhL9ipVnYRw9CsWfm/BGRL5FwDX4a25bcJ/OJSD3+Hx+k/a8LDKcG2AFdJV3BA==}
+ '@vue/shared@3.5.5':
+ resolution: {integrity: sha512-0KyMXyEgnmFAs6rNUL+6eUHtUCqCaNrVd+AW3MX3LyA0Yry5SA0Km03CDKiOua1x1WWnIr+W9+S0GMFoSDWERQ==}
ansi-regex@4.1.1:
resolution: {integrity: sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==}
@@ -858,8 +852,8 @@ packages:
mobx@6.13.2:
resolution: {integrity: sha512-GIubI2qf+P6lG6rSEG0T2pg3jV9/0+O0ncF09+0umRe75+Cbnh1KNLM1GvbTY9RSc7QuU+LcPNZfxDY8B+3XRg==}
- mol_wire_lib@1.0.1155:
- resolution: {integrity: sha512-q5r5/615KmV5dvM13zak0mYBi5c0Na6RGDRgunZRmezkiIdu4YyVtjPL9syUGpNib8KLzj5acTTWm2BXNC7MHw==}
+ mol_wire_lib@1.0.1158:
+ resolution: {integrity: sha512-ZUsjaBJmxiRH9Lw/+J+sdMBMGHVx/jyZYtpJ/srf4IdsdIMzy8mRXENzjHsLfZw7O/e9RKRXGawRHOx3qT2IQA==}
mol_wire_lib@1.0.488:
resolution: {integrity: sha512-AqGNHtM5HvxdYKXMt85ESXG+Owj/E6HEUM2a0SKoCpx+R4uHrqM3V8HABt13twXzMDDfjO713TRWQb7Qb4EQRA==}
@@ -909,12 +903,12 @@ packages:
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
engines: {node: '>=8.6'}
- postcss@8.4.45:
- resolution: {integrity: sha512-7KTLTdzdZZYscUc65XmjFiB73vBhBfbPztCYdUNvlaso9PrzjzcmjqBPR0lNGkcVlcO4BjiO5rK/qNz+XAen1Q==}
+ postcss@8.4.47:
+ resolution: {integrity: sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==}
engines: {node: ^10 || ^12 || >=14}
- preact@10.23.2:
- resolution: {integrity: sha512-kKYfePf9rzKnxOAKDpsWhg/ysrHPqT+yQ7UW4JjdnqjFIeNUnNcEJvhuA8fDenxAGWzUqtd51DfVg7xp/8T9NA==}
+ preact@10.24.0:
+ resolution: {integrity: sha512-aK8Cf+jkfyuZ0ZZRG9FbYqwmEiGQ4y/PUO4SuTWoyWL244nZZh7bd5h2APd4rSNDYTBNghg1L+5iJN3Skxtbsw==}
prettier@3.3.3:
resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==}
@@ -1018,9 +1012,6 @@ packages:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
- tslib@2.6.2:
- resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
-
tslib@2.7.0:
resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==}
@@ -1054,13 +1045,13 @@ packages:
react:
optional: true
- vite-node@2.1.0:
- resolution: {integrity: sha512-+ybYqBVUjYyIscoLzMWodus2enQDZOpGhcU6HdOVD6n8WZdk12w1GFL3mbnxLs7hPtRtqs1Wo5YF6/Tsr6fmhg==}
+ vite-node@2.1.1:
+ resolution: {integrity: sha512-N/mGckI1suG/5wQI35XeR9rsMsPqKXzq1CdUndzVstBj/HvyxxGctwnK6WX43NGt5L3Z5tcRf83g4TITKJhPrA==}
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
- vite@5.4.4:
- resolution: {integrity: sha512-RHFCkULitycHVTtelJ6jQLd+KSAAzOgEYorV32R2q++M6COBjKJR6BxqClwp5sf0XaBDjVMuJ9wnNfyAJwjMkA==}
+ vite@5.4.5:
+ resolution: {integrity: sha512-pXqR0qtb2bTwLkev4SE3r4abCNioP3GkjvIDLlzziPpXtHgiJIjuKl+1GN6ESOT3wMjG3JTeARopj2SwYaHTOA==}
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
peerDependencies:
@@ -1090,15 +1081,15 @@ packages:
terser:
optional: true
- vitest@2.1.0:
- resolution: {integrity: sha512-XuuEeyNkqbfr0FtAvd9vFbInSSNY1ykCQTYQ0sj9wPy4hx+1gR7gqVNdW0AX2wrrM1wWlN5fnJDjF9xG6mYRSQ==}
+ vitest@2.1.1:
+ resolution: {integrity: sha512-97We7/VC0e9X5zBVkvt7SGQMGrRtn3KtySFQG5fpaMlS+l62eeXRQO633AYhSTC3z7IMebnPPNjGXVGNRFlxBA==}
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
peerDependencies:
'@edge-runtime/vm': '*'
'@types/node': ^18.0.0 || >=20.0.0
- '@vitest/browser': 2.1.0
- '@vitest/ui': 2.1.0
+ '@vitest/browser': 2.1.1
+ '@vitest/ui': 2.1.1
happy-dom: '*'
jsdom: '*'
peerDependenciesMeta:
@@ -1358,10 +1349,10 @@ snapshots:
'@preact/signals-core@1.8.0': {}
- '@preact/signals@1.3.0(preact@10.23.2)':
+ '@preact/signals@1.3.0(preact@10.24.0)':
dependencies:
'@preact/signals-core': 1.8.0
- preact: 10.23.2
+ preact: 10.24.0
'@reactively/core@0.0.8': {}
@@ -1419,55 +1410,55 @@ snapshots:
'@types/node@18.14.0': {}
- '@types/node@22.5.4':
+ '@types/node@22.5.5':
dependencies:
undici-types: 6.19.8
- '@vitest/expect@2.1.0':
+ '@vitest/expect@2.1.1':
dependencies:
- '@vitest/spy': 2.1.0
- '@vitest/utils': 2.1.0
+ '@vitest/spy': 2.1.1
+ '@vitest/utils': 2.1.1
chai: 5.1.1
tinyrainbow: 1.2.0
- '@vitest/mocker@2.1.0(@vitest/spy@2.1.0)(vite@5.4.4(@types/node@22.5.4))':
+ '@vitest/mocker@2.1.1(@vitest/spy@2.1.1)(vite@5.4.5(@types/node@22.5.5))':
dependencies:
- '@vitest/spy': 2.1.0
+ '@vitest/spy': 2.1.1
estree-walker: 3.0.3
magic-string: 0.30.11
optionalDependencies:
- vite: 5.4.4(@types/node@22.5.4)
+ vite: 5.4.5(@types/node@22.5.5)
- '@vitest/pretty-format@2.1.0':
+ '@vitest/pretty-format@2.1.1':
dependencies:
tinyrainbow: 1.2.0
- '@vitest/runner@2.1.0':
+ '@vitest/runner@2.1.1':
dependencies:
- '@vitest/utils': 2.1.0
+ '@vitest/utils': 2.1.1
pathe: 1.1.2
- '@vitest/snapshot@2.1.0':
+ '@vitest/snapshot@2.1.1':
dependencies:
- '@vitest/pretty-format': 2.1.0
+ '@vitest/pretty-format': 2.1.1
magic-string: 0.30.11
pathe: 1.1.2
- '@vitest/spy@2.1.0':
+ '@vitest/spy@2.1.1':
dependencies:
tinyspy: 3.0.2
- '@vitest/utils@2.1.0':
+ '@vitest/utils@2.1.1':
dependencies:
- '@vitest/pretty-format': 2.1.0
+ '@vitest/pretty-format': 2.1.1
loupe: 3.1.1
tinyrainbow: 1.2.0
- '@vue/reactivity@3.5.4':
+ '@vue/reactivity@3.5.5':
dependencies:
- '@vue/shared': 3.5.4
+ '@vue/shared': 3.5.5
- '@vue/shared@3.5.4': {}
+ '@vue/shared@3.5.5': {}
ansi-regex@4.1.1: {}
@@ -1694,7 +1685,7 @@ snapshots:
mobx@6.13.2: {}
- mol_wire_lib@1.0.1155: {}
+ mol_wire_lib@1.0.1158: {}
mol_wire_lib@1.0.488: {}
@@ -1726,13 +1717,13 @@ snapshots:
picomatch@2.3.1: {}
- postcss@8.4.45:
+ postcss@8.4.47:
dependencies:
nanoid: 3.3.7
picocolors: 1.1.0
source-map-js: 1.2.1
- preact@10.23.2: {}
+ preact@10.24.0: {}
prettier@3.3.3: {}
@@ -1774,7 +1765,7 @@ snapshots:
rxjs@7.8.1:
dependencies:
- tslib: 2.6.2
+ tslib: 2.7.0
s-js@0.4.9: {}
@@ -1832,8 +1823,6 @@ snapshots:
dependencies:
is-number: 7.0.0
- tslib@2.6.2: {}
-
tslib@2.7.0: {}
typescript@4.9.5: {}
@@ -1852,12 +1841,12 @@ snapshots:
optionalDependencies:
react: 18.3.1
- vite-node@2.1.0(@types/node@22.5.4):
+ vite-node@2.1.1(@types/node@22.5.5):
dependencies:
cac: 6.7.14
debug: 4.3.7
pathe: 1.1.2
- vite: 5.4.4(@types/node@22.5.4)
+ vite: 5.4.5(@types/node@22.5.5)
transitivePeerDependencies:
- '@types/node'
- less
@@ -1869,24 +1858,24 @@ snapshots:
- supports-color
- terser
- vite@5.4.4(@types/node@22.5.4):
+ vite@5.4.5(@types/node@22.5.5):
dependencies:
esbuild: 0.21.5
- postcss: 8.4.45
+ postcss: 8.4.47
rollup: 4.21.3
optionalDependencies:
- '@types/node': 22.5.4
+ '@types/node': 22.5.5
fsevents: 2.3.3
- vitest@2.1.0(@types/node@22.5.4):
+ vitest@2.1.1(@types/node@22.5.5):
dependencies:
- '@vitest/expect': 2.1.0
- '@vitest/mocker': 2.1.0(@vitest/spy@2.1.0)(vite@5.4.4(@types/node@22.5.4))
- '@vitest/pretty-format': 2.1.0
- '@vitest/runner': 2.1.0
- '@vitest/snapshot': 2.1.0
- '@vitest/spy': 2.1.0
- '@vitest/utils': 2.1.0
+ '@vitest/expect': 2.1.1
+ '@vitest/mocker': 2.1.1(@vitest/spy@2.1.1)(vite@5.4.5(@types/node@22.5.5))
+ '@vitest/pretty-format': 2.1.1
+ '@vitest/runner': 2.1.1
+ '@vitest/snapshot': 2.1.1
+ '@vitest/spy': 2.1.1
+ '@vitest/utils': 2.1.1
chai: 5.1.1
debug: 4.3.7
magic-string: 0.30.11
@@ -1896,11 +1885,11 @@ snapshots:
tinyexec: 0.3.0
tinypool: 1.0.1
tinyrainbow: 1.2.0
- vite: 5.4.4(@types/node@22.5.4)
- vite-node: 2.1.0(@types/node@22.5.4)
+ vite: 5.4.5(@types/node@22.5.5)
+ vite-node: 2.1.1(@types/node@22.5.5)
why-is-node-running: 2.3.0
optionalDependencies:
- '@types/node': 22.5.4
+ '@types/node': 22.5.5
transitivePeerDependencies:
- less
- lightningcss
diff --git a/src/config.ts b/src/config.ts
index 0f485de..bc5e289 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -2,39 +2,38 @@ import { TestConfig, FrameworkInfo } from "./util/frameworkTypes";
import { angularFramework } from "./frameworks/angularSignals";
import { compostateFramework } from "./frameworks/compostate";
-// import { kairoFramework } from "./frameworks/kairo";
import { mobxFramework } from "./frameworks/mobx";
import { tc39SignalsProposalStage0 } from "./frameworks/tc39-proposal-signals-stage-0";
import { molWireFramework } from "./frameworks/molWire";
import { obyFramework } from "./frameworks/oby";
import { preactSignalFramework } from "./frameworks/preactSignals";
import { reactivelyFramework } from "./frameworks/reactively";
-import { sFramework } from "./frameworks/s";
+import { signiaFramework } from "./frameworks/signia";
import { solidFramework } from "./frameworks/solid";
+import { sFramework } from "./frameworks/s";
import { usignalFramework } from "./frameworks/uSignal";
import { vueReactivityFramework } from "./frameworks/vueReactivity";
import { xReactivityFramework } from "./frameworks/xReactivity";
-import { signiaFramework } from "./frameworks/signia";
-import { valtioFramework } from "./frameworks/valtio";
+// import { valtioFramework } from "./frameworks/valtio";
export const frameworkInfo: FrameworkInfo[] = [
{ framework: angularFramework, testPullCounts: true },
{ framework: compostateFramework, testPullCounts: true },
- // NOTE: MobX currently hangs on some of the dynamic tests, so disable it if you want to run them.
- { framework: mobxFramework },
- { framework: tc39SignalsProposalStage0, testPullCounts: true },
// { framework: kairoFramework, testPullCounts: true },
+ // NOTE: MobX currently hangs on some of the dynamic tests, so disable it if you want to run them. (https://github.com/mobxjs/mobx/issues/3926)
+ { framework: mobxFramework },
{ framework: molWireFramework, testPullCounts: true },
{ framework: obyFramework, testPullCounts: true },
{ framework: preactSignalFramework, testPullCounts: true },
{ framework: reactivelyFramework, testPullCounts: true },
{ framework: signiaFramework, testPullCounts: true },
- { framework: sFramework },
// Solid can't testPullCounts because batch executes all leaf nodes even if unread
{ framework: solidFramework },
+ { framework: sFramework },
+ { framework: tc39SignalsProposalStage0, testPullCounts: true },
{ framework: usignalFramework, testPullCounts: true },
- // NOTE: Valtio currently hangs on some of the dynamic tests, so disable it if you want to run them.
- { framework: valtioFramework },
+ // NOTE: Valtio currently hangs on some of the dynamic tests, so disable it if you want to run them. (https://github.com/pmndrs/valtio/discussions/949)
+ // ramework: valtioFramework },
{ framework: vueReactivityFramework, testPullCounts: true },
{ framework: xReactivityFramework, testPullCounts: true },
];
@@ -105,18 +104,17 @@ export const perfTests: TestConfig[] = [
count: 1246500,
},
},
- // NOTE: Several of the frameworks hang on this test, so disabling it for now.
- // {
- // name: 'very dynamic',
- // width: 100,
- // totalLayers: 15,
- // staticFraction: 0.5,
- // nSources: 6,
- // readFraction: 1,
- // iterations: 2000,
- // expected: {
- // sum: 15664996402790400,
- // count: 1078000
- // }
- // }
+ {
+ name: "very dynamic",
+ width: 100,
+ totalLayers: 15,
+ staticFraction: 0.5,
+ nSources: 6,
+ readFraction: 1,
+ iterations: 2000,
+ expected: {
+ sum: 15664996402790400,
+ count: 1078000,
+ },
+ },
];
diff --git a/src/dynamicBench.ts b/src/dynamicBench.ts
index 4b43116..a69cab2 100644
--- a/src/dynamicBench.ts
+++ b/src/dynamicBench.ts
@@ -1,4 +1,3 @@
-import v8 from "v8-natives";
import { makeGraph, runGraph } from "./util/dependencyGraph";
import { logPerfResult, perfRowStrings } from "./util/perfLogging";
import { verifyBenchResult } from "./util/perfTests";
@@ -24,7 +23,6 @@ export async function dynamicBench(
}
// warm up
- v8.optimizeFunctionOnNextCall(runOnce);
runOnce();
const timedResult = await fastestTest(testRepeats, () => {
diff --git a/src/util/benchRepeat.ts b/src/util/benchRepeat.ts
index 88e0d02..4bae639 100644
--- a/src/util/benchRepeat.ts
+++ b/src/util/benchRepeat.ts
@@ -1,5 +1,3 @@
-import v8 from "v8-natives";
-import { GarbageTrack } from "./garbageTracking";
import { TimingResult } from "./perfTests";
import { runTimed } from "./perfUtil";
@@ -9,10 +7,12 @@ export async function fastestTest(
fn: () => T
): Promise> {
const results: TimingResult[] = [];
+
for (let i = 0; i < times; i++) {
const run = await runTracked(fn);
results.push(run);
}
+
const fastest = results.reduce((a, b) =>
a.timing.time < b.timing.time ? a : b
);
@@ -22,11 +22,11 @@ export async function fastestTest(
/** run a function, reporting the wall clock time and garbage collection time. */
async function runTracked(fn: () => T): Promise> {
- v8.collectGarbage();
- const gcTrack = new GarbageTrack();
- const { result: wrappedResult, trackId } = gcTrack.watch(() => runTimed(fn));
- const gcTime = await gcTrack.gcDuration(trackId);
- const { result, time } = wrappedResult;
- gcTrack.destroy();
- return { result, timing: { time, gcTime } };
+ globalThis.gc?.();
+
+ const { result, time } = runTimed(fn);
+
+ globalThis.gc?.();
+
+ return { result, timing: { time } };
}
diff --git a/src/util/garbageTracking.ts b/src/util/garbageTracking.ts
deleted file mode 100644
index 58fda34..0000000
--- a/src/util/garbageTracking.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-import { performance, PerformanceEntry, PerformanceObserver } from "perf_hooks";
-import { promiseDelay } from "./asyncUtil";
-
-/** Track garbage collection via the PerformanceObserver api.
- * Watch user provided benchmark functions, and report
- * execution duration of gc events during the benchmarked function.
- */
-export class GarbageTrack {
- private trackId = 0;
- private observer = new PerformanceObserver((list) =>
- this.perfEntries.push(...list.getEntries())
- );
- private perfEntries: PerformanceEntry[] = [];
- private periods: WatchPeriod[] = [];
-
- /** look for gc events during the time this function is executing */
- watch(fn: () => T): { result: T; trackId: number } {
- this.trackId++;
- const start = performance.now();
- const result = fn();
- const end = performance.now();
- this.periods.push({ trackId: this.trackId, start, end });
-
- return { result, trackId: this.trackId };
- }
-
- /** report total duration of gc events during one watched function */
- async gcDuration(trackId: number): Promise {
- await promiseDelay(10); // wait one eventloop cycle until the perfEntries are populated
-
- const period = this.periods.find((period) => period.trackId === trackId);
- if (!period) {
- return Promise.reject("no period found");
- }
-
- const entries = this.perfEntries.filter(
- (e) => e.startTime >= period.start && e.startTime < period.end
- );
- const totalTime = entries.reduce((t, e) => e.duration + t, 0);
- return totalTime;
- }
-
- destroy() {
- this.observer.disconnect();
- }
-
- constructor() {
- this.observer.observe({ entryTypes: ["gc"] });
- }
-}
-
-interface WatchPeriod {
- trackId: number;
- start: number;
- end: number;
-}
diff --git a/src/util/perfLogging.ts b/src/util/perfLogging.ts
index df8db2d..6b1a41c 100644
--- a/src/util/perfLogging.ts
+++ b/src/util/perfLogging.ts
@@ -10,14 +10,12 @@ export interface PerfRowStrings {
framework: string;
test: string;
time: string;
- gcTime?: string;
}
const columnWidth = {
framework: 22,
test: 60,
time: 8,
- gcTime: 6,
};
export function perfReportHeaders(): PerfRowStrings {
@@ -38,7 +36,6 @@ export function perfRowStrings(
framework: frameworkName,
test: `${makeTitle(config)} (${config.name || ""})`,
time: timing.time.toFixed(2),
- gcTime: (timing.gcTime || 0).toFixed(2),
};
}
diff --git a/src/util/perfTests.ts b/src/util/perfTests.ts
index df4d55a..0a0a6c7 100644
--- a/src/util/perfTests.ts
+++ b/src/util/perfTests.ts
@@ -12,7 +12,6 @@ export interface TimingResult {
export interface TestTiming {
time: number;
- gcTime?: number;
}
export function verifyBenchResult(
diff --git a/src/v8-natives.d.ts b/src/v8-natives.d.ts
deleted file mode 100644
index 96a7af2..0000000
--- a/src/v8-natives.d.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-declare module "v8-natives" {
- export interface V8 {
- isNative: () => boolean;
- collectGarbage: () => void;
- debugPrint: (data: any) => void;
- optimizeFunctionOnNextCall: (fn: Function) => void;
- getOptimizationStatus: (fn: Function) => number;
- deoptimizeFunction: (fn: Function) => void;
- deoptimizeNow: (fn: Function) => void;
- ClearFunctionFeedback: (fn: Function) => void;
- debugTrace: (fn: Function) => void;
- getHeapUsage: (fn: Function) => void;
- hasFastProperties: (fn: Function) => void;
- hasFastPackedElements: (fn: Function) => void;
- HasSmiElements: (fn: Function) => void;
- hasDoubleElements: (fn: Function) => void;
- hasDictionaryElements: (fn: Function) => void;
- HasHoleyElements: (fn: Function) => void;
- hasSmiOrObjectElements: (fn: Function) => void;
- hasSloppyArgumentsElements: (fn: Function) => void;
- haveSameMap: (fn: Function) => void;
- getFunctionName: (fn: Function) => void;
- functionGetName: (fn: Function) => void;
- isSmi: (fn: Function) => void;
- isValidSmi: (fn: Function) => void;
- neverOptimizeFunction: (fn: Function) => void;
- traceEnter: (fn: Function) => void;
- traceExit: (fn: Function) => void;
- CompileOptimized: (fn: Function) => void;
- helpers: {
- printStatus: (fn: Function) => void;
- testOptimization: (fn: Function) => void;
- benchmark: (fn: Function) => void;
- };
- }
-
- const v8: V8;
- export default v8;
-}
From 0f0855cce17bde54869ede7f9bb699a25a3b73e8 Mon Sep 17 00:00:00 2001
From: Travis Fischer
Date: Sun, 15 Sep 2024 22:49:52 -0500
Subject: [PATCH 20/45] feat: replace v8 intrinsics with node --expose-gc;
replace pseudorandom with random package
---
README.md | 9 +++---
package.json | 1 +
pnpm-lock.yaml | 9 ++++++
src/cellxBench.ts | 2 ++
src/config.ts | 24 ++++++++--------
src/dynamicBench.ts | 11 ++++---
src/frameworks.test.ts | 13 +++++----
src/frameworks/mobx.ts | 6 ++--
src/frameworks/valtio.ts | 2 ++
src/index.ts | 10 ++++---
src/kairoBench.ts | 4 +--
src/molBench.ts | 3 --
src/sBench.ts | 6 ++--
src/util/dependencyGraph.ts | 57 +++++++++++++++++++++++--------------
src/util/pseudoRandom.ts | 47 ------------------------------
15 files changed, 93 insertions(+), 111 deletions(-)
delete mode 100644 src/util/pseudoRandom.ts
diff --git a/README.md b/README.md
index 81b7843..411a638 100644
--- a/README.md
+++ b/README.md
@@ -6,13 +6,12 @@ $ pnpm bench
## Features
-- Configurable dependency graph: graph shape, density, read rate are all adjustable.
+- Configurable dependency graph: graph shape, density, read rate are all adjustable
- Easily add new benchmarks and frameworks
- Supports dynamic reactive nodes
-- Framework agnostic. Simple API to test new reactive frameworks.
-- Uses v8 intrinsics to warmup and cleanup
-- Tracks garbage collection overhead per test
-- Outputs a csv file for easy integration with other tools.
+- Framework agnostic. Simple API to test new reactive frameworks
+- Forces garbage collection between each test
+- Outputs a csv file for easy integration with other tools
Current reactivity benchmarks ([S.js](https://github.com/adamhaile/S/blob/master/bench/bench.js), [CellX](https://github.com/Riim/cellx/blob/master/perf/perf.html)) are focused on creation time, and update time for a static graph. Additionally, existing benchmarks aren't very configurable, and don't test for dynamic dependencies. We've created a new benchmark that allows library authors to compare their frameworks against each other, and against the existing benchmarks, as well as against a new configurable benchmark with dynamically changing sources.
diff --git a/package.json b/package.json
index 084d0c5..4d92a58 100644
--- a/package.json
+++ b/package.json
@@ -22,6 +22,7 @@
"mol_wire_lib": "^1.0.1158",
"oby": "15.1.2",
"preact": "^10.24.0",
+ "random": "^5.1.0",
"react": "^18.3.1",
"s-js": "^0.4.9",
"signal-polyfill": "^0.1.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index f11ad7c..18639ce 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -41,6 +41,9 @@ importers:
preact:
specifier: ^10.24.0
version: 10.24.0
+ random:
+ specifier: ^5.1.0
+ version: 5.1.0
react:
specifier: ^18.3.1
version: 18.3.1
@@ -918,6 +921,10 @@ packages:
proxy-compare@3.0.0:
resolution: {integrity: sha512-y44MCkgtZUCT9tZGuE278fB7PWVf7fRYy0vbRXAts2o5F0EfC4fIQrvQQGBJo1WJbFcVLXzApOscyJuZqHQc1w==}
+ random@5.1.0:
+ resolution: {integrity: sha512-0NGG4HMW9sTstLbignEDasSQJlCGkNQZICIWStZ+h4SzSJfZXpecGKV7qL0AOKcIT8XX9pJ49uZnvI0n/Y+vWA==}
+ engines: {node: '>=18'}
+
react@18.3.1:
resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==}
engines: {node: '>=0.10.0'}
@@ -1729,6 +1736,8 @@ snapshots:
proxy-compare@3.0.0: {}
+ random@5.1.0: {}
+
react@18.3.1:
dependencies:
loose-envify: 1.4.0
diff --git a/src/cellxBench.ts b/src/cellxBench.ts
index b6a8631..0c876bc 100644
--- a/src/cellxBench.ts
+++ b/src/cellxBench.ts
@@ -114,6 +114,8 @@ export const cellxbench = (framework: ReactiveFramework) => {
total += elapsed;
}
+
+ globalThis.gc?.();
logPerfResult({
framework: framework.name,
test: `cellx${layers}`,
diff --git a/src/config.ts b/src/config.ts
index bc5e289..254f544 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -17,6 +17,10 @@ import { xReactivityFramework } from "./frameworks/xReactivity";
// import { valtioFramework } from "./frameworks/valtio";
export const frameworkInfo: FrameworkInfo[] = [
+ { framework: preactSignalFramework, testPullCounts: true },
+ { framework: tc39SignalsProposalStage0, testPullCounts: true },
+ { framework: reactivelyFramework, testPullCounts: true },
+ { framework: sFramework },
{ framework: angularFramework, testPullCounts: true },
{ framework: compostateFramework, testPullCounts: true },
// { framework: kairoFramework, testPullCounts: true },
@@ -24,13 +28,9 @@ export const frameworkInfo: FrameworkInfo[] = [
{ framework: mobxFramework },
{ framework: molWireFramework, testPullCounts: true },
{ framework: obyFramework, testPullCounts: true },
- { framework: preactSignalFramework, testPullCounts: true },
- { framework: reactivelyFramework, testPullCounts: true },
{ framework: signiaFramework, testPullCounts: true },
// Solid can't testPullCounts because batch executes all leaf nodes even if unread
{ framework: solidFramework },
- { framework: sFramework },
- { framework: tc39SignalsProposalStage0, testPullCounts: true },
{ framework: usignalFramework, testPullCounts: true },
// NOTE: Valtio currently hangs on some of the dynamic tests, so disable it if you want to run them. (https://github.com/pmndrs/valtio/discussions/949)
// ramework: valtioFramework },
@@ -48,8 +48,8 @@ export const perfTests: TestConfig[] = [
readFraction: 0.2,
iterations: 600000,
expected: {
- sum: 19199968,
- count: 3480000,
+ sum: 19199832,
+ count: 2640004,
},
},
{
@@ -61,8 +61,8 @@ export const perfTests: TestConfig[] = [
readFraction: 0.2,
iterations: 15000,
expected: {
- sum: 302310782860,
- count: 1155000,
+ sum: 302310477864,
+ count: 1125003,
},
},
{
@@ -75,7 +75,7 @@ export const perfTests: TestConfig[] = [
iterations: 7000,
expected: {
sum: 29355933696000,
- count: 1463000,
+ count: 1473791,
},
},
{
@@ -88,7 +88,7 @@ export const perfTests: TestConfig[] = [
iterations: 3000,
expected: {
sum: 1171484375000,
- count: 732000,
+ count: 735756,
},
},
{
@@ -101,7 +101,7 @@ export const perfTests: TestConfig[] = [
iterations: 500,
expected: {
sum: 3.0239642676898464e241,
- count: 1246500,
+ count: 1246502,
},
},
{
@@ -114,7 +114,7 @@ export const perfTests: TestConfig[] = [
iterations: 2000,
expected: {
sum: 15664996402790400,
- count: 1078000,
+ count: 1078671,
},
},
];
diff --git a/src/dynamicBench.ts b/src/dynamicBench.ts
index a69cab2..7d28d2c 100644
--- a/src/dynamicBench.ts
+++ b/src/dynamicBench.ts
@@ -1,4 +1,4 @@
-import { makeGraph, runGraph } from "./util/dependencyGraph";
+import { Counter, makeGraph, runGraph } from "./util/dependencyGraph";
import { logPerfResult, perfRowStrings } from "./util/perfLogging";
import { verifyBenchResult } from "./util/perfTests";
import { FrameworkInfo } from "./util/frameworkTypes";
@@ -10,20 +10,23 @@ import { fastestTest } from "./util/benchRepeat";
*/
export async function dynamicBench(
frameworkTest: FrameworkInfo,
- testRepeats = 5
+ testRepeats = 1
): Promise {
const { framework } = frameworkTest;
for (const config of perfTests) {
const { iterations, readFraction } = config;
- const { graph, counter } = makeGraph(framework, config);
+ let counter = new Counter();
function runOnce(): number {
+ // Create a new graph from scratch for each run to ensure they're independent
+ // from each other.
+ const graph = makeGraph(framework, config, counter);
return runGraph(graph, iterations, readFraction, framework);
}
// warm up
- runOnce();
+ // runOnce();
const timedResult = await fastestTest(testRepeats, () => {
counter.count = 0;
diff --git a/src/frameworks.test.ts b/src/frameworks.test.ts
index 8903cc8..cfa6840 100644
--- a/src/frameworks.test.ts
+++ b/src/frameworks.test.ts
@@ -1,4 +1,4 @@
-import { makeGraph, runGraph } from "./util/dependencyGraph";
+import { Counter, makeGraph, runGraph } from "./util/dependencyGraph";
import { expect, test, vi } from "vitest";
import { FrameworkInfo, TestConfig } from "./util/frameworkTypes";
import { frameworkInfo } from "./config";
@@ -46,7 +46,8 @@ function frameworkTests({ framework, testPullCounts }: FrameworkInfo) {
test(`${name} | static graph`, () => {
const config = makeConfig();
- const { graph, counter } = makeGraph(framework, config);
+ const counter = new Counter();
+ const graph = makeGraph(framework, config, counter);
const sum = runGraph(graph, 2, 1, framework);
expect(sum).toEqual(16);
if (testPullCounts) {
@@ -60,10 +61,11 @@ function frameworkTests({ framework, testPullCounts }: FrameworkInfo) {
const config = makeConfig();
config.readFraction = 2 / 3;
config.iterations = 10;
- const { counter, graph } = makeGraph(framework, config);
+ const counter = new Counter();
+ const graph = makeGraph(framework, config, counter);
const sum = runGraph(graph, 10, 2 / 3, framework);
- expect(sum).toEqual(72);
+ expect(sum).toEqual(73);
if (testPullCounts) {
expect(counter.count).toEqual(41);
} else {
@@ -76,7 +78,8 @@ function frameworkTests({ framework, testPullCounts }: FrameworkInfo) {
config.staticFraction = 0.5;
config.width = 4;
config.totalLayers = 2;
- const { graph, counter } = makeGraph(framework, config);
+ const counter = new Counter();
+ const graph = makeGraph(framework, config, counter);
const sum = runGraph(graph, 10, 1, framework);
expect(sum).toEqual(72);
diff --git a/src/frameworks/mobx.ts b/src/frameworks/mobx.ts
index d757e1b..6d47bd0 100644
--- a/src/frameworks/mobx.ts
+++ b/src/frameworks/mobx.ts
@@ -1,4 +1,4 @@
-import { computed, observable, autorun, transaction, action } from "mobx";
+import { computed, observable, autorun, runInAction } from "mobx";
import { ReactiveFramework } from "../util/reactiveFramework";
export const mobxFramework: ReactiveFramework = {
@@ -7,7 +7,7 @@ export const mobxFramework: ReactiveFramework = {
const s = observable.box(initial, { deep: false });
return {
read: () => s.get(),
- write: action((x) => s.set(x)),
+ write: (x) => s.set(x),
};
},
computed: (fn) => {
@@ -17,6 +17,6 @@ export const mobxFramework: ReactiveFramework = {
};
},
effect: (fn) => autorun(fn),
- withBatch: (fn) => transaction(fn),
+ withBatch: (fn) => runInAction(fn),
withBuild: (fn) => fn(),
};
diff --git a/src/frameworks/valtio.ts b/src/frameworks/valtio.ts
index 0cc8e63..c763bbb 100644
--- a/src/frameworks/valtio.ts
+++ b/src/frameworks/valtio.ts
@@ -2,6 +2,8 @@ import { ReactiveFramework } from "../util/reactiveFramework";
import { proxy } from "valtio/vanilla";
import { watch } from "valtio/utils";
+// The Valtio adapter is currently broken and not used: https://github.com/pmndrs/valtio/discussions/949
+
type WatchGet = (proxyObject: T) => T;
// stack of watch getters because Valtio doesn't auto-track dependency reads
diff --git a/src/index.ts b/src/index.ts
index 248b812..de2596c 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -22,10 +22,12 @@ async function main() {
sbench(framework);
}
- // NOTE: Several of the frameworks hang on this benchmark, so disabling it for now.
- // for (const { framework } of frameworkInfo) {
- // cellxbench(framework);
- // }
+ for (const { framework } of frameworkInfo) {
+ // https://github.com/vuejs/core/issues/11928
+ if (framework.name !== "Vue") {
+ cellxbench(framework);
+ }
+ }
for (const frameworkTest of frameworkInfo) {
await dynamicBench(frameworkTest);
diff --git a/src/kairoBench.ts b/src/kairoBench.ts
index cae27f8..3730a45 100644
--- a/src/kairoBench.ts
+++ b/src/kairoBench.ts
@@ -1,4 +1,3 @@
-import v8 from "v8-natives";
import { avoidablePropagation } from "./kairo/avoidable";
import { broadPropagation } from "./kairo/broad";
import { deepPropagation } from "./kairo/deep";
@@ -29,7 +28,7 @@ export async function kairoBench(framework: ReactiveFramework) {
return iter;
});
- v8.optimizeFunctionOnNextCall(iter);
+ // warm up
iter();
const { timing } = await fastestTest(10, () => {
@@ -42,7 +41,6 @@ export async function kairoBench(framework: ReactiveFramework) {
framework: framework.name,
test: c.name,
time: timing.time.toFixed(2),
- gcTime: timing.gcTime?.toFixed(2),
});
}
}
diff --git a/src/molBench.ts b/src/molBench.ts
index e9d7c5c..3dccb8b 100644
--- a/src/molBench.ts
+++ b/src/molBench.ts
@@ -1,4 +1,3 @@
-import v8 from "v8-natives";
import { fastestTest } from "./util/benchRepeat";
import { logPerfResult } from "./util/perfLogging";
import { ReactiveFramework } from "./util/reactiveFramework";
@@ -47,7 +46,6 @@ export async function molBench(framework: ReactiveFramework) {
};
});
- v8.optimizeFunctionOnNextCall(iter);
iter(1);
const { timing } = await fastestTest(10, () => {
@@ -60,6 +58,5 @@ export async function molBench(framework: ReactiveFramework) {
framework: framework.name,
test: "molBench",
time: timing.time.toFixed(2),
- gcTime: timing.gcTime?.toFixed(2),
});
}
diff --git a/src/sBench.ts b/src/sBench.ts
index 5ca7fc3..25a511c 100644
--- a/src/sBench.ts
+++ b/src/sBench.ts
@@ -1,5 +1,4 @@
// Inspired by https://github.com/solidjs/solid/blob/main/packages/solid/bench/bench.cjs
-import v8 from "v8-natives";
import { logPerfResult } from "./util/perfLogging";
import { Computed, Signal, ReactiveFramework } from "./util/reactiveFramework";
@@ -55,7 +54,6 @@ export function sbench(framework: ReactiveFramework) {
sources = createDataSignals(scount, []);
fn(n / 100, sources);
sources = createDataSignals(scount, []);
- v8.optimizeFunctionOnNextCall(fn);
fn(n / 100, sources);
sources = createDataSignals(scount, []);
for (let i = 0; i < scount; i++) {
@@ -65,7 +63,7 @@ export function sbench(framework: ReactiveFramework) {
}
// start GC clean
- v8.collectGarbage();
+ globalThis.gc?.();
start = performance.now();
@@ -73,7 +71,7 @@ export function sbench(framework: ReactiveFramework) {
// end GC clean
sources = null;
- v8.collectGarbage();
+ globalThis.gc?.();
end = performance.now();
});
diff --git a/src/util/dependencyGraph.ts b/src/util/dependencyGraph.ts
index a704642..403b2d8 100644
--- a/src/util/dependencyGraph.ts
+++ b/src/util/dependencyGraph.ts
@@ -1,17 +1,12 @@
import { TestConfig } from "./frameworkTypes";
-import { pseudoRandom } from "./pseudoRandom";
import { Computed, ReactiveFramework, Signal } from "./reactiveFramework";
+import { Random } from "random";
export interface Graph {
sources: Signal[];
layers: Computed[][];
}
-export interface GraphAndCounter {
- graph: Graph;
- counter: Counter;
-}
-
/**
* Make a rectangular dependency graph, with an equal number of source elements
* and computation elements at every layer.
@@ -23,13 +18,13 @@ export interface GraphAndCounter {
*/
export function makeGraph(
framework: ReactiveFramework,
- config: TestConfig
-): GraphAndCounter {
+ config: TestConfig,
+ counter: Counter
+): Graph {
const { width, totalLayers, staticFraction, nSources } = config;
return framework.withBuild(() => {
const sources = new Array(width).fill(0).map((_, i) => framework.signal(i));
- const counter = new Counter();
const rows = makeDependentRows(
sources,
totalLayers - 1,
@@ -39,7 +34,7 @@ export function makeGraph(
framework
);
const graph = { sources, layers: rows };
- return { graph, counter };
+ return graph;
});
}
@@ -54,30 +49,50 @@ export function runGraph(
readFraction: number,
framework: ReactiveFramework
): number {
- const rand = pseudoRandom();
+ const rand = new Random("seed");
const { sources, layers } = graph;
const leaves = layers[layers.length - 1];
const skipCount = Math.round(leaves.length * (1 - readFraction));
const readLeaves = removeElems(leaves, skipCount, rand);
+ // const start = Date.now();
for (let i = 0; i < iterations; i++) {
+ // Useful for debugging edge cases for some frameworks that experience
+ // dramatic slow downs for certain test configurations. These are generally
+ // due to `computed` effects not being cached efficiently, and as the number
+ // of layers increases, the uncached `computed` effects are re-evaluated in
+ // an `O(n^2)` manner where `n` is the number of layers.
+ // if (i % 100 === 0) {
+ // console.log("iteration:", i, "delta:", Date.now() - start);
+ // }
+
framework.withBatch(() => {
const sourceDex = i % sources.length;
sources[sourceDex].write(i + sourceDex);
});
- for (const leaf of readLeaves) {
- leaf.read();
- }
+
+ // this batch is necessary for `mobx` (https://github.com/mobxjs/mobx/issues/3926)
+ framework.withBatch(() => {
+ for (const leaf of readLeaves) {
+ leaf.read();
+ }
+ });
}
- const sum = readLeaves.reduce((total, leaf) => leaf.read() + total, 0);
+ let sum = 0;
+
+ // this batch is necessary for `mobx` (https://github.com/mobxjs/mobx/issues/3926)
+ framework.withBatch(() => {
+ sum = readLeaves.reduce((total, leaf) => leaf.read() + total, 0);
+ });
+
return sum;
}
-function removeElems(src: T[], rmCount: number, rand: () => number): T[] {
+function removeElems(src: T[], rmCount: number, rand: Random): T[] {
const copy = src.slice();
for (let i = 0; i < rmCount; i++) {
- const rmDex = Math.floor(rand() * copy.length);
+ const rmDex = rand.int(0, copy.length - 1);
copy.splice(rmDex, 1);
}
return copy;
@@ -96,7 +111,7 @@ function makeDependentRows(
framework: ReactiveFramework
): Computed[][] {
let prevRow = sources;
- const random = pseudoRandom();
+ const rand = new Random("seed");
const rows = [];
for (let l = 0; l < numRows; l++) {
const row = makeRow(
@@ -106,7 +121,7 @@ function makeDependentRows(
nSources,
framework,
l,
- random
+ rand
);
rows.push(row);
prevRow = row;
@@ -121,7 +136,7 @@ function makeRow(
nSources: number,
framework: ReactiveFramework,
_layer: number,
- random: () => number
+ random: Random
): Computed[] {
return sources.map((_, myDex) => {
const mySources: Computed[] = [];
@@ -129,7 +144,7 @@ function makeRow(
mySources.push(sources[(myDex + sourceDex) % sources.length]);
}
- const staticNode = random() < staticFraction;
+ const staticNode = random.float() < staticFraction;
if (staticNode) {
// static node, always reference sources
return framework.computed(() => {
diff --git a/src/util/pseudoRandom.ts b/src/util/pseudoRandom.ts
deleted file mode 100644
index 7d6a633..0000000
--- a/src/util/pseudoRandom.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-export function pseudoRandom(seed = "seed"): () => number {
- const hash = xmur3a(seed);
- const rng = sfc32(hash(), hash(), hash(), hash());
- return rng;
-}
-
-/* these are adapted from https://github.com/bryc/code/blob/master/jshash/PRNGs.md
- * (License: Public domain) */
-
-/** random number generator originally in PractRand */
-function sfc32(a: number, b: number, c: number, d: number): () => number {
- return function () {
- a >>>= 0;
- b >>>= 0;
- c >>>= 0;
- d >>>= 0;
- let t = (a + b) | 0;
- a = b ^ (b >>> 9);
- b = (c + (c << 3)) | 0;
- c = (c << 21) | (c >>> 11);
- d = (d + 1) | 0;
- t = (t + d) | 0;
- c = (c + t) | 0;
- return (t >>> 0) / 4294967296;
- };
-}
-
-/** MurmurHash3 */
-export function xmur3a(str: string): () => number {
- let h = 2166136261 >>> 0;
- for (let k: number, i = 0; i < str.length; i++) {
- k = Math.imul(str.charCodeAt(i), 3432918353);
- k = (k << 15) | (k >>> 17);
- h ^= Math.imul(k, 461845907);
- h = (h << 13) | (h >>> 19);
- h = (Math.imul(h, 5) + 3864292196) | 0;
- }
- h ^= str.length;
- return function () {
- h ^= h >>> 16;
- h = Math.imul(h, 2246822507);
- h ^= h >>> 13;
- h = Math.imul(h, 3266489909);
- h ^= h >>> 16;
- return h >>> 0;
- };
-}
From d8215fb5628b339a456b1bf828bd89ce6d3e8b45 Mon Sep 17 00:00:00 2001
From: Travis Fischer
Date: Sun, 15 Sep 2024 22:50:59 -0500
Subject: [PATCH 21/45] =?UTF-8?q?=F0=9F=92=8C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/frameworks/kairo.ts | 2 ++
src/frameworks/valtio.ts | 2 +-
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/frameworks/kairo.ts b/src/frameworks/kairo.ts
index d78ef6c..613a8df 100644
--- a/src/frameworks/kairo.ts
+++ b/src/frameworks/kairo.ts
@@ -2,6 +2,8 @@ import { ReactiveFramework } from "../util/reactiveFramework";
import { batch, computed, effect, mutValue } from "kairo";
import { collectScope } from "kairo";
+// NOTE: The kairo adapter is currently not working and used.
+
export const kairoFramework: ReactiveFramework = {
name: "kairo",
signal: (initialValue) => {
diff --git a/src/frameworks/valtio.ts b/src/frameworks/valtio.ts
index c763bbb..32e4c87 100644
--- a/src/frameworks/valtio.ts
+++ b/src/frameworks/valtio.ts
@@ -2,7 +2,7 @@ import { ReactiveFramework } from "../util/reactiveFramework";
import { proxy } from "valtio/vanilla";
import { watch } from "valtio/utils";
-// The Valtio adapter is currently broken and not used: https://github.com/pmndrs/valtio/discussions/949
+// The Valtio adapter is currently not working and unused: https://github.com/pmndrs/valtio/discussions/949
type WatchGet = (proxyObject: T) => T;
From abcdae32c2e8e082194ea7138f67d8b9d9cd8e89 Mon Sep 17 00:00:00 2001
From: Travis Fischer
Date: Sun, 15 Sep 2024 22:52:27 -0500
Subject: [PATCH 22/45] =?UTF-8?q?=F0=9F=8F=8E?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/molBench.ts | 9 ++++----
src/sBench.ts | 60 ++++++++++++++++++++++++-------------------------
2 files changed, 35 insertions(+), 34 deletions(-)
diff --git a/src/molBench.ts b/src/molBench.ts
index 3dccb8b..dd209a6 100644
--- a/src/molBench.ts
+++ b/src/molBench.ts
@@ -7,7 +7,7 @@ function fib(n: number): number {
return fib(n - 1) + fib(n - 2);
}
-function hard(n: number, log: string) {
+function hard(n: number, _log: string) {
return n + fib(16);
}
@@ -29,9 +29,10 @@ export async function molBench(framework: ReactiveFramework) {
const G = framework.computed(
() => C.read() + (C.read() || E.read() % 2) + D.read()[4].x + F.read()
);
- const H = framework.effect(() => res.push(hard(G.read(), "H")));
- const I = framework.effect(() => res.push(G.read()));
- const J = framework.effect(() => res.push(hard(F.read(), "J")));
+
+ framework.effect(() => res.push(hard(G.read(), "H")));
+ framework.effect(() => res.push(G.read()));
+ framework.effect(() => res.push(hard(F.read(), "J")));
return (i: number) => {
res.length = 0;
diff --git a/src/sBench.ts b/src/sBench.ts
index 25a511c..99af087 100644
--- a/src/sBench.ts
+++ b/src/sBench.ts
@@ -85,7 +85,7 @@ export function sbench(framework: ReactiveFramework) {
return sources;
}
- function createComputations0to1(n: number, sources: Computed[]) {
+ function createComputations0to1(n: number, _sources: Computed[]) {
for (let i = 0; i < n; i++) {
createComputation0(i);
}
@@ -156,20 +156,20 @@ export function sbench(framework: ReactiveFramework) {
}
}
- function createComputations8to1(n: number, sources: Computed[]) {
- for (let i = 0; i < n; i++) {
- createComputation8(
- sources[i * 8].read,
- sources[i * 8 + 1].read,
- sources[i * 8 + 2].read,
- sources[i * 8 + 3].read,
- sources[i * 8 + 4].read,
- sources[i * 8 + 5].read,
- sources[i * 8 + 6].read,
- sources[i * 8 + 7].read
- );
- }
- }
+ // function createComputations8to1(n: number, sources: Computed[]) {
+ // for (let i = 0; i < n; i++) {
+ // createComputation8(
+ // sources[i * 8].read,
+ // sources[i * 8 + 1].read,
+ // sources[i * 8 + 2].read,
+ // sources[i * 8 + 3].read,
+ // sources[i * 8 + 4].read,
+ // sources[i * 8 + 5].read,
+ // sources[i * 8 + 6].read,
+ // sources[i * 8 + 7].read
+ // );
+ // }
+ // }
// only create n / 100 computations, as otherwise takes too long
function createComputations1000to1(n: number, sources: Computed[]) {
@@ -193,20 +193,20 @@ export function sbench(framework: ReactiveFramework) {
framework.computed(() => s1() + s2() + s3() + s4());
}
- function createComputation8(
- s1: Reader,
- s2: Reader,
- s3: Reader,
- s4: Reader,
- s5: Reader,
- s6: Reader,
- s7: Reader,
- s8: Reader
- ) {
- framework.computed(
- () => s1() + s2() + s3() + s4() + s5() + s6() + s7() + s8()
- );
- }
+ // function createComputation8(
+ // s1: Reader,
+ // s2: Reader,
+ // s3: Reader,
+ // s4: Reader,
+ // s5: Reader,
+ // s6: Reader,
+ // s7: Reader,
+ // s8: Reader
+ // ) {
+ // framework.computed(
+ // () => s1() + s2() + s3() + s4() + s5() + s6() + s7() + s8()
+ // );
+ // }
function createComputation1000(ss: Computed[], offset: number) {
framework.computed(() => {
@@ -247,7 +247,7 @@ export function sbench(framework: ReactiveFramework) {
}
function updateComputations1000to1(n: number, sources: Signal[]) {
- let { read: get1, write: set1 } = sources[0];
+ let { read: _get1, write: set1 } = sources[0];
framework.computed(() => {
let sum = 0;
for (let i = 0; i < 1000; i++) {
From 3ed3e4f7d303de0c7c839d6d3c7890c2e0956a1c Mon Sep 17 00:00:00 2001
From: Travis Fischer
Date: Mon, 16 Sep 2024 00:22:02 -0500
Subject: [PATCH 23/45] feat: update tests to get them all working reliably
---
src/cellxBench.ts | 5 ++-
src/config.ts | 50 +++++++++++++++-------------
src/dynamicBench.ts | 13 ++++++--
src/frameworks.test.ts | 58 ++++++++++++++++++---------------
src/frameworks/compostate.ts | 2 ++
src/frameworks/kairo.ts | 2 +-
src/frameworks/vueReactivity.ts | 16 +++++++--
src/index.ts | 13 ++++----
src/kairo/deep.ts | 2 +-
src/util/dependencyGraph.ts | 5 ++-
src/util/perfTests.ts | 6 +++-
11 files changed, 103 insertions(+), 69 deletions(-)
diff --git a/src/cellxBench.ts b/src/cellxBench.ts
index 0c876bc..d8b0f29 100644
--- a/src/cellxBench.ts
+++ b/src/cellxBench.ts
@@ -88,6 +88,8 @@ type BenchmarkResults = [
];
export const cellxbench = (framework: ReactiveFramework) => {
+ globalThis.gc?.();
+
const expected: Record = {
1000: [
[-3, -6, -2, 2],
@@ -115,7 +117,6 @@ export const cellxbench = (framework: ReactiveFramework) => {
total += elapsed;
}
- globalThis.gc?.();
logPerfResult({
framework: framework.name,
test: `cellx${layers}`,
@@ -137,4 +138,6 @@ export const cellxbench = (framework: ReactiveFramework) => {
`Expected last layer ${expectedAfter}, found last layer ${after}`
);
}
+
+ globalThis.gc?.();
};
diff --git a/src/config.ts b/src/config.ts
index 254f544..8c49e58 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -1,7 +1,7 @@
import { TestConfig, FrameworkInfo } from "./util/frameworkTypes";
import { angularFramework } from "./frameworks/angularSignals";
-import { compostateFramework } from "./frameworks/compostate";
+// import { compostateFramework } from "./frameworks/compostate";
import { mobxFramework } from "./frameworks/mobx";
import { tc39SignalsProposalStage0 } from "./frameworks/tc39-proposal-signals-stage-0";
import { molWireFramework } from "./frameworks/molWire";
@@ -22,20 +22,24 @@ export const frameworkInfo: FrameworkInfo[] = [
{ framework: reactivelyFramework, testPullCounts: true },
{ framework: sFramework },
{ framework: angularFramework, testPullCounts: true },
- { framework: compostateFramework, testPullCounts: true },
- // { framework: kairoFramework, testPullCounts: true },
- // NOTE: MobX currently hangs on some of the dynamic tests, so disable it if you want to run them. (https://github.com/mobxjs/mobx/issues/3926)
- { framework: mobxFramework },
{ framework: molWireFramework, testPullCounts: true },
{ framework: obyFramework, testPullCounts: true },
{ framework: signiaFramework, testPullCounts: true },
- // Solid can't testPullCounts because batch executes all leaf nodes even if unread
{ framework: solidFramework },
{ framework: usignalFramework, testPullCounts: true },
- // NOTE: Valtio currently hangs on some of the dynamic tests, so disable it if you want to run them. (https://github.com/pmndrs/valtio/discussions/949)
- // ramework: valtioFramework },
- { framework: vueReactivityFramework, testPullCounts: true },
{ framework: xReactivityFramework, testPullCounts: true },
+ // NOTE: Vue currently hangs on some of the `dynamic` tests and `cellx` tests, so disable it if you want to run them. https://github.com/vuejs/core/issues/11928
+ { framework: vueReactivityFramework, testPullCounts: true },
+ // NOTE: MobX currently hangs on some of the `dynamic` tests and `cellx` tests, so disable it if you want to run them. (https://github.com/mobxjs/mobx/issues/3926)
+ { framework: mobxFramework, testPullCounts: false },
+
+ // --- Disabled frameworks ---
+ // NOTE: the compostate adapter is currently broken and unused.
+ // { framework: compostateFramework },
+ // NOTE: the kairo adapter is currently broken and unused.
+ // { framework: kairoFramework, testPullCounts: true },
+ // NOTE: Valtio currently hangs on some of the `dynamic` tests, so disable it if you want to run them. (https://github.com/pmndrs/valtio/discussions/949)
+ // { framework: valtioFramework },
];
export const perfTests: TestConfig[] = [
@@ -104,17 +108,19 @@ export const perfTests: TestConfig[] = [
count: 1246502,
},
},
- {
- name: "very dynamic",
- width: 100,
- totalLayers: 15,
- staticFraction: 0.5,
- nSources: 6,
- readFraction: 1,
- iterations: 2000,
- expected: {
- sum: 15664996402790400,
- count: 1078671,
- },
- },
+ // Several frameworks hang on this test, so disabling it for now.
+ // @see https://github.com/vuejs/core/issues/11928
+ // {
+ // name: "very dynamic",
+ // width: 100,
+ // totalLayers: 15,
+ // staticFraction: 0.5,
+ // nSources: 6,
+ // readFraction: 1,
+ // iterations: 2000,
+ // expected: {
+ // sum: 15664996402790400,
+ // count: 1078671,
+ // },
+ // },
];
diff --git a/src/dynamicBench.ts b/src/dynamicBench.ts
index 7d28d2c..1f64f47 100644
--- a/src/dynamicBench.ts
+++ b/src/dynamicBench.ts
@@ -21,12 +21,19 @@ export async function dynamicBench(
function runOnce(): number {
// Create a new graph from scratch for each run to ensure they're independent
// from each other.
- const graph = makeGraph(framework, config, counter);
- return runGraph(graph, iterations, readFraction, framework);
+ try {
+ const graph = makeGraph(framework, config, counter);
+ const res = runGraph(graph, iterations, readFraction, framework);
+ globalThis.gc?.();
+ return res;
+ } catch (err: any) {
+ console.warn(`Error dynamicBench "${framework.name}":`, err.message);
+ return -1;
+ }
}
// warm up
- // runOnce();
+ runOnce();
const timedResult = await fastestTest(testRepeats, () => {
counter.count = 0;
diff --git a/src/frameworks.test.ts b/src/frameworks.test.ts
index cfa6840..fdaf16a 100644
--- a/src/frameworks.test.ts
+++ b/src/frameworks.test.ts
@@ -58,36 +58,40 @@ function frameworkTests({ framework, testPullCounts }: FrameworkInfo) {
});
test(`${name} | static graph, read 2/3 of leaves`, () => {
- const config = makeConfig();
- config.readFraction = 2 / 3;
- config.iterations = 10;
- const counter = new Counter();
- const graph = makeGraph(framework, config, counter);
- const sum = runGraph(graph, 10, 2 / 3, framework);
-
- expect(sum).toEqual(73);
- if (testPullCounts) {
- expect(counter.count).toEqual(41);
- } else {
- expect(counter.count).toBeGreaterThanOrEqual(41);
- }
+ framework.withBuild(() => {
+ const config = makeConfig();
+ config.readFraction = 2 / 3;
+ config.iterations = 10;
+ const counter = new Counter();
+ const graph = makeGraph(framework, config, counter);
+ const sum = runGraph(graph, 10, 2 / 3, framework);
+
+ expect(sum).toEqual(73);
+ if (testPullCounts) {
+ expect(counter.count).toEqual(41);
+ } else {
+ expect(counter.count).toBeGreaterThanOrEqual(41);
+ }
+ });
});
test(`${name} | dynamic graph`, () => {
- const config = makeConfig();
- config.staticFraction = 0.5;
- config.width = 4;
- config.totalLayers = 2;
- const counter = new Counter();
- const graph = makeGraph(framework, config, counter);
- const sum = runGraph(graph, 10, 1, framework);
-
- expect(sum).toEqual(72);
- if (testPullCounts) {
- expect(counter.count).toEqual(22);
- } else {
- expect(counter.count).toBeGreaterThanOrEqual(22);
- }
+ framework.withBuild(() => {
+ const config = makeConfig();
+ config.staticFraction = 0.5;
+ config.width = 4;
+ config.totalLayers = 2;
+ const counter = new Counter();
+ const graph = makeGraph(framework, config, counter);
+ const sum = runGraph(graph, 10, 1, framework);
+
+ expect(sum).toEqual(72);
+ if (testPullCounts) {
+ expect(counter.count).toEqual(22);
+ } else {
+ expect(counter.count).toBeGreaterThanOrEqual(22);
+ }
+ });
});
test(`${name} | withBuild`, () => {
diff --git a/src/frameworks/compostate.ts b/src/frameworks/compostate.ts
index e28edfd..aafc899 100644
--- a/src/frameworks/compostate.ts
+++ b/src/frameworks/compostate.ts
@@ -1,6 +1,8 @@
import { signal, computed, syncEffect, batch, createRoot } from "compostate";
import { ReactiveFramework } from "../util/reactiveFramework";
+// NOTE: The compostate adapter is currently not working and unused.
+
export const compostateFramework: ReactiveFramework = {
name: "Compostate",
signal: (initialValue) => {
diff --git a/src/frameworks/kairo.ts b/src/frameworks/kairo.ts
index 613a8df..bb89329 100644
--- a/src/frameworks/kairo.ts
+++ b/src/frameworks/kairo.ts
@@ -2,7 +2,7 @@ import { ReactiveFramework } from "../util/reactiveFramework";
import { batch, computed, effect, mutValue } from "kairo";
import { collectScope } from "kairo";
-// NOTE: The kairo adapter is currently not working and used.
+// NOTE: The kairo adapter is currently not working and unused.
export const kairoFramework: ReactiveFramework = {
name: "kairo",
diff --git a/src/frameworks/vueReactivity.ts b/src/frameworks/vueReactivity.ts
index d379a6e..89778a5 100644
--- a/src/frameworks/vueReactivity.ts
+++ b/src/frameworks/vueReactivity.ts
@@ -7,6 +7,8 @@ import {
} from "@vue/reactivity";
import { ReactiveFramework } from "../util/reactiveFramework";
+// The `@vue/reactivity` adapter is currently broken for some tests pending https://github.com/vuejs/core/issues/11928
+
let scheduled = [] as ReactiveEffect[];
let batching = false;
@@ -26,13 +28,12 @@ export const vueReactivityFramework: ReactiveFramework = {
};
},
effect: (fn) => {
- let t = effect(fn, {
+ let t = effect(() => fn(), {
scheduler: () => {
scheduled.push(t.effect);
},
});
},
- // withBatch: (fn) => fn(),
withBatch: (fn) => {
if (batching) {
fn();
@@ -44,8 +45,17 @@ export const vueReactivityFramework: ReactiveFramework = {
}
batching = false;
}
+
+ // if (batching) {
+ // fn();
+ // }
+ // batching = true;
+ // fn();
+ // while (scheduled.length) {
+ // scheduled.pop()!.run();
+ // }
+ // batching = false;
},
- // withBuild: (fn) => fn()
withBuild: (fn) => {
const e = effectScope();
const r = e.run(fn)!;
diff --git a/src/index.ts b/src/index.ts
index de2596c..da42b0f 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,5 +1,5 @@
import { dynamicBench } from "./dynamicBench";
-import { cellxbench } from "./cellxBench";
+// import { cellxbench } from "./cellxBench";
import { sbench } from "./sBench";
import { frameworkInfo } from "./config";
import { logPerfResult, perfReportHeaders } from "./util/perfLogging";
@@ -22,12 +22,11 @@ async function main() {
sbench(framework);
}
- for (const { framework } of frameworkInfo) {
- // https://github.com/vuejs/core/issues/11928
- if (framework.name !== "Vue") {
- cellxbench(framework);
- }
- }
+ // MobX, Vue, and Valtio all fail this test currently, so disabling it for now.
+ // @see https://github.com/vuejs/core/issues/11928
+ // for (const { framework } of frameworkInfo) {
+ // cellxbench(framework);
+ // }
for (const frameworkTest of frameworkInfo) {
await dynamicBench(frameworkTest);
diff --git a/src/kairo/deep.ts b/src/kairo/deep.ts
index 534318c..eef6f8e 100644
--- a/src/kairo/deep.ts
+++ b/src/kairo/deep.ts
@@ -14,7 +14,7 @@ export function deepPropagation(bridge: ReactiveFramework) {
}
let callCounter = new Counter();
- const stop = bridge.effect(() => {
+ bridge.effect(() => {
current.read();
callCounter.count++;
});
diff --git a/src/util/dependencyGraph.ts b/src/util/dependencyGraph.ts
index 403b2d8..112e720 100644
--- a/src/util/dependencyGraph.ts
+++ b/src/util/dependencyGraph.ts
@@ -71,7 +71,7 @@ export function runGraph(
sources[sourceDex].write(i + sourceDex);
});
- // this batch is necessary for `mobx` (https://github.com/mobxjs/mobx/issues/3926)
+ // This batch is only necessary for `mobx`: https://github.com/mobxjs/mobx/issues/3926
framework.withBatch(() => {
for (const leaf of readLeaves) {
leaf.read();
@@ -79,9 +79,8 @@ export function runGraph(
});
}
+ // This batch is only necessary for `mobx`: https://github.com/mobxjs/mobx/issues/3926
let sum = 0;
-
- // this batch is necessary for `mobx` (https://github.com/mobxjs/mobx/issues/3926)
framework.withBatch(() => {
sum = readLeaves.reduce((total, leaf) => leaf.read() + total, 0);
});
diff --git a/src/util/perfTests.ts b/src/util/perfTests.ts
index 0a0a6c7..9b37333 100644
--- a/src/util/perfTests.ts
+++ b/src/util/perfTests.ts
@@ -29,7 +29,11 @@ export function verifyBenchResult(
`sum ${framework.name} ${config.name} result:${result.sum} expected:${expected.sum}`
);
}
- if (expected.count && (config.readFraction === 1 || testPullCounts)) {
+ if (
+ expected.count &&
+ (config.readFraction === 1 || testPullCounts) &&
+ testPullCounts !== false
+ ) {
console.assert(
result.count === expected.count,
`count ${framework.name} ${config.name} result:${result.count} expected:${expected.count}`
From e9eb9c757ccbaf18cf6d6efb0ef39d1f69d5ae97 Mon Sep 17 00:00:00 2001
From: Travis Fischer
Date: Mon, 16 Sep 2024 00:49:10 -0500
Subject: [PATCH 24/45] feat: fix @vue/reactivity for kairo tests
---
package.json | 2 ++
src/index.ts | 20 ++++++++++----------
src/kairo/broad.ts | 4 ++--
src/kairo/deep.ts | 4 ++--
src/kairo/diamond.ts | 4 ++--
src/kairo/repeated.ts | 4 ++--
src/kairo/triangle.ts | 4 ++--
src/kairo/unstable.ts | 4 ++--
8 files changed, 24 insertions(+), 22 deletions(-)
diff --git a/package.json b/package.json
index 4d92a58..01478e0 100644
--- a/package.json
+++ b/package.json
@@ -5,6 +5,8 @@
"main": "index.js",
"scripts": {
"test": "vitest run",
+ "build": "esbuild src/index.ts --bundle --format=cjs --platform=node --outdir=dist --sourcemap=external",
+ "run": "node --expose-gc dist/index.js",
"bench": "esbuild src/index.ts --bundle --format=cjs --platform=node | node --expose-gc"
},
"keywords": [],
diff --git a/src/index.ts b/src/index.ts
index da42b0f..7203048 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -8,19 +8,19 @@ import { kairoBench } from "./kairoBench";
async function main() {
logPerfResult(perfReportHeaders());
- // (globalThis as any).__DEV__ = true;
+ (globalThis as any).__DEV__ = true;
for (const { framework } of frameworkInfo) {
await kairoBench(framework);
}
- for (const { framework } of frameworkInfo) {
- await molBench(framework);
- }
+ // for (const { framework } of frameworkInfo) {
+ // await molBench(framework);
+ // }
- for (const { framework } of frameworkInfo) {
- sbench(framework);
- }
+ // for (const { framework } of frameworkInfo) {
+ // sbench(framework);
+ // }
// MobX, Vue, and Valtio all fail this test currently, so disabling it for now.
// @see https://github.com/vuejs/core/issues/11928
@@ -28,9 +28,9 @@ async function main() {
// cellxbench(framework);
// }
- for (const frameworkTest of frameworkInfo) {
- await dynamicBench(frameworkTest);
- }
+ // for (const frameworkTest of frameworkInfo) {
+ // await dynamicBench(frameworkTest);
+ // }
}
main();
diff --git a/src/kairo/broad.ts b/src/kairo/broad.ts
index 4507289..6a84860 100644
--- a/src/kairo/broad.ts
+++ b/src/kairo/broad.ts
@@ -24,7 +24,7 @@ export function broadPropagation(bridge: ReactiveFramework) {
bridge.withBatch(() => {
head.write(1);
});
- const atleast = 50 * 50;
+ // const atleast = 50 * 50;
callCounter.count = 0;
for (let i = 0; i < 50; i++) {
bridge.withBatch(() => {
@@ -32,6 +32,6 @@ export function broadPropagation(bridge: ReactiveFramework) {
});
console.assert(last.read() === i + 50);
}
- console.assert(callCounter.count === atleast, callCounter.count);
+ // console.assert(callCounter.count === atleast, callCounter.count);
};
}
diff --git a/src/kairo/deep.ts b/src/kairo/deep.ts
index eef6f8e..eb05a08 100644
--- a/src/kairo/deep.ts
+++ b/src/kairo/deep.ts
@@ -25,7 +25,7 @@ export function deepPropagation(bridge: ReactiveFramework) {
bridge.withBatch(() => {
head.write(1);
});
- const atleast = iter;
+ // const atleast = iter;
callCounter.count = 0;
for (let i = 0; i < iter; i++) {
bridge.withBatch(() => {
@@ -34,6 +34,6 @@ export function deepPropagation(bridge: ReactiveFramework) {
console.assert(current.read() === len + i);
}
- console.assert(callCounter.count === atleast);
+ // console.assert(callCounter.count === atleast);
};
}
diff --git a/src/kairo/diamond.ts b/src/kairo/diamond.ts
index b98fba1..740f1c3 100644
--- a/src/kairo/diamond.ts
+++ b/src/kairo/diamond.ts
@@ -27,7 +27,7 @@ export function diamond(bridge: ReactiveFramework) {
head.write(1);
});
console.assert(sum.read() === 2 * width);
- const atleast = 500;
+ // const atleast = 500;
callCounter.count = 0;
for (let i = 0; i < 500; i++) {
bridge.withBatch(() => {
@@ -35,6 +35,6 @@ export function diamond(bridge: ReactiveFramework) {
});
console.assert(sum.read() === (i + 1) * width);
}
- console.assert(callCounter.count === atleast);
+ // console.assert(callCounter.count === atleast);
};
}
diff --git a/src/kairo/repeated.ts b/src/kairo/repeated.ts
index c3313b5..2258dd8 100644
--- a/src/kairo/repeated.ts
+++ b/src/kairo/repeated.ts
@@ -26,7 +26,7 @@ export function repeatedObservers(bridge: ReactiveFramework) {
head.write(1);
});
console.assert(current.read() === size);
- const atleast = 100;
+ // const atleast = 100;
callCounter.count = 0;
for (let i = 0; i < 100; i++) {
bridge.withBatch(() => {
@@ -34,6 +34,6 @@ export function repeatedObservers(bridge: ReactiveFramework) {
});
console.assert(current.read() === i * size);
}
- console.assert(callCounter.count === atleast);
+ // console.assert(callCounter.count === atleast);
};
}
diff --git a/src/kairo/triangle.ts b/src/kairo/triangle.ts
index b472506..24a94b2 100644
--- a/src/kairo/triangle.ts
+++ b/src/kairo/triangle.ts
@@ -30,7 +30,7 @@ export function triangle(bridge: ReactiveFramework) {
head.write(1);
});
console.assert(sum.read() === constant);
- const atleast = 100;
+ // const atleast = 100;
callCounter.count = 0;
for (let i = 0; i < 100; i++) {
bridge.withBatch(() => {
@@ -38,7 +38,7 @@ export function triangle(bridge: ReactiveFramework) {
});
console.assert(sum.read() === constant - width + i * width);
}
- console.assert(callCounter.count === atleast);
+ // console.assert(callCounter.count === atleast);
};
}
diff --git a/src/kairo/unstable.ts b/src/kairo/unstable.ts
index c520f9f..e70ae16 100644
--- a/src/kairo/unstable.ts
+++ b/src/kairo/unstable.ts
@@ -24,7 +24,7 @@ export function unstable(bridge: ReactiveFramework) {
head.write(1);
});
console.assert(current.read() === 40);
- const atleast = 100;
+ // const atleast = 100;
callCounter.count = 0;
for (let i = 0; i < 100; i++) {
bridge.withBatch(() => {
@@ -32,6 +32,6 @@ export function unstable(bridge: ReactiveFramework) {
});
// console.assert(current.read() === i % 2 ? i * 2 * 10 : i * -10);
}
- console.assert(callCounter.count === atleast);
+ // console.assert(callCounter.count === atleast);
};
}
From 9c65fd25231751b3cb415b53cfc86b2bff9df0e7 Mon Sep 17 00:00:00 2001
From: Travis Fischer
Date: Mon, 16 Sep 2024 00:51:39 -0500
Subject: [PATCH 25/45] =?UTF-8?q?=F0=9F=91=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/index.ts | 28 ++++++++++------------------
1 file changed, 10 insertions(+), 18 deletions(-)
diff --git a/src/index.ts b/src/index.ts
index 7203048..9998212 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -10,27 +10,19 @@ async function main() {
logPerfResult(perfReportHeaders());
(globalThis as any).__DEV__ = true;
- for (const { framework } of frameworkInfo) {
- await kairoBench(framework);
- }
-
- // for (const { framework } of frameworkInfo) {
- // await molBench(framework);
- // }
+ for (const frameworkTest of frameworkInfo) {
+ const { framework } = frameworkTest;
- // for (const { framework } of frameworkInfo) {
- // sbench(framework);
- // }
+ await kairoBench(framework);
+ await molBench(framework);
+ sbench(framework);
- // MobX, Vue, and Valtio all fail this test currently, so disabling it for now.
- // @see https://github.com/vuejs/core/issues/11928
- // for (const { framework } of frameworkInfo) {
- // cellxbench(framework);
- // }
+ // MobX, Vue, and Valtio all fail this test currently, so disabling it for now.
+ // @see https://github.com/vuejs/core/issues/11928
+ // cellxbench(framework);
- // for (const frameworkTest of frameworkInfo) {
- // await dynamicBench(frameworkTest);
- // }
+ await dynamicBench(frameworkTest);
+ }
}
main();
From c22196a4f4d2671e35537886233e1c264a7d7070 Mon Sep 17 00:00:00 2001
From: Travis Fischer
Date: Mon, 16 Sep 2024 01:34:51 -0500
Subject: [PATCH 26/45] =?UTF-8?q?=F0=9F=8E=92?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/config.ts | 26 +++++++++---------
src/util/dependencyGraph.ts | 53 ++++++++++++++++++++++++-------------
2 files changed, 47 insertions(+), 32 deletions(-)
diff --git a/src/config.ts b/src/config.ts
index 8c49e58..8b090f8 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -17,19 +17,19 @@ import { xReactivityFramework } from "./frameworks/xReactivity";
// import { valtioFramework } from "./frameworks/valtio";
export const frameworkInfo: FrameworkInfo[] = [
- { framework: preactSignalFramework, testPullCounts: true },
- { framework: tc39SignalsProposalStage0, testPullCounts: true },
- { framework: reactivelyFramework, testPullCounts: true },
- { framework: sFramework },
- { framework: angularFramework, testPullCounts: true },
- { framework: molWireFramework, testPullCounts: true },
- { framework: obyFramework, testPullCounts: true },
- { framework: signiaFramework, testPullCounts: true },
- { framework: solidFramework },
- { framework: usignalFramework, testPullCounts: true },
- { framework: xReactivityFramework, testPullCounts: true },
- // NOTE: Vue currently hangs on some of the `dynamic` tests and `cellx` tests, so disable it if you want to run them. https://github.com/vuejs/core/issues/11928
- { framework: vueReactivityFramework, testPullCounts: true },
+ // { framework: preactSignalFramework, testPullCounts: true },
+ // { framework: tc39SignalsProposalStage0, testPullCounts: true },
+ // { framework: reactivelyFramework, testPullCounts: true },
+ // { framework: sFramework },
+ // { framework: angularFramework, testPullCounts: true },
+ // { framework: molWireFramework, testPullCounts: true },
+ // { framework: obyFramework, testPullCounts: true },
+ // { framework: signiaFramework, testPullCounts: true },
+ // { framework: solidFramework },
+ // { framework: usignalFramework, testPullCounts: true },
+ // { framework: xReactivityFramework, testPullCounts: true },
+ // // NOTE: Vue currently hangs on some of the `dynamic` tests and `cellx` tests, so disable it if you want to run them. https://github.com/vuejs/core/issues/11928
+ // { framework: vueReactivityFramework, testPullCounts: true },
// NOTE: MobX currently hangs on some of the `dynamic` tests and `cellx` tests, so disable it if you want to run them. (https://github.com/mobxjs/mobx/issues/3926)
{ framework: mobxFramework, testPullCounts: false },
diff --git a/src/util/dependencyGraph.ts b/src/util/dependencyGraph.ts
index 112e720..d99dbc6 100644
--- a/src/util/dependencyGraph.ts
+++ b/src/util/dependencyGraph.ts
@@ -56,34 +56,49 @@ export function runGraph(
const readLeaves = removeElems(leaves, skipCount, rand);
// const start = Date.now();
- for (let i = 0; i < iterations; i++) {
- // Useful for debugging edge cases for some frameworks that experience
- // dramatic slow downs for certain test configurations. These are generally
- // due to `computed` effects not being cached efficiently, and as the number
- // of layers increases, the uncached `computed` effects are re-evaluated in
- // an `O(n^2)` manner where `n` is the number of layers.
- // if (i % 100 === 0) {
- // console.log("iteration:", i, "delta:", Date.now() - start);
- // }
+ let sum = 0;
+ if (framework.name.toLowerCase() === "mobx") {
+ // This special-case is only necessary for `mobx`: https://github.com/mobxjs/mobx/issues/3926
framework.withBatch(() => {
- const sourceDex = i % sources.length;
- sources[sourceDex].write(i + sourceDex);
+ for (let i = 0; i < iterations; i++) {
+ // Useful for debugging edge cases for some frameworks that experience
+ // dramatic slow downs for certain test configurations. These are generally
+ // due to `computed` effects not being cached efficiently, and as the number
+ // of layers increases, the uncached `computed` effects are re-evaluated in
+ // an `O(n^2)` manner where `n` is the number of layers.
+ // if (i % 100 === 0) {
+ // console.log("iteration:", i, "delta:", Date.now() - start);
+ // }
+
+ const sourceDex = i % sources.length;
+ sources[sourceDex].write(i + sourceDex);
+
+ for (const leaf of readLeaves) {
+ leaf.read();
+ }
+ }
+
+ sum = readLeaves.reduce((total, leaf) => leaf.read() + total, 0);
});
+ } else {
+ for (let i = 0; i < iterations; i++) {
+ // if (i % 100 === 0) {
+ // console.log("iteration:", i, "delta:", Date.now() - start);
+ // }
+
+ framework.withBatch(() => {
+ const sourceDex = i % sources.length;
+ sources[sourceDex].write(i + sourceDex);
+ });
- // This batch is only necessary for `mobx`: https://github.com/mobxjs/mobx/issues/3926
- framework.withBatch(() => {
for (const leaf of readLeaves) {
leaf.read();
}
- });
- }
+ }
- // This batch is only necessary for `mobx`: https://github.com/mobxjs/mobx/issues/3926
- let sum = 0;
- framework.withBatch(() => {
sum = readLeaves.reduce((total, leaf) => leaf.read() + total, 0);
- });
+ }
return sum;
}
From 29d22d64666b25aa8268ef8ff30afe8d51bb7937 Mon Sep 17 00:00:00 2001
From: Travis Fischer
Date: Mon, 16 Sep 2024 01:42:59 -0500
Subject: [PATCH 27/45] docs: update benchmark results
---
README.md | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/README.md b/README.md
index 411a638..ae0aa54 100644
--- a/README.md
+++ b/README.md
@@ -39,13 +39,11 @@ We're also working on enabling consistent logging and efficient tracking of GC t
## Results
-
- Raw results CSV (lower times are better)
+
+ Raw results CSV (lower times are better)
-Note that MobX and Valtio are not included in the average results summary because they fail to run some of the benchmark tests.
-
-These results were last updated _September 2024_ on an M3 Macbook Pro.
+These results were last updated _September 2024_ on an M3 Macbook Pro using Node.js v22.4.1 ([c22196a](https://github.com/transitive-bullshit/js-reactivity-benchmark/tree/c22196a4f4d2671e35537886233e1c264a7d7070)).
From ff8b96251f75ad430ac24a647d430998a838916c Mon Sep 17 00:00:00 2001
From: Travis Fischer
Date: Mon, 16 Sep 2024 01:46:49 -0500
Subject: [PATCH 28/45] =?UTF-8?q?=F0=9F=90=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index ae0aa54..b62f810 100644
--- a/README.md
+++ b/README.md
@@ -43,7 +43,7 @@ We're also working on enabling consistent logging and efficient tracking of GC t
Raw results CSV (lower times are better)
-These results were last updated _September 2024_ on an M3 Macbook Pro using Node.js v22.4.1 ([c22196a](https://github.com/transitive-bullshit/js-reactivity-benchmark/tree/c22196a4f4d2671e35537886233e1c264a7d7070)).
+These results were last updated _September 2024_ on an M3 Macbook Pro using Node.js v22.4.1 ([29d22d6](https://github.com/transitive-bullshit/js-reactivity-benchmark/tree/29d22d64666b25aa8268ef8ff30afe8d51bb7937)).
From 902b7206ed278404e0fbd0d8fc0967b97b503d1b Mon Sep 17 00:00:00 2001
From: Travis Fischer
Date: Mon, 16 Sep 2024 02:42:25 -0500
Subject: [PATCH 29/45] =?UTF-8?q?=E2=AC=85?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/frameworks/vueReactivity.ts | 12 +-----------
1 file changed, 1 insertion(+), 11 deletions(-)
diff --git a/src/frameworks/vueReactivity.ts b/src/frameworks/vueReactivity.ts
index 89778a5..669bae0 100644
--- a/src/frameworks/vueReactivity.ts
+++ b/src/frameworks/vueReactivity.ts
@@ -13,7 +13,7 @@ let scheduled = [] as ReactiveEffect[];
let batching = false;
export const vueReactivityFramework: ReactiveFramework = {
- name: "Vue",
+ name: "@vue/reactivity",
signal: (initial) => {
const data = shallowRef(initial);
return {
@@ -45,16 +45,6 @@ export const vueReactivityFramework: ReactiveFramework = {
}
batching = false;
}
-
- // if (batching) {
- // fn();
- // }
- // batching = true;
- // fn();
- // while (scheduled.length) {
- // scheduled.pop()!.run();
- // }
- // batching = false;
},
withBuild: (fn) => {
const e = effectScope();
From 0e93a8b13d11c3644aa44a28b87caa2f3ea3a3a9 Mon Sep 17 00:00:00 2001
From: Travis Fischer
Date: Mon, 16 Sep 2024 03:19:31 -0500
Subject: [PATCH 30/45] feat: update @vue/reactivity to latest fix
---
package.json | 2 +-
pnpm-lock.yaml | 18 +++++++++---------
src/config.ts | 26 +++++++++++++-------------
src/index.ts | 6 +++---
4 files changed, 26 insertions(+), 26 deletions(-)
diff --git a/package.json b/package.json
index 01478e0..d267882 100644
--- a/package.json
+++ b/package.json
@@ -17,7 +17,7 @@
"@preact/signals": "^1.3.0",
"@reactively/core": "^0.0.8",
"@solidjs/reactivity": "^0.0.9",
- "@vue/reactivity": "^3.5.5",
+ "@vue/reactivity": "^3.5.6",
"compostate": "0.5.1",
"kairo": "0.6.0-rc.0",
"mobx": "^6.13.2",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 18639ce..e193462 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -21,8 +21,8 @@ importers:
specifier: ^0.0.9
version: 0.0.9
'@vue/reactivity':
- specifier: ^3.5.5
- version: 3.5.5
+ specifier: ^3.5.6
+ version: 3.5.6
compostate:
specifier: 0.5.1
version: 0.5.1
@@ -665,11 +665,11 @@ packages:
'@vitest/utils@2.1.1':
resolution: {integrity: sha512-Y6Q9TsI+qJ2CC0ZKj6VBb+T8UPz593N113nnUykqwANqhgf3QkZeHFlusgKLTqrnVHbj/XDKZcDHol+dxVT+rQ==}
- '@vue/reactivity@3.5.5':
- resolution: {integrity: sha512-V4tTWElZQhT73PSK3Wnax9R9m4qvMX+LeKHnfylZc6SLh4Jc5/BPakp6e3zEhKWi5AN8TDzRkGnLkp8OqycYng==}
+ '@vue/reactivity@3.5.6':
+ resolution: {integrity: sha512-shZ+KtBoHna5GyUxWfoFVBCVd7k56m6lGhk5e+J9AKjheHF6yob5eukssHRI+rzvHBiU1sWs/1ZhNbLExc5oYQ==}
- '@vue/shared@3.5.5':
- resolution: {integrity: sha512-0KyMXyEgnmFAs6rNUL+6eUHtUCqCaNrVd+AW3MX3LyA0Yry5SA0Km03CDKiOua1x1WWnIr+W9+S0GMFoSDWERQ==}
+ '@vue/shared@3.5.6':
+ resolution: {integrity: sha512-eidH0HInnL39z6wAt6SFIwBrvGOpDWsDxlw3rCgo1B+CQ1781WzQUSU3YjxgdkcJo9Q8S6LmXTkvI+cLHGkQfA==}
ansi-regex@4.1.1:
resolution: {integrity: sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==}
@@ -1461,11 +1461,11 @@ snapshots:
loupe: 3.1.1
tinyrainbow: 1.2.0
- '@vue/reactivity@3.5.5':
+ '@vue/reactivity@3.5.6':
dependencies:
- '@vue/shared': 3.5.5
+ '@vue/shared': 3.5.6
- '@vue/shared@3.5.5': {}
+ '@vue/shared@3.5.6': {}
ansi-regex@4.1.1: {}
diff --git a/src/config.ts b/src/config.ts
index 8b090f8..7cfcf58 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -1,7 +1,6 @@
import { TestConfig, FrameworkInfo } from "./util/frameworkTypes";
import { angularFramework } from "./frameworks/angularSignals";
-// import { compostateFramework } from "./frameworks/compostate";
import { mobxFramework } from "./frameworks/mobx";
import { tc39SignalsProposalStage0 } from "./frameworks/tc39-proposal-signals-stage-0";
import { molWireFramework } from "./frameworks/molWire";
@@ -14,22 +13,23 @@ import { sFramework } from "./frameworks/s";
import { usignalFramework } from "./frameworks/uSignal";
import { vueReactivityFramework } from "./frameworks/vueReactivity";
import { xReactivityFramework } from "./frameworks/xReactivity";
+// import { compostateFramework } from "./frameworks/compostate";
// import { valtioFramework } from "./frameworks/valtio";
export const frameworkInfo: FrameworkInfo[] = [
- // { framework: preactSignalFramework, testPullCounts: true },
- // { framework: tc39SignalsProposalStage0, testPullCounts: true },
- // { framework: reactivelyFramework, testPullCounts: true },
- // { framework: sFramework },
- // { framework: angularFramework, testPullCounts: true },
- // { framework: molWireFramework, testPullCounts: true },
- // { framework: obyFramework, testPullCounts: true },
- // { framework: signiaFramework, testPullCounts: true },
- // { framework: solidFramework },
- // { framework: usignalFramework, testPullCounts: true },
- // { framework: xReactivityFramework, testPullCounts: true },
+ { framework: preactSignalFramework, testPullCounts: true },
+ { framework: tc39SignalsProposalStage0, testPullCounts: true },
+ { framework: reactivelyFramework, testPullCounts: true },
+ { framework: sFramework },
+ { framework: angularFramework, testPullCounts: true },
+ { framework: molWireFramework, testPullCounts: true },
+ { framework: obyFramework, testPullCounts: true },
+ { framework: signiaFramework, testPullCounts: true },
+ { framework: solidFramework },
+ { framework: usignalFramework, testPullCounts: true },
+ { framework: xReactivityFramework, testPullCounts: true },
// // NOTE: Vue currently hangs on some of the `dynamic` tests and `cellx` tests, so disable it if you want to run them. https://github.com/vuejs/core/issues/11928
- // { framework: vueReactivityFramework, testPullCounts: true },
+ { framework: vueReactivityFramework, testPullCounts: true },
// NOTE: MobX currently hangs on some of the `dynamic` tests and `cellx` tests, so disable it if you want to run them. (https://github.com/mobxjs/mobx/issues/3926)
{ framework: mobxFramework, testPullCounts: false },
diff --git a/src/index.ts b/src/index.ts
index 9998212..1387678 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,5 +1,5 @@
import { dynamicBench } from "./dynamicBench";
-// import { cellxbench } from "./cellxBench";
+import { cellxbench } from "./cellxBench";
import { sbench } from "./sBench";
import { frameworkInfo } from "./config";
import { logPerfResult, perfReportHeaders } from "./util/perfLogging";
@@ -17,9 +17,9 @@ async function main() {
await molBench(framework);
sbench(framework);
- // MobX, Vue, and Valtio all fail this test currently, so disabling it for now.
+ // MobX and Valtio both fail this test currently, so disabling it for now.
// @see https://github.com/vuejs/core/issues/11928
- // cellxbench(framework);
+ cellxbench(framework);
await dynamicBench(frameworkTest);
}
From 0adc71cdf9d77eda425ee38291211caf15e455cc Mon Sep 17 00:00:00 2001
From: Travis Fischer
Date: Mon, 16 Sep 2024 03:32:12 -0500
Subject: [PATCH 31/45] feat: remove warnings for vue issue
---
src/config.ts | 1 -
src/frameworks/vueReactivity.ts | 2 --
2 files changed, 3 deletions(-)
diff --git a/src/config.ts b/src/config.ts
index 7cfcf58..8ac6411 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -28,7 +28,6 @@ export const frameworkInfo: FrameworkInfo[] = [
{ framework: solidFramework },
{ framework: usignalFramework, testPullCounts: true },
{ framework: xReactivityFramework, testPullCounts: true },
- // // NOTE: Vue currently hangs on some of the `dynamic` tests and `cellx` tests, so disable it if you want to run them. https://github.com/vuejs/core/issues/11928
{ framework: vueReactivityFramework, testPullCounts: true },
// NOTE: MobX currently hangs on some of the `dynamic` tests and `cellx` tests, so disable it if you want to run them. (https://github.com/mobxjs/mobx/issues/3926)
{ framework: mobxFramework, testPullCounts: false },
diff --git a/src/frameworks/vueReactivity.ts b/src/frameworks/vueReactivity.ts
index 669bae0..4c539cb 100644
--- a/src/frameworks/vueReactivity.ts
+++ b/src/frameworks/vueReactivity.ts
@@ -7,8 +7,6 @@ import {
} from "@vue/reactivity";
import { ReactiveFramework } from "../util/reactiveFramework";
-// The `@vue/reactivity` adapter is currently broken for some tests pending https://github.com/vuejs/core/issues/11928
-
let scheduled = [] as ReactiveEffect[];
let batching = false;
From fd6d6710a20b7cb46f702b12bba6962958087951 Mon Sep 17 00:00:00 2001
From: Travis Fischer
Date: Mon, 16 Sep 2024 03:32:28 -0500
Subject: [PATCH 32/45] =?UTF-8?q?=F0=9F=90=9B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index b62f810..f8cd0c4 100644
--- a/README.md
+++ b/README.md
@@ -22,7 +22,7 @@ We're also working on enabling consistent logging and efficient tracking of GC t
- [Angular Signals](https://angular.dev/guide/signals/)
- [Compostate](https://github.com/lxsmnsyc/compostate)
- [Kairo](https://github.com/3Shain/kairo)
-- [MobX](https://mobx.js.org) (not included in the average benchmark results because it fails to run some tests)
+- [MobX](https://mobx.js.org)
- [mol wire](https://www.npmjs.com/package/mol_wire_lib)
- [Oby](https://github.com/vobyjs/oby)
- [Preact Signals](https://github.com/preactjs/signals)
From a136d206e4b749a5a624cc20f173390818b04ffe Mon Sep 17 00:00:00 2001
From: Travis Fischer
Date: Mon, 16 Sep 2024 03:40:12 -0500
Subject: [PATCH 33/45] feat: re-siable the cellx test suite for mobx
---
src/index.ts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/index.ts b/src/index.ts
index 1387678..701829a 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,5 +1,5 @@
import { dynamicBench } from "./dynamicBench";
-import { cellxbench } from "./cellxBench";
+// import { cellxbench } from "./cellxBench";
import { sbench } from "./sBench";
import { frameworkInfo } from "./config";
import { logPerfResult, perfReportHeaders } from "./util/perfLogging";
@@ -19,7 +19,7 @@ async function main() {
// MobX and Valtio both fail this test currently, so disabling it for now.
// @see https://github.com/vuejs/core/issues/11928
- cellxbench(framework);
+ // cellxbench(framework);
await dynamicBench(frameworkTest);
}
From e83c0be8981aab07b43e77b9f01330f7c414dcf7 Mon Sep 17 00:00:00 2001
From: Travis Fischer
Date: Mon, 16 Sep 2024 03:41:09 -0500
Subject: [PATCH 34/45] =?UTF-8?q?=F0=9F=9A=85?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/frameworks/molWire.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/frameworks/molWire.ts b/src/frameworks/molWire.ts
index 310eefa..4b44d06 100644
--- a/src/frameworks/molWire.ts
+++ b/src/frameworks/molWire.ts
@@ -4,7 +4,7 @@ import $ from "mol_wire_lib";
const Atom = $.$mol_wire_atom; // fix a bug in mol exports
export const molWireFramework: ReactiveFramework = {
- name: "$mol_wire_atom",
+ name: "$mol_wire",
signal: (initialValue: T): Signal => {
const atom = new Atom("", (next: T = initialValue) => next);
return {
From c501ada78d1052554786a74a9549979260ca73fa Mon Sep 17 00:00:00 2001
From: Travis Fischer
Date: Mon, 16 Sep 2024 16:24:16 -0500
Subject: [PATCH 35/45] feat: add svelte v5 framework to benchmark
---
README.md | 20 +-----
package.json | 1 +
pnpm-lock.yaml | 120 ++++++++++++++++++++++++++++++++++++
src/config.ts | 2 +
src/frameworks/svelte.ts | 48 +++++++++++++++
src/index.ts | 2 +-
src/util/dependencyGraph.ts | 6 +-
7 files changed, 179 insertions(+), 20 deletions(-)
create mode 100644 src/frameworks/svelte.ts
diff --git a/README.md b/README.md
index f8cd0c4..6e0c25e 100644
--- a/README.md
+++ b/README.md
@@ -30,6 +30,7 @@ We're also working on enabling consistent logging and efficient tracking of GC t
- [S.js](https://github.com/adamhaile/S)
- [Signia](https://github.com/tldraw/signia)
- [Solid](https://github.com/solidjs/solid)
+- [Svelte v5](https://svelte.dev/blog/runes)
- [TC39 Signals Proposal](https://github.com/tc39/proposal-signals) [polyfill](https://github.com/proposal-signals/signal-polyfill)
- [uSignal](https://github.com/WebReflection/usignal)
- [Valtio](https://github.com/pmndrs/valtio)
@@ -39,23 +40,8 @@ We're also working on enabling consistent logging and efficient tracking of GC t
## Results
-
- Raw results CSV (lower times are better)
+
+ (lower times are better)
These results were last updated _September 2024_ on an M3 Macbook Pro using Node.js v22.4.1 ([29d22d6](https://github.com/transitive-bullshit/js-reactivity-benchmark/tree/29d22d64666b25aa8268ef8ff30afe8d51bb7937)).
-
-
-
-Old results
-
-
-The frameworks are all plenty fast for typical applications. The charts report the run time of the test in milliseconds on an M1 laptop, and are made using [Tableau](https://public.tableau.com/). Typical applications will do much more work than a framework benchmark, and at these speeds the frameworks are unlikely to bottleneck overall performance.
-
-That said, there's learning here to improve performance of all the frameworks.
-
-
-
-
-
-
diff --git a/package.json b/package.json
index d267882..ea891e0 100644
--- a/package.json
+++ b/package.json
@@ -30,6 +30,7 @@
"signal-polyfill": "^0.1.0",
"signia": "^0.1.5",
"solid-js": "^1.8.22",
+ "svelte": "5.0.0-next.246",
"usignal": "^0.9.0",
"valtio": "^2.0.0"
},
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index e193462..98595d5 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -59,6 +59,9 @@ importers:
solid-js:
specifier: ^1.8.22
version: 1.8.22
+ svelte:
+ specifier: 5.0.0-next.246
+ version: 5.0.0-next.246
usignal:
specifier: ^0.9.0
version: 0.9.0
@@ -108,6 +111,10 @@ importers:
packages:
+ '@ampproject/remapping@2.3.0':
+ resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
+ engines: {node: '>=6.0.0'}
+
'@angular/core@18.2.4':
resolution: {integrity: sha512-ulYmYpI/ZVQ5BL38rBy4DS/9wgGWmVD9Uo6tcrLqCzt1G1G2nKwseZv009536pHfk6dj2HdPSkpcerhWh57DWw==}
engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0}
@@ -529,9 +536,24 @@ packages:
cpu: [x64]
os: [win32]
+ '@jridgewell/gen-mapping@0.3.5':
+ resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==}
+ engines: {node: '>=6.0.0'}
+
+ '@jridgewell/resolve-uri@3.1.2':
+ resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
+ engines: {node: '>=6.0.0'}
+
+ '@jridgewell/set-array@1.2.1':
+ resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==}
+ engines: {node: '>=6.0.0'}
+
'@jridgewell/sourcemap-codec@1.5.0':
resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==}
+ '@jridgewell/trace-mapping@0.3.25':
+ resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
+
'@preact/signals-core@1.8.0':
resolution: {integrity: sha512-OBvUsRZqNmjzCZXWLxkZfhcgT+Fk8DDcT/8vD6a1xhDemodyy87UJRJfASMuSD8FaAIeGgGm85ydXhm7lr4fyA==}
@@ -671,6 +693,16 @@ packages:
'@vue/shared@3.5.6':
resolution: {integrity: sha512-eidH0HInnL39z6wAt6SFIwBrvGOpDWsDxlw3rCgo1B+CQ1781WzQUSU3YjxgdkcJo9Q8S6LmXTkvI+cLHGkQfA==}
+ acorn-typescript@1.4.13:
+ resolution: {integrity: sha512-xsc9Xv0xlVfwp2o7sQ+GCQ1PgbkdcpWdTzrwXxO3xDMTAywVS3oXVOcOHuRjAPkS4P9b+yc/qNF15460v+jp4Q==}
+ peerDependencies:
+ acorn: '>=8.9.0'
+
+ acorn@8.12.1:
+ resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==}
+ engines: {node: '>=0.4.0'}
+ hasBin: true
+
ansi-regex@4.1.1:
resolution: {integrity: sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==}
engines: {node: '>=6'}
@@ -683,10 +715,18 @@ packages:
resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
engines: {node: '>= 8'}
+ aria-query@5.3.1:
+ resolution: {integrity: sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g==}
+ engines: {node: '>= 0.4'}
+
assertion-error@2.0.1:
resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
engines: {node: '>=12'}
+ axobject-query@4.1.0:
+ resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==}
+ engines: {node: '>= 0.4'}
+
binary-extensions@2.2.0:
resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
engines: {node: '>=8'}
@@ -774,6 +814,12 @@ packages:
engines: {node: '>=18'}
hasBin: true
+ esm-env@1.0.0:
+ resolution: {integrity: sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==}
+
+ esrap@1.2.2:
+ resolution: {integrity: sha512-F2pSJklxx1BlQIQgooczXCPHmcWpn6EsP5oo73LQfonG9fIlIENQ8vMmfGXeojP9MrkzUNAfyU5vdFlR9shHAw==}
+
estree-walker@3.0.3:
resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
@@ -826,12 +872,18 @@ packages:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
+ is-reference@3.0.2:
+ resolution: {integrity: sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==}
+
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
kairo@0.6.0-rc.0:
resolution: {integrity: sha512-8yWTOujaeU5a6FtFCQnRhljxo8KaxQVDV6xJFxEpkCKd2azlMBmc5ARazaQUb/KJ2PWzsVdiXRbvFmreP6pbFA==}
+ locate-character@3.0.0:
+ resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==}
+
locate-path@3.0.0:
resolution: {integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==}
engines: {node: '>=6'}
@@ -997,6 +1049,10 @@ packages:
resolution: {integrity: sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==}
engines: {node: '>=6'}
+ svelte@5.0.0-next.246:
+ resolution: {integrity: sha512-FRfq6W17mOHiSbY9nen6/skCV7AHQJdB9yaS9DA4x4mKXR/RIGMDLlxxU3jhQsMiLoqmUFHXJc6Rqe1o6HWlow==}
+ engines: {node: '>=18'}
+
tinybench@2.9.0:
resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
@@ -1134,11 +1190,19 @@ packages:
yargs@13.3.2:
resolution: {integrity: sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==}
+ zimmerframe@1.1.2:
+ resolution: {integrity: sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==}
+
zone.js@0.15.0:
resolution: {integrity: sha512-9oxn0IIjbCZkJ67L+LkhYWRyAy7axphb3VgE2MBDlOqnmHMPWGYMxJxBYFueFq/JGY2GMwS0rU+UCLunEmy5UA==}
snapshots:
+ '@ampproject/remapping@2.3.0':
+ dependencies:
+ '@jridgewell/gen-mapping': 0.3.5
+ '@jridgewell/trace-mapping': 0.3.25
+
'@angular/core@18.2.4(rxjs@7.8.1)(zone.js@0.15.0)':
dependencies:
rxjs: 7.8.1
@@ -1352,8 +1416,23 @@ snapshots:
'@esbuild/win32-x64@0.23.1':
optional: true
+ '@jridgewell/gen-mapping@0.3.5':
+ dependencies:
+ '@jridgewell/set-array': 1.2.1
+ '@jridgewell/sourcemap-codec': 1.5.0
+ '@jridgewell/trace-mapping': 0.3.25
+
+ '@jridgewell/resolve-uri@3.1.2': {}
+
+ '@jridgewell/set-array@1.2.1': {}
+
'@jridgewell/sourcemap-codec@1.5.0': {}
+ '@jridgewell/trace-mapping@0.3.25':
+ dependencies:
+ '@jridgewell/resolve-uri': 3.1.2
+ '@jridgewell/sourcemap-codec': 1.5.0
+
'@preact/signals-core@1.8.0': {}
'@preact/signals@1.3.0(preact@10.24.0)':
@@ -1467,6 +1546,12 @@ snapshots:
'@vue/shared@3.5.6': {}
+ acorn-typescript@1.4.13(acorn@8.12.1):
+ dependencies:
+ acorn: 8.12.1
+
+ acorn@8.12.1: {}
+
ansi-regex@4.1.1: {}
ansi-styles@3.2.1:
@@ -1478,8 +1563,12 @@ snapshots:
normalize-path: 3.0.0
picomatch: 2.3.1
+ aria-query@5.3.1: {}
+
assertion-error@2.0.1: {}
+ axobject-query@4.1.0: {}
+
binary-extensions@2.2.0: {}
braces@3.0.2:
@@ -1625,6 +1714,13 @@ snapshots:
'@esbuild/win32-ia32': 0.23.1
'@esbuild/win32-x64': 0.23.1
+ esm-env@1.0.0: {}
+
+ esrap@1.2.2:
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.0
+ '@types/estree': 1.0.5
+
estree-walker@3.0.3:
dependencies:
'@types/estree': 1.0.5
@@ -1665,10 +1761,16 @@ snapshots:
is-number@7.0.0: {}
+ is-reference@3.0.2:
+ dependencies:
+ '@types/estree': 1.0.5
+
js-tokens@4.0.0: {}
kairo@0.6.0-rc.0: {}
+ locate-character@3.0.0: {}
+
locate-path@3.0.0:
dependencies:
p-locate: 3.0.0
@@ -1818,6 +1920,22 @@ snapshots:
dependencies:
ansi-regex: 4.1.1
+ svelte@5.0.0-next.246:
+ dependencies:
+ '@ampproject/remapping': 2.3.0
+ '@jridgewell/sourcemap-codec': 1.5.0
+ '@types/estree': 1.0.5
+ acorn: 8.12.1
+ acorn-typescript: 1.4.13(acorn@8.12.1)
+ aria-query: 5.3.1
+ axobject-query: 4.1.0
+ esm-env: 1.0.0
+ esrap: 1.2.2
+ is-reference: 3.0.2
+ locate-character: 3.0.0
+ magic-string: 0.30.11
+ zimmerframe: 1.1.2
+
tinybench@2.9.0: {}
tinyexec@0.3.0: {}
@@ -1943,4 +2061,6 @@ snapshots:
y18n: 4.0.3
yargs-parser: 13.1.2
+ zimmerframe@1.1.2: {}
+
zone.js@0.15.0: {}
diff --git a/src/config.ts b/src/config.ts
index 8ac6411..d1b17cb 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -13,11 +13,13 @@ import { sFramework } from "./frameworks/s";
import { usignalFramework } from "./frameworks/uSignal";
import { vueReactivityFramework } from "./frameworks/vueReactivity";
import { xReactivityFramework } from "./frameworks/xReactivity";
+import { svelteFramework } from "./frameworks/svelte";
// import { compostateFramework } from "./frameworks/compostate";
// import { valtioFramework } from "./frameworks/valtio";
export const frameworkInfo: FrameworkInfo[] = [
{ framework: preactSignalFramework, testPullCounts: true },
+ { framework: svelteFramework, testPullCounts: true },
{ framework: tc39SignalsProposalStage0, testPullCounts: true },
{ framework: reactivelyFramework, testPullCounts: true },
{ framework: sFramework },
diff --git a/src/frameworks/svelte.ts b/src/frameworks/svelte.ts
new file mode 100644
index 0000000..c129550
--- /dev/null
+++ b/src/frameworks/svelte.ts
@@ -0,0 +1,48 @@
+import { ReactiveFramework } from "../util/reactiveFramework";
+// @ts-ignore
+import * as $ from "svelte/internal/client";
+
+// NOTE: The svelte adapter uses private, internal APIs that are usually only
+// used by the Svelte compiler and client runtime. The Svelte team has made the
+// decision to not expose these APIs publicly / officially, because it gives
+// them more freedom to experiment without making breaking changes, but given
+// that Svelte's v5 reactivity API is one of the most actively developed and
+// efficient TS implementations available, I wanted to include it in the
+// benchmark suite regardless.
+
+export const svelteFramework: ReactiveFramework = {
+ name: "Svelte v5",
+ signal: (initialValue) => {
+ const s = $.state(initialValue);
+ return {
+ write: (v) => $.set(s, v),
+ read: () => $.get(s),
+ };
+ },
+ computed: (fn) => {
+ const c = $.derived(fn);
+ return {
+ read: () => $.get(c),
+ };
+ },
+ effect: (fn) => {
+ // TODO: which one makes more sense here?
+ $.user_effect(fn);
+ // $.render_effect(fn);
+ fn();
+ },
+ withBatch: (fn) => {
+ fn();
+ // $.tick();
+ $.flush_sync();
+ },
+ withBuild: (fn) => {
+ let res: ReturnType | undefined;
+ const destroy = $.effect_root(() => {
+ res = fn();
+ });
+ $.tick();
+ destroy();
+ return res!;
+ },
+};
diff --git a/src/index.ts b/src/index.ts
index 701829a..e2e23c2 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -18,7 +18,7 @@ async function main() {
sbench(framework);
// MobX and Valtio both fail this test currently, so disabling it for now.
- // @see https://github.com/vuejs/core/issues/11928
+ // @see https://github.com/mobxjs/mobx/issues/3926
// cellxbench(framework);
await dynamicBench(frameworkTest);
diff --git a/src/util/dependencyGraph.ts b/src/util/dependencyGraph.ts
index d99dbc6..d9c62fa 100644
--- a/src/util/dependencyGraph.ts
+++ b/src/util/dependencyGraph.ts
@@ -55,10 +55,12 @@ export function runGraph(
const skipCount = Math.round(leaves.length * (1 - readFraction));
const readLeaves = removeElems(leaves, skipCount, rand);
// const start = Date.now();
-
let sum = 0;
- if (framework.name.toLowerCase() === "mobx") {
+ if (
+ framework.name.toLowerCase() === "mobx" ||
+ framework.name.toLowerCase() === "svelte v5"
+ ) {
// This special-case is only necessary for `mobx`: https://github.com/mobxjs/mobx/issues/3926
framework.withBatch(() => {
for (let i = 0; i < iterations; i++) {
From 99a7ca8f1f763e23a557391165603404082b5489 Mon Sep 17 00:00:00 2001
From: Travis Fischer
Date: Mon, 16 Sep 2024 17:09:56 -0500
Subject: [PATCH 36/45] =?UTF-8?q?=F0=9F=94=B2?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 6e0c25e..9f414ac 100644
--- a/README.md
+++ b/README.md
@@ -44,4 +44,4 @@ We're also working on enabling consistent logging and efficient tracking of GC t
(lower times are better)
-These results were last updated _September 2024_ on an M3 Macbook Pro using Node.js v22.4.1 ([29d22d6](https://github.com/transitive-bullshit/js-reactivity-benchmark/tree/29d22d64666b25aa8268ef8ff30afe8d51bb7937)).
+These results were last updated _September 2024_ on an M3 Macbook Pro using Node.js v22.4.1.
From 131f9905059824ca8246259b95151ab719b07289 Mon Sep 17 00:00:00 2001
From: Travis Fischer
Date: Mon, 16 Sep 2024 20:04:08 -0500
Subject: [PATCH 37/45] feat: fix s.js and improve svelte adapters
---
src/frameworks/svelte.ts | 9 ++------
src/index.ts | 2 ++
src/util/dependencyGraph.ts | 46 +++++++++++++++++++------------------
3 files changed, 28 insertions(+), 29 deletions(-)
diff --git a/src/frameworks/svelte.ts b/src/frameworks/svelte.ts
index c129550..4ffe72c 100644
--- a/src/frameworks/svelte.ts
+++ b/src/frameworks/svelte.ts
@@ -26,15 +26,10 @@ export const svelteFramework: ReactiveFramework = {
};
},
effect: (fn) => {
- // TODO: which one makes more sense here?
- $.user_effect(fn);
- // $.render_effect(fn);
- fn();
+ $.render_effect(fn);
},
withBatch: (fn) => {
- fn();
- // $.tick();
- $.flush_sync();
+ $.flush_sync(fn);
},
withBuild: (fn) => {
let res: ReturnType | undefined;
diff --git a/src/index.ts b/src/index.ts
index e2e23c2..4e09041 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -22,6 +22,8 @@ async function main() {
// cellxbench(framework);
await dynamicBench(frameworkTest);
+
+ globalThis.gc?.();
}
}
diff --git a/src/util/dependencyGraph.ts b/src/util/dependencyGraph.ts
index d9c62fa..a740d56 100644
--- a/src/util/dependencyGraph.ts
+++ b/src/util/dependencyGraph.ts
@@ -57,11 +57,30 @@ export function runGraph(
// const start = Date.now();
let sum = 0;
- if (
- framework.name.toLowerCase() === "mobx" ||
- framework.name.toLowerCase() === "svelte v5"
- ) {
- // This special-case is only necessary for `mobx`: https://github.com/mobxjs/mobx/issues/3926
+ if (framework.name === "s-js") {
+ // [S.js freeze](https://github.com/adamhaile/S#sdatavalue) doesn't allow different values to be set during a single batch, so special case it.
+ for (let i = 0; i < iterations; i++) {
+ // Useful for debugging edge cases for some frameworks that experience
+ // dramatic slow downs for certain test configurations. These are generally
+ // due to `computed` effects not being cached efficiently, and as the number
+ // of layers increases, the uncached `computed` effects are re-evaluated in
+ // an `O(n^2)` manner where `n` is the number of layers.
+ // if (i % 100 === 0) {
+ // console.log("iteration:", i, "delta:", Date.now() - start);
+ // }
+
+ framework.withBatch(() => {
+ const sourceDex = i % sources.length;
+ sources[sourceDex].write(i + sourceDex);
+ });
+
+ for (const leaf of readLeaves) {
+ leaf.read();
+ }
+ }
+
+ sum = readLeaves.reduce((total, leaf) => leaf.read() + total, 0);
+ } else {
framework.withBatch(() => {
for (let i = 0; i < iterations; i++) {
// Useful for debugging edge cases for some frameworks that experience
@@ -83,23 +102,6 @@ export function runGraph(
sum = readLeaves.reduce((total, leaf) => leaf.read() + total, 0);
});
- } else {
- for (let i = 0; i < iterations; i++) {
- // if (i % 100 === 0) {
- // console.log("iteration:", i, "delta:", Date.now() - start);
- // }
-
- framework.withBatch(() => {
- const sourceDex = i % sources.length;
- sources[sourceDex].write(i + sourceDex);
- });
-
- for (const leaf of readLeaves) {
- leaf.read();
- }
- }
-
- sum = readLeaves.reduce((total, leaf) => leaf.read() + total, 0);
}
return sum;
From 5c2d442f4df099e812504f4d08b179efc19ac1c2 Mon Sep 17 00:00:00 2001
From: Travis Fischer
Date: Mon, 16 Sep 2024 20:06:57 -0500
Subject: [PATCH 38/45] =?UTF-8?q?=E2=9E=A1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/util/dependencyGraph.ts | 9 ---------
1 file changed, 9 deletions(-)
diff --git a/src/util/dependencyGraph.ts b/src/util/dependencyGraph.ts
index a740d56..888a1ef 100644
--- a/src/util/dependencyGraph.ts
+++ b/src/util/dependencyGraph.ts
@@ -60,15 +60,6 @@ export function runGraph(
if (framework.name === "s-js") {
// [S.js freeze](https://github.com/adamhaile/S#sdatavalue) doesn't allow different values to be set during a single batch, so special case it.
for (let i = 0; i < iterations; i++) {
- // Useful for debugging edge cases for some frameworks that experience
- // dramatic slow downs for certain test configurations. These are generally
- // due to `computed` effects not being cached efficiently, and as the number
- // of layers increases, the uncached `computed` effects are re-evaluated in
- // an `O(n^2)` manner where `n` is the number of layers.
- // if (i % 100 === 0) {
- // console.log("iteration:", i, "delta:", Date.now() - start);
- // }
-
framework.withBatch(() => {
const sourceDex = i % sources.length;
sources[sourceDex].write(i + sourceDex);
From 924147de306a7a9a82b90d4d8fbdf25db2a56fd6 Mon Sep 17 00:00:00 2001
From: Travis Fischer
Date: Mon, 16 Sep 2024 20:48:20 -0500
Subject: [PATCH 39/45] feat: bump svelte
---
package.json | 2 +-
pnpm-lock.yaml | 10 +++++-----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/package.json b/package.json
index ea891e0..65ac781 100644
--- a/package.json
+++ b/package.json
@@ -30,7 +30,7 @@
"signal-polyfill": "^0.1.0",
"signia": "^0.1.5",
"solid-js": "^1.8.22",
- "svelte": "5.0.0-next.246",
+ "svelte": "5.0.0-next.247",
"usignal": "^0.9.0",
"valtio": "^2.0.0"
},
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 98595d5..5a6e353 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -60,8 +60,8 @@ importers:
specifier: ^1.8.22
version: 1.8.22
svelte:
- specifier: 5.0.0-next.246
- version: 5.0.0-next.246
+ specifier: 5.0.0-next.247
+ version: 5.0.0-next.247
usignal:
specifier: ^0.9.0
version: 0.9.0
@@ -1049,8 +1049,8 @@ packages:
resolution: {integrity: sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==}
engines: {node: '>=6'}
- svelte@5.0.0-next.246:
- resolution: {integrity: sha512-FRfq6W17mOHiSbY9nen6/skCV7AHQJdB9yaS9DA4x4mKXR/RIGMDLlxxU3jhQsMiLoqmUFHXJc6Rqe1o6HWlow==}
+ svelte@5.0.0-next.247:
+ resolution: {integrity: sha512-vfF5x75RDQwYErDru+usscMDrbm4KOV4UY7X52pbGPfFH5DsLpt7jiU+pBzB++W07YPKvoPWlNpl3OUKd7aBAQ==}
engines: {node: '>=18'}
tinybench@2.9.0:
@@ -1920,7 +1920,7 @@ snapshots:
dependencies:
ansi-regex: 4.1.1
- svelte@5.0.0-next.246:
+ svelte@5.0.0-next.247:
dependencies:
'@ampproject/remapping': 2.3.0
'@jridgewell/sourcemap-codec': 1.5.0
From 3153341c408167ff8649325f8a20799d9486aa2d Mon Sep 17 00:00:00 2001
From: Travis Fischer
Date: Tue, 17 Sep 2024 01:33:27 -0500
Subject: [PATCH 40/45] feat: add github CI
---
.github/funding.yml | 1 +
.github/workflows/main.yml | 41 ++++++++++++++++++++++++++++++++++++++
2 files changed, 42 insertions(+)
create mode 100644 .github/funding.yml
create mode 100644 .github/workflows/main.yml
diff --git a/.github/funding.yml b/.github/funding.yml
new file mode 100644
index 0000000..9377c23
--- /dev/null
+++ b/.github/funding.yml
@@ -0,0 +1 @@
+github: [transitive-bullshit]
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
new file mode 100644
index 0000000..84a1f0c
--- /dev/null
+++ b/.github/workflows/main.yml
@@ -0,0 +1,41 @@
+name: CI
+
+on: [push, pull_request]
+
+jobs:
+ test:
+ name: Test Node.js ${{ matrix.node-version }}
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: true
+ matrix:
+ node-version:
+ - 18
+ - 20
+ - 21
+ - 22
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Install pnpm
+ uses: pnpm/action-setup@v4
+ with:
+ version: 9.10.0
+ run_install: false
+
+ - name: Install Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: ${{ matrix.node-version }}
+ cache: "pnpm"
+
+ - name: Install dependencies
+ run: pnpm install --frozen-lockfile --strict-peer-dependencies
+
+ - name: Run test
+ run: pnpm test
+
+ - name: Run build
+ run: pnpm build
From 867d5158437cdbada9bf55bf84008c02b3ef1222 Mon Sep 17 00:00:00 2001
From: Travis Fischer
Date: Tue, 17 Sep 2024 01:37:40 -0500
Subject: [PATCH 41/45] =?UTF-8?q?=E2=9C=82?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/frameworks/svelte.ts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/frameworks/svelte.ts b/src/frameworks/svelte.ts
index 4ffe72c..61cc082 100644
--- a/src/frameworks/svelte.ts
+++ b/src/frameworks/svelte.ts
@@ -31,8 +31,8 @@ export const svelteFramework: ReactiveFramework = {
withBatch: (fn) => {
$.flush_sync(fn);
},
- withBuild: (fn) => {
- let res: ReturnType | undefined;
+ withBuild: (fn: () => T): T => {
+ let res: T | undefined;
const destroy = $.effect_root(() => {
res = fn();
});
From 630036906ad1d12ce56c1ddf04812d99551d9aad Mon Sep 17 00:00:00 2001
From: Travis Fischer
Date: Tue, 17 Sep 2024 14:59:30 -0500
Subject: [PATCH 42/45] fix: bugs with svelte and vue adapters
---
package.json | 2 +-
pnpm-lock.yaml | 10 +++++-----
src/frameworks.test.ts | 20 ++++++++++++--------
src/frameworks/svelte.ts | 4 +---
src/frameworks/vueReactivity.ts | 4 +---
src/index.ts | 3 ++-
6 files changed, 22 insertions(+), 21 deletions(-)
diff --git a/package.json b/package.json
index 65ac781..cbb44b6 100644
--- a/package.json
+++ b/package.json
@@ -30,7 +30,7 @@
"signal-polyfill": "^0.1.0",
"signia": "^0.1.5",
"solid-js": "^1.8.22",
- "svelte": "5.0.0-next.247",
+ "svelte": "5.0.0-next.249",
"usignal": "^0.9.0",
"valtio": "^2.0.0"
},
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 5a6e353..2ceb6a4 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -60,8 +60,8 @@ importers:
specifier: ^1.8.22
version: 1.8.22
svelte:
- specifier: 5.0.0-next.247
- version: 5.0.0-next.247
+ specifier: 5.0.0-next.249
+ version: 5.0.0-next.249
usignal:
specifier: ^0.9.0
version: 0.9.0
@@ -1049,8 +1049,8 @@ packages:
resolution: {integrity: sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==}
engines: {node: '>=6'}
- svelte@5.0.0-next.247:
- resolution: {integrity: sha512-vfF5x75RDQwYErDru+usscMDrbm4KOV4UY7X52pbGPfFH5DsLpt7jiU+pBzB++W07YPKvoPWlNpl3OUKd7aBAQ==}
+ svelte@5.0.0-next.249:
+ resolution: {integrity: sha512-vbGir3ScQJjdKyWjhLi4aXc0DpilL4zVzC8UdEksoUhvP6OcaXrTC3aitHfSmdQ+FDntDLUWtytZMA01nRBs6Q==}
engines: {node: '>=18'}
tinybench@2.9.0:
@@ -1920,7 +1920,7 @@ snapshots:
dependencies:
ansi-regex: 4.1.1
- svelte@5.0.0-next.247:
+ svelte@5.0.0-next.249:
dependencies:
'@ampproject/remapping': 2.3.0
'@jridgewell/sourcemap-codec': 1.5.0
diff --git a/src/frameworks.test.ts b/src/frameworks.test.ts
index fdaf16a..afd94ac 100644
--- a/src/frameworks.test.ts
+++ b/src/frameworks.test.ts
@@ -109,19 +109,23 @@ function frameworkTests({ framework, testPullCounts }: FrameworkInfo) {
test(`${name} | effect`, () => {
const spy = vi.fn();
+ const s = framework.signal(2);
+ let c: any;
+
framework.withBuild(() => {
- const s = framework.signal(2);
- const c = framework.computed(() => s.read() * 2);
+ c = framework.computed(() => s.read() * 2);
- framework.effect(() => spy(c.read()));
- framework.withBatch(() => {
- s.write(3);
+ framework.effect(() => {
+ spy(c.read());
});
-
- expect(s.read()).toEqual(3);
- expect(c.read()).toEqual(6);
});
+ expect(spy.mock.calls.length).toBe(1);
+ framework.withBatch(() => {
+ s.write(3);
+ });
+ expect(s.read()).toEqual(3);
+ expect(c.read()).toEqual(6);
expect(spy.mock.calls.length).toBe(2);
});
}
diff --git a/src/frameworks/svelte.ts b/src/frameworks/svelte.ts
index 61cc082..5644f5b 100644
--- a/src/frameworks/svelte.ts
+++ b/src/frameworks/svelte.ts
@@ -33,11 +33,9 @@ export const svelteFramework: ReactiveFramework = {
},
withBuild: (fn: () => T): T => {
let res: T | undefined;
- const destroy = $.effect_root(() => {
+ $.effect_root(() => {
res = fn();
});
- $.tick();
- destroy();
return res!;
},
};
diff --git a/src/frameworks/vueReactivity.ts b/src/frameworks/vueReactivity.ts
index 4c539cb..34268d4 100644
--- a/src/frameworks/vueReactivity.ts
+++ b/src/frameworks/vueReactivity.ts
@@ -46,8 +46,6 @@ export const vueReactivityFramework: ReactiveFramework = {
},
withBuild: (fn) => {
const e = effectScope();
- const r = e.run(fn)!;
- e.stop();
- return r;
+ return e.run(fn)!;
},
};
diff --git a/src/index.ts b/src/index.ts
index 4e09041..46baa74 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -17,8 +17,9 @@ async function main() {
await molBench(framework);
sbench(framework);
- // MobX and Valtio both fail this test currently, so disabling it for now.
+ // MobX, Valtio, and Svelte fail this test currently, so disabling it for now.
// @see https://github.com/mobxjs/mobx/issues/3926
+ // @see https://github.com/sveltejs/svelte/discussions/13277
// cellxbench(framework);
await dynamicBench(frameworkTest);
From 71223ab57e582a038ee9188939cba724a2aa2809 Mon Sep 17 00:00:00 2001
From: Travis Fischer
Date: Tue, 17 Sep 2024 15:30:03 -0500
Subject: [PATCH 43/45] fix: solidjs and svelte
---
src/dynamicBench.ts | 2 +-
src/util/dependencyGraph.ts | 3 ++-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/dynamicBench.ts b/src/dynamicBench.ts
index 1f64f47..91a364a 100644
--- a/src/dynamicBench.ts
+++ b/src/dynamicBench.ts
@@ -27,7 +27,7 @@ export async function dynamicBench(
globalThis.gc?.();
return res;
} catch (err: any) {
- console.warn(`Error dynamicBench "${framework.name}":`, err.message);
+ console.warn(`Error dynamicBench "${framework.name}":`, err);
return -1;
}
}
diff --git a/src/util/dependencyGraph.ts b/src/util/dependencyGraph.ts
index 888a1ef..eea0436 100644
--- a/src/util/dependencyGraph.ts
+++ b/src/util/dependencyGraph.ts
@@ -54,10 +54,11 @@ export function runGraph(
const leaves = layers[layers.length - 1];
const skipCount = Math.round(leaves.length * (1 - readFraction));
const readLeaves = removeElems(leaves, skipCount, rand);
+ const frameworkName = framework.name.toLowerCase();
// const start = Date.now();
let sum = 0;
- if (framework.name === "s-js") {
+ if (frameworkName === "s-js" || frameworkName === "solidjs") {
// [S.js freeze](https://github.com/adamhaile/S#sdatavalue) doesn't allow different values to be set during a single batch, so special case it.
for (let i = 0; i < iterations; i++) {
framework.withBatch(() => {
From e4a399a4bd9034baa1734fce2b91c038b5489906 Mon Sep 17 00:00:00 2001
From: Travis Fischer
Date: Tue, 17 Sep 2024 15:31:24 -0500
Subject: [PATCH 44/45] docs: update readme results
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 9f414ac..325c1f5 100644
--- a/README.md
+++ b/README.md
@@ -40,7 +40,7 @@ We're also working on enabling consistent logging and efficient tracking of GC t
## Results
-
+
(lower times are better)
From db852c55b93f5eb6718e27cd8592486aa0cea58d Mon Sep 17 00:00:00 2001
From: Travis Fischer
Date: Sun, 6 Oct 2024 05:30:04 -0400
Subject: [PATCH 45/45] feat: PR feedback
---
.github/funding.yml | 1 -
src/cellxBench.ts | 19 +++++++++++--------
src/dynamicBench.ts | 2 +-
src/index.ts | 8 ++------
src/kairo/broad.ts | 4 ++--
src/kairo/deep.ts | 4 ++--
src/kairo/diamond.ts | 4 ++--
src/kairo/repeated.ts | 4 ++--
src/kairo/triangle.ts | 4 ++--
src/kairo/unstable.ts | 5 +++--
10 files changed, 27 insertions(+), 28 deletions(-)
delete mode 100644 .github/funding.yml
diff --git a/.github/funding.yml b/.github/funding.yml
deleted file mode 100644
index 9377c23..0000000
--- a/.github/funding.yml
+++ /dev/null
@@ -1 +0,0 @@
-github: [transitive-bullshit]
diff --git a/src/cellxBench.ts b/src/cellxBench.ts
index d8b0f29..4d175a5 100644
--- a/src/cellxBench.ts
+++ b/src/cellxBench.ts
@@ -95,14 +95,17 @@ export const cellxbench = (framework: ReactiveFramework) => {
[-3, -6, -2, 2],
[-2, -4, 2, 3],
],
- 2500: [
- [-3, -6, -2, 2],
- [-2, -4, 2, 3],
- ],
- 5000: [
- [2, 4, -1, -6],
- [-2, 1, -4, -4],
- ],
+ // TODO: https://github.com/milomg/js-reactivity-benchmark/pull/13#issuecomment-2395253701
+ // @see https://github.com/mobxjs/mobx/issues/3926
+ // @see https://github.com/sveltejs/svelte/discussions/13277
+ // 2500: [
+ // [-3, -6, -2, 2],
+ // [-2, -4, 2, 3],
+ // ],
+ // 5000: [
+ // [2, 4, -1, -6],
+ // [-2, 1, -4, -4],
+ // ],
};
const results: Record = {};
diff --git a/src/dynamicBench.ts b/src/dynamicBench.ts
index 91a364a..3a7c1ff 100644
--- a/src/dynamicBench.ts
+++ b/src/dynamicBench.ts
@@ -10,7 +10,7 @@ import { fastestTest } from "./util/benchRepeat";
*/
export async function dynamicBench(
frameworkTest: FrameworkInfo,
- testRepeats = 1
+ testRepeats = 5
): Promise {
const { framework } = frameworkTest;
for (const config of perfTests) {
diff --git a/src/index.ts b/src/index.ts
index 46baa74..d0542af 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,5 +1,5 @@
import { dynamicBench } from "./dynamicBench";
-// import { cellxbench } from "./cellxBench";
+import { cellxbench } from "./cellxBench";
import { sbench } from "./sBench";
import { frameworkInfo } from "./config";
import { logPerfResult, perfReportHeaders } from "./util/perfLogging";
@@ -8,7 +8,6 @@ import { kairoBench } from "./kairoBench";
async function main() {
logPerfResult(perfReportHeaders());
- (globalThis as any).__DEV__ = true;
for (const frameworkTest of frameworkInfo) {
const { framework } = frameworkTest;
@@ -17,10 +16,7 @@ async function main() {
await molBench(framework);
sbench(framework);
- // MobX, Valtio, and Svelte fail this test currently, so disabling it for now.
- // @see https://github.com/mobxjs/mobx/issues/3926
- // @see https://github.com/sveltejs/svelte/discussions/13277
- // cellxbench(framework);
+ cellxbench(framework);
await dynamicBench(frameworkTest);
diff --git a/src/kairo/broad.ts b/src/kairo/broad.ts
index 6a84860..4507289 100644
--- a/src/kairo/broad.ts
+++ b/src/kairo/broad.ts
@@ -24,7 +24,7 @@ export function broadPropagation(bridge: ReactiveFramework) {
bridge.withBatch(() => {
head.write(1);
});
- // const atleast = 50 * 50;
+ const atleast = 50 * 50;
callCounter.count = 0;
for (let i = 0; i < 50; i++) {
bridge.withBatch(() => {
@@ -32,6 +32,6 @@ export function broadPropagation(bridge: ReactiveFramework) {
});
console.assert(last.read() === i + 50);
}
- // console.assert(callCounter.count === atleast, callCounter.count);
+ console.assert(callCounter.count === atleast, callCounter.count);
};
}
diff --git a/src/kairo/deep.ts b/src/kairo/deep.ts
index eb05a08..eef6f8e 100644
--- a/src/kairo/deep.ts
+++ b/src/kairo/deep.ts
@@ -25,7 +25,7 @@ export function deepPropagation(bridge: ReactiveFramework) {
bridge.withBatch(() => {
head.write(1);
});
- // const atleast = iter;
+ const atleast = iter;
callCounter.count = 0;
for (let i = 0; i < iter; i++) {
bridge.withBatch(() => {
@@ -34,6 +34,6 @@ export function deepPropagation(bridge: ReactiveFramework) {
console.assert(current.read() === len + i);
}
- // console.assert(callCounter.count === atleast);
+ console.assert(callCounter.count === atleast);
};
}
diff --git a/src/kairo/diamond.ts b/src/kairo/diamond.ts
index 740f1c3..b98fba1 100644
--- a/src/kairo/diamond.ts
+++ b/src/kairo/diamond.ts
@@ -27,7 +27,7 @@ export function diamond(bridge: ReactiveFramework) {
head.write(1);
});
console.assert(sum.read() === 2 * width);
- // const atleast = 500;
+ const atleast = 500;
callCounter.count = 0;
for (let i = 0; i < 500; i++) {
bridge.withBatch(() => {
@@ -35,6 +35,6 @@ export function diamond(bridge: ReactiveFramework) {
});
console.assert(sum.read() === (i + 1) * width);
}
- // console.assert(callCounter.count === atleast);
+ console.assert(callCounter.count === atleast);
};
}
diff --git a/src/kairo/repeated.ts b/src/kairo/repeated.ts
index 2258dd8..c3313b5 100644
--- a/src/kairo/repeated.ts
+++ b/src/kairo/repeated.ts
@@ -26,7 +26,7 @@ export function repeatedObservers(bridge: ReactiveFramework) {
head.write(1);
});
console.assert(current.read() === size);
- // const atleast = 100;
+ const atleast = 100;
callCounter.count = 0;
for (let i = 0; i < 100; i++) {
bridge.withBatch(() => {
@@ -34,6 +34,6 @@ export function repeatedObservers(bridge: ReactiveFramework) {
});
console.assert(current.read() === i * size);
}
- // console.assert(callCounter.count === atleast);
+ console.assert(callCounter.count === atleast);
};
}
diff --git a/src/kairo/triangle.ts b/src/kairo/triangle.ts
index 24a94b2..b472506 100644
--- a/src/kairo/triangle.ts
+++ b/src/kairo/triangle.ts
@@ -30,7 +30,7 @@ export function triangle(bridge: ReactiveFramework) {
head.write(1);
});
console.assert(sum.read() === constant);
- // const atleast = 100;
+ const atleast = 100;
callCounter.count = 0;
for (let i = 0; i < 100; i++) {
bridge.withBatch(() => {
@@ -38,7 +38,7 @@ export function triangle(bridge: ReactiveFramework) {
});
console.assert(sum.read() === constant - width + i * width);
}
- // console.assert(callCounter.count === atleast);
+ console.assert(callCounter.count === atleast);
};
}
diff --git a/src/kairo/unstable.ts b/src/kairo/unstable.ts
index e70ae16..ca8982f 100644
--- a/src/kairo/unstable.ts
+++ b/src/kairo/unstable.ts
@@ -24,14 +24,15 @@ export function unstable(bridge: ReactiveFramework) {
head.write(1);
});
console.assert(current.read() === 40);
- // const atleast = 100;
+ const atleast = 100;
callCounter.count = 0;
for (let i = 0; i < 100; i++) {
bridge.withBatch(() => {
head.write(i);
});
+ // TODO: this assertion is failing for Preact Signals (and possibly other frameworks)
// console.assert(current.read() === i % 2 ? i * 2 * 10 : i * -10);
}
- // console.assert(callCounter.count === atleast);
+ console.assert(callCounter.count === atleast);
};
}