mirror of https://github.com/sveltejs/svelte
commit
7ce419bb4c
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"svelte": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: remove correct event listener from document
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'svelte': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: make more types from `svelte/compiler` public
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'svelte': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: support contenteditable binding undefined fallback
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"svelte": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: correctly serialize object assignment expressions
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"svelte": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: robustify migration script around indentation and comments
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'svelte': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
feat: more accurate `render`/`mount`/`hydrate` options
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"svelte": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: wait a microtask for await blocks to reduce UI churn
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"svelte": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: ensure state update expressions are serialised correctly
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"svelte": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: ensure element size bindings don't unsubscribe multiple times from the resize observer
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"svelte": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: repair each block length even without an else
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'svelte': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
breaking: prevent usage of arguments keyword in certain places
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"svelte": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: prevent misidentification of bindings as delegatable event handlers if used outside event attribute
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"svelte": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix(types): export CompileResult and Warning
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'svelte': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: ensure element dir properties persist with text changes
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"svelte": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
breaking: bump dts-buddy
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"svelte": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: preserve current input values when removing defaults
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"svelte": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: better binding interop between runes/non-runes components
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'svelte': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: disallow accessing internal Svelte props
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"svelte": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: throw compilation error for malformed snippets
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'svelte': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: make media bindings more robust
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"svelte": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: allow slot attribute inside snippets
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'svelte': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
feat: allow `let props = $props()` and optimize prop read access
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"svelte": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
chore: remove anchor node from each block items
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"svelte": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
chore: improve runtime performance of capturing reactive signals
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"svelte": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: prevent `a11y_label_has_associated_control` false positive for component or render tag in `<label>`
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"svelte": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: allow multiple optional parameters with defaults in snippets
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"svelte": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: improve await block behaviour in non-runes mode
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"svelte": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
feat: improve type arguments for Snippet and $bindable
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"svelte": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: remove document event listeners on unmount
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"svelte": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: preserve component function context for nested components
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"svelte": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: improve select handling of dynamic value with placeholders
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'svelte': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: deconflict multiple snippets of the same name
|
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"search.exclude": {
|
"search.exclude": {
|
||||||
"sites/svelte-5-preview/static/*": true
|
"sites/svelte-5-preview/static/*": true
|
||||||
}
|
},
|
||||||
|
"typescript.tsdk": "node_modules/typescript/lib"
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,58 @@
|
|||||||
|
import {
|
||||||
|
kairo_avoidable_owned,
|
||||||
|
kairo_avoidable_unowned
|
||||||
|
} from './benchmarks/kairo/kairo_avoidable.js';
|
||||||
|
import { kairo_broad_owned, kairo_broad_unowned } from './benchmarks/kairo/kairo_broad.js';
|
||||||
|
import { kairo_deep_owned, kairo_deep_unowned } from './benchmarks/kairo/kairo_deep.js';
|
||||||
|
import { kairo_diamond_owned, kairo_diamond_unowned } from './benchmarks/kairo/kairo_diamond.js';
|
||||||
|
import { kairo_mux_unowned, kairo_mux_owned } from './benchmarks/kairo/kairo_mux.js';
|
||||||
|
import { kairo_repeated_unowned, kairo_repeated_owned } from './benchmarks/kairo/kairo_repeated.js';
|
||||||
|
import { kairo_triangle_owned, kairo_triangle_unowned } from './benchmarks/kairo/kairo_triangle.js';
|
||||||
|
import { kairo_unstable_owned, kairo_unstable_unowned } from './benchmarks/kairo/kairo_unstable.js';
|
||||||
|
import { mol_bench_owned, mol_bench_unowned } from './benchmarks/mol_bench.js';
|
||||||
|
import {
|
||||||
|
sbench_create_0to1,
|
||||||
|
sbench_create_1000to1,
|
||||||
|
sbench_create_1to1,
|
||||||
|
sbench_create_1to1000,
|
||||||
|
sbench_create_1to2,
|
||||||
|
sbench_create_1to4,
|
||||||
|
sbench_create_1to8,
|
||||||
|
sbench_create_2to1,
|
||||||
|
sbench_create_4to1,
|
||||||
|
sbench_create_signals
|
||||||
|
} from './benchmarks/sbench.js';
|
||||||
|
|
||||||
|
// This benchmark has been adapted from the js-reactivity-benchmark (https://github.com/milomg/js-reactivity-benchmark)
|
||||||
|
// Not all tests are the same, and many parts have been tweaked to capture different data.
|
||||||
|
|
||||||
|
export const benchmarks = [
|
||||||
|
sbench_create_signals,
|
||||||
|
sbench_create_0to1,
|
||||||
|
sbench_create_1to1,
|
||||||
|
sbench_create_2to1,
|
||||||
|
sbench_create_4to1,
|
||||||
|
sbench_create_1000to1,
|
||||||
|
sbench_create_1to2,
|
||||||
|
sbench_create_1to4,
|
||||||
|
sbench_create_1to8,
|
||||||
|
sbench_create_1to1000,
|
||||||
|
kairo_avoidable_owned,
|
||||||
|
kairo_avoidable_unowned,
|
||||||
|
kairo_broad_owned,
|
||||||
|
kairo_broad_unowned,
|
||||||
|
kairo_deep_owned,
|
||||||
|
kairo_deep_unowned,
|
||||||
|
kairo_diamond_owned,
|
||||||
|
kairo_diamond_unowned,
|
||||||
|
kairo_triangle_owned,
|
||||||
|
kairo_triangle_unowned,
|
||||||
|
kairo_mux_owned,
|
||||||
|
kairo_mux_unowned,
|
||||||
|
kairo_repeated_owned,
|
||||||
|
kairo_repeated_unowned,
|
||||||
|
kairo_unstable_owned,
|
||||||
|
kairo_unstable_unowned,
|
||||||
|
mol_bench_owned,
|
||||||
|
mol_bench_unowned
|
||||||
|
];
|
@ -0,0 +1,91 @@
|
|||||||
|
import { assert, fastest_test } from '../../utils.js';
|
||||||
|
import * as $ from '../../../packages/svelte/src/internal/client/index.js';
|
||||||
|
import { busy } from './util.js';
|
||||||
|
|
||||||
|
function setup() {
|
||||||
|
let head = $.source(0);
|
||||||
|
let computed1 = $.derived(() => $.get(head));
|
||||||
|
let computed2 = $.derived(() => ($.get(computed1), 0));
|
||||||
|
let computed3 = $.derived(() => (busy(), $.get(computed2) + 1)); // heavy computation
|
||||||
|
let computed4 = $.derived(() => $.get(computed3) + 2);
|
||||||
|
let computed5 = $.derived(() => $.get(computed4) + 3);
|
||||||
|
|
||||||
|
const destroy = $.effect_root(() => {
|
||||||
|
$.render_effect(() => {
|
||||||
|
$.get(computed5);
|
||||||
|
busy(); // heavy side effect
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
destroy,
|
||||||
|
run() {
|
||||||
|
$.flush_sync(() => {
|
||||||
|
$.set(head, 1);
|
||||||
|
});
|
||||||
|
assert($.get(computed5) === 6);
|
||||||
|
for (let i = 0; i < 1000; i++) {
|
||||||
|
$.flush_sync(() => {
|
||||||
|
$.set(head, i);
|
||||||
|
});
|
||||||
|
assert($.get(computed5) === 6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function kairo_avoidable_unowned() {
|
||||||
|
// Do 10 loops to warm up JIT
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
const { run, destroy } = setup();
|
||||||
|
run();
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
const { run, destroy } = setup();
|
||||||
|
|
||||||
|
const { timing } = await fastest_test(10, () => {
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
run();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
destroy();
|
||||||
|
|
||||||
|
return {
|
||||||
|
benchmark: 'kairo_avoidable_unowned',
|
||||||
|
time: timing.time.toFixed(2),
|
||||||
|
gc_time: timing.gc_time.toFixed(2)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function kairo_avoidable_owned() {
|
||||||
|
let run, destroy;
|
||||||
|
|
||||||
|
const destroy_owned = $.effect_root(() => {
|
||||||
|
// Do 10 loops to warm up JIT
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
const { run, destroy } = setup();
|
||||||
|
run();
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
({ run, destroy } = setup());
|
||||||
|
});
|
||||||
|
|
||||||
|
const { timing } = await fastest_test(10, () => {
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
run();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
destroy();
|
||||||
|
destroy_owned();
|
||||||
|
|
||||||
|
return {
|
||||||
|
benchmark: 'kairo_avoidable_owned',
|
||||||
|
time: timing.time.toFixed(2),
|
||||||
|
gc_time: timing.gc_time.toFixed(2)
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,97 @@
|
|||||||
|
import { assert, fastest_test } from '../../utils.js';
|
||||||
|
import * as $ from '../../../packages/svelte/src/internal/client/index.js';
|
||||||
|
|
||||||
|
function setup() {
|
||||||
|
let head = $.source(0);
|
||||||
|
let last = head;
|
||||||
|
let counter = 0;
|
||||||
|
|
||||||
|
const destroy = $.effect_root(() => {
|
||||||
|
for (let i = 0; i < 50; i++) {
|
||||||
|
let current = $.derived(() => {
|
||||||
|
return $.get(head) + i;
|
||||||
|
});
|
||||||
|
let current2 = $.derived(() => {
|
||||||
|
return $.get(current) + 1;
|
||||||
|
});
|
||||||
|
$.render_effect(() => {
|
||||||
|
$.get(current2);
|
||||||
|
counter++;
|
||||||
|
});
|
||||||
|
last = current2;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
destroy,
|
||||||
|
run() {
|
||||||
|
$.flush_sync(() => {
|
||||||
|
$.set(head, 1);
|
||||||
|
});
|
||||||
|
counter = 0;
|
||||||
|
for (let i = 0; i < 50; i++) {
|
||||||
|
$.flush_sync(() => {
|
||||||
|
$.set(head, i);
|
||||||
|
});
|
||||||
|
assert($.get(last) === i + 50);
|
||||||
|
}
|
||||||
|
assert(counter === 50 * 50);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function kairo_broad_unowned() {
|
||||||
|
// Do 10 loops to warm up JIT
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
const { run, destroy } = setup();
|
||||||
|
run();
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
const { run, destroy } = setup();
|
||||||
|
|
||||||
|
const { timing } = await fastest_test(10, () => {
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
run();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
destroy();
|
||||||
|
|
||||||
|
return {
|
||||||
|
benchmark: 'kairo_broad_unowned',
|
||||||
|
time: timing.time.toFixed(2),
|
||||||
|
gc_time: timing.gc_time.toFixed(2)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function kairo_broad_owned() {
|
||||||
|
let run, destroy;
|
||||||
|
|
||||||
|
const destroy_owned = $.effect_root(() => {
|
||||||
|
// Do 10 loops to warm up JIT
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
const { run, destroy } = setup();
|
||||||
|
run();
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
({ run, destroy } = setup());
|
||||||
|
});
|
||||||
|
|
||||||
|
const { timing } = await fastest_test(10, () => {
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
run();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
destroy();
|
||||||
|
destroy_owned();
|
||||||
|
|
||||||
|
return {
|
||||||
|
benchmark: 'kairo_broad_owned',
|
||||||
|
time: timing.time.toFixed(2),
|
||||||
|
gc_time: timing.gc_time.toFixed(2)
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,97 @@
|
|||||||
|
import { assert, fastest_test } from '../../utils.js';
|
||||||
|
import * as $ from '../../../packages/svelte/src/internal/client/index.js';
|
||||||
|
|
||||||
|
let len = 50;
|
||||||
|
const iter = 50;
|
||||||
|
|
||||||
|
function setup() {
|
||||||
|
let head = $.source(0);
|
||||||
|
let current = head;
|
||||||
|
for (let i = 0; i < len; i++) {
|
||||||
|
let c = current;
|
||||||
|
current = $.derived(() => {
|
||||||
|
return $.get(c) + 1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let counter = 0;
|
||||||
|
|
||||||
|
const destroy = $.effect_root(() => {
|
||||||
|
$.render_effect(() => {
|
||||||
|
$.get(current);
|
||||||
|
counter++;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
destroy,
|
||||||
|
run() {
|
||||||
|
$.flush_sync(() => {
|
||||||
|
$.set(head, 1);
|
||||||
|
});
|
||||||
|
counter = 0;
|
||||||
|
for (let i = 0; i < iter; i++) {
|
||||||
|
$.flush_sync(() => {
|
||||||
|
$.set(head, i);
|
||||||
|
});
|
||||||
|
assert($.get(current) === len + i);
|
||||||
|
}
|
||||||
|
assert(counter === iter);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function kairo_deep_unowned() {
|
||||||
|
// Do 10 loops to warm up JIT
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
const { run, destroy } = setup();
|
||||||
|
run();
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
const { run, destroy } = setup();
|
||||||
|
|
||||||
|
const { timing } = await fastest_test(10, () => {
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
run();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
destroy();
|
||||||
|
|
||||||
|
return {
|
||||||
|
benchmark: 'kairo_deep_unowned',
|
||||||
|
time: timing.time.toFixed(2),
|
||||||
|
gc_time: timing.gc_time.toFixed(2)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function kairo_deep_owned() {
|
||||||
|
let run, destroy;
|
||||||
|
|
||||||
|
const destroy_owned = $.effect_root(() => {
|
||||||
|
// Do 10 loops to warm up JIT
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
const { run, destroy } = setup();
|
||||||
|
run();
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
({ run, destroy } = setup());
|
||||||
|
});
|
||||||
|
|
||||||
|
const { timing } = await fastest_test(10, () => {
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
run();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
destroy();
|
||||||
|
destroy_owned();
|
||||||
|
|
||||||
|
return {
|
||||||
|
benchmark: 'kairo_deep_owned',
|
||||||
|
time: timing.time.toFixed(2),
|
||||||
|
gc_time: timing.gc_time.toFixed(2)
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,101 @@
|
|||||||
|
import { assert, fastest_test } from '../../utils.js';
|
||||||
|
import * as $ from '../../../packages/svelte/src/internal/client/index.js';
|
||||||
|
|
||||||
|
let width = 5;
|
||||||
|
|
||||||
|
function setup() {
|
||||||
|
let head = $.source(0);
|
||||||
|
let current = [];
|
||||||
|
for (let i = 0; i < width; i++) {
|
||||||
|
current.push(
|
||||||
|
$.derived(() => {
|
||||||
|
return $.get(head) + 1;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let sum = $.derived(() => {
|
||||||
|
return current.map((x) => $.get(x)).reduce((a, b) => a + b, 0);
|
||||||
|
});
|
||||||
|
let counter = 0;
|
||||||
|
|
||||||
|
const destroy = $.effect_root(() => {
|
||||||
|
$.render_effect(() => {
|
||||||
|
$.get(sum);
|
||||||
|
counter++;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
destroy,
|
||||||
|
run() {
|
||||||
|
$.flush_sync(() => {
|
||||||
|
$.set(head, 1);
|
||||||
|
});
|
||||||
|
assert($.get(sum) === 2 * width);
|
||||||
|
counter = 0;
|
||||||
|
for (let i = 0; i < 500; i++) {
|
||||||
|
$.flush_sync(() => {
|
||||||
|
$.set(head, i);
|
||||||
|
});
|
||||||
|
assert($.get(sum) === (i + 1) * width);
|
||||||
|
}
|
||||||
|
assert(counter === 500);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function kairo_diamond_unowned() {
|
||||||
|
// Do 10 loops to warm up JIT
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
const { run, destroy } = setup();
|
||||||
|
run();
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
const { run, destroy } = setup();
|
||||||
|
|
||||||
|
const { timing } = await fastest_test(10, () => {
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
run();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
destroy();
|
||||||
|
|
||||||
|
return {
|
||||||
|
benchmark: 'kairo_diamond_unowned',
|
||||||
|
time: timing.time.toFixed(2),
|
||||||
|
gc_time: timing.gc_time.toFixed(2)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function kairo_diamond_owned() {
|
||||||
|
let run, destroy;
|
||||||
|
|
||||||
|
const destroy_owned = $.effect_root(() => {
|
||||||
|
// Do 10 loops to warm up JIT
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
const { run, destroy } = setup();
|
||||||
|
run();
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
({ run, destroy } = setup());
|
||||||
|
});
|
||||||
|
|
||||||
|
const { timing } = await fastest_test(10, () => {
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
run();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
destroy();
|
||||||
|
destroy_owned();
|
||||||
|
|
||||||
|
return {
|
||||||
|
benchmark: 'kairo_diamond_owned',
|
||||||
|
time: timing.time.toFixed(2),
|
||||||
|
gc_time: timing.gc_time.toFixed(2)
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,94 @@
|
|||||||
|
import { assert, fastest_test } from '../../utils.js';
|
||||||
|
import * as $ from '../../../packages/svelte/src/internal/client/index.js';
|
||||||
|
|
||||||
|
function setup() {
|
||||||
|
let heads = new Array(100).fill(null).map((_) => $.source(0));
|
||||||
|
const mux = $.derived(() => {
|
||||||
|
return Object.fromEntries(heads.map((h) => $.get(h)).entries());
|
||||||
|
});
|
||||||
|
const splited = heads
|
||||||
|
.map((_, index) => $.derived(() => $.get(mux)[index]))
|
||||||
|
.map((x) => $.derived(() => $.get(x) + 1));
|
||||||
|
|
||||||
|
const destroy = $.effect_root(() => {
|
||||||
|
splited.forEach((x) => {
|
||||||
|
$.render_effect(() => {
|
||||||
|
$.get(x);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
destroy,
|
||||||
|
run() {
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
$.flush_sync(() => {
|
||||||
|
$.set(heads[i], i);
|
||||||
|
});
|
||||||
|
assert($.get(splited[i]) === i + 1);
|
||||||
|
}
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
$.flush_sync(() => {
|
||||||
|
$.set(heads[i], i * 2);
|
||||||
|
});
|
||||||
|
assert($.get(splited[i]) === i * 2 + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function kairo_mux_unowned() {
|
||||||
|
// Do 10 loops to warm up JIT
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
const { run, destroy } = setup();
|
||||||
|
run();
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
const { run, destroy } = setup();
|
||||||
|
|
||||||
|
const { timing } = await fastest_test(10, () => {
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
run();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
destroy();
|
||||||
|
|
||||||
|
return {
|
||||||
|
benchmark: 'kairo_mux_unowned',
|
||||||
|
time: timing.time.toFixed(2),
|
||||||
|
gc_time: timing.gc_time.toFixed(2)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function kairo_mux_owned() {
|
||||||
|
let run, destroy;
|
||||||
|
|
||||||
|
const destroy_owned = $.effect_root(() => {
|
||||||
|
// Do 10 loops to warm up JIT
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
const { run, destroy } = setup();
|
||||||
|
run();
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
({ run, destroy } = setup());
|
||||||
|
});
|
||||||
|
|
||||||
|
const { timing } = await fastest_test(10, () => {
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
run();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
destroy();
|
||||||
|
destroy_owned();
|
||||||
|
|
||||||
|
return {
|
||||||
|
benchmark: 'kairo_mux_owned',
|
||||||
|
time: timing.time.toFixed(2),
|
||||||
|
gc_time: timing.gc_time.toFixed(2)
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,98 @@
|
|||||||
|
import { assert, fastest_test } from '../../utils.js';
|
||||||
|
import * as $ from '../../../packages/svelte/src/internal/client/index.js';
|
||||||
|
|
||||||
|
let size = 30;
|
||||||
|
|
||||||
|
function setup() {
|
||||||
|
let head = $.source(0);
|
||||||
|
let current = $.derived(() => {
|
||||||
|
let result = 0;
|
||||||
|
for (let i = 0; i < size; i++) {
|
||||||
|
result += $.get(head);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
|
||||||
|
let counter = 0;
|
||||||
|
|
||||||
|
const destroy = $.effect_root(() => {
|
||||||
|
$.render_effect(() => {
|
||||||
|
$.get(current);
|
||||||
|
counter++;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
destroy,
|
||||||
|
run() {
|
||||||
|
$.flush_sync(() => {
|
||||||
|
$.set(head, 1);
|
||||||
|
});
|
||||||
|
assert($.get(current) === size);
|
||||||
|
counter = 0;
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
$.flush_sync(() => {
|
||||||
|
$.set(head, i);
|
||||||
|
});
|
||||||
|
assert($.get(current) === i * size);
|
||||||
|
}
|
||||||
|
assert(counter === 100);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function kairo_repeated_unowned() {
|
||||||
|
// Do 10 loops to warm up JIT
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
const { run, destroy } = setup();
|
||||||
|
run();
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
const { run, destroy } = setup();
|
||||||
|
|
||||||
|
const { timing } = await fastest_test(10, () => {
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
run();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
destroy();
|
||||||
|
|
||||||
|
return {
|
||||||
|
benchmark: 'kairo_repeated_unowned',
|
||||||
|
time: timing.time.toFixed(2),
|
||||||
|
gc_time: timing.gc_time.toFixed(2)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function kairo_repeated_owned() {
|
||||||
|
let run, destroy;
|
||||||
|
|
||||||
|
const destroy_owned = $.effect_root(() => {
|
||||||
|
// Do 10 loops to warm up JIT
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
const { run, destroy } = setup();
|
||||||
|
run();
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
({ run, destroy } = setup());
|
||||||
|
});
|
||||||
|
|
||||||
|
const { timing } = await fastest_test(10, () => {
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
run();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
destroy();
|
||||||
|
destroy_owned();
|
||||||
|
|
||||||
|
return {
|
||||||
|
benchmark: 'kairo_repeated_owned',
|
||||||
|
time: timing.time.toFixed(2),
|
||||||
|
gc_time: timing.gc_time.toFixed(2)
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,111 @@
|
|||||||
|
import { assert, fastest_test } from '../../utils.js';
|
||||||
|
import * as $ from '../../../packages/svelte/src/internal/client/index.js';
|
||||||
|
|
||||||
|
let width = 10;
|
||||||
|
|
||||||
|
function count(number) {
|
||||||
|
return new Array(number)
|
||||||
|
.fill(0)
|
||||||
|
.map((_, i) => i + 1)
|
||||||
|
.reduce((x, y) => x + y, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setup() {
|
||||||
|
let head = $.source(0);
|
||||||
|
let current = head;
|
||||||
|
let list = [];
|
||||||
|
for (let i = 0; i < width; i++) {
|
||||||
|
let c = current;
|
||||||
|
list.push(current);
|
||||||
|
current = $.derived(() => {
|
||||||
|
return $.get(c) + 1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let sum = $.derived(() => {
|
||||||
|
return list.map((x) => $.get(x)).reduce((a, b) => a + b, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
let counter = 0;
|
||||||
|
|
||||||
|
const destroy = $.effect_root(() => {
|
||||||
|
$.render_effect(() => {
|
||||||
|
$.get(sum);
|
||||||
|
counter++;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
destroy,
|
||||||
|
run() {
|
||||||
|
const constant = count(width);
|
||||||
|
$.flush_sync(() => {
|
||||||
|
$.set(head, 1);
|
||||||
|
});
|
||||||
|
assert($.get(sum) === constant);
|
||||||
|
counter = 0;
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
$.flush_sync(() => {
|
||||||
|
$.set(head, i);
|
||||||
|
});
|
||||||
|
assert($.get(sum) === constant - width + i * width);
|
||||||
|
}
|
||||||
|
assert(counter === 100);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function kairo_triangle_unowned() {
|
||||||
|
// Do 10 loops to warm up JIT
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
const { run, destroy } = setup();
|
||||||
|
run();
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
const { run, destroy } = setup();
|
||||||
|
|
||||||
|
const { timing } = await fastest_test(10, () => {
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
run();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
destroy();
|
||||||
|
|
||||||
|
return {
|
||||||
|
benchmark: 'kairo_triangle_unowned',
|
||||||
|
time: timing.time.toFixed(2),
|
||||||
|
gc_time: timing.gc_time.toFixed(2)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function kairo_triangle_owned() {
|
||||||
|
let run, destroy;
|
||||||
|
|
||||||
|
const destroy_owned = $.effect_root(() => {
|
||||||
|
// Do 10 loops to warm up JIT
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
const { run, destroy } = setup();
|
||||||
|
run();
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
({ run, destroy } = setup());
|
||||||
|
});
|
||||||
|
|
||||||
|
const { timing } = await fastest_test(10, () => {
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
run();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
destroy();
|
||||||
|
destroy_owned();
|
||||||
|
|
||||||
|
return {
|
||||||
|
benchmark: 'kairo_triangle_owned',
|
||||||
|
time: timing.time.toFixed(2),
|
||||||
|
gc_time: timing.gc_time.toFixed(2)
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,97 @@
|
|||||||
|
import { assert, fastest_test } from '../../utils.js';
|
||||||
|
import * as $ from '../../../packages/svelte/src/internal/client/index.js';
|
||||||
|
|
||||||
|
function setup() {
|
||||||
|
let head = $.source(0);
|
||||||
|
const double = $.derived(() => $.get(head) * 2);
|
||||||
|
const inverse = $.derived(() => -$.get(head));
|
||||||
|
let current = $.derived(() => {
|
||||||
|
let result = 0;
|
||||||
|
for (let i = 0; i < 20; i++) {
|
||||||
|
result += $.get(head) % 2 ? $.get(double) : $.get(inverse);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
|
||||||
|
let counter = 0;
|
||||||
|
|
||||||
|
const destroy = $.effect_root(() => {
|
||||||
|
$.render_effect(() => {
|
||||||
|
$.get(current);
|
||||||
|
counter++;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
destroy,
|
||||||
|
run() {
|
||||||
|
$.flush_sync(() => {
|
||||||
|
$.set(head, 1);
|
||||||
|
});
|
||||||
|
assert($.get(current) === 40);
|
||||||
|
counter = 0;
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
$.flush_sync(() => {
|
||||||
|
$.set(head, i);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
assert(counter === 100);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function kairo_unstable_unowned() {
|
||||||
|
// Do 10 loops to warm up JIT
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
const { run, destroy } = setup();
|
||||||
|
run();
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
const { run, destroy } = setup();
|
||||||
|
|
||||||
|
const { timing } = await fastest_test(10, () => {
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
run();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
destroy();
|
||||||
|
|
||||||
|
return {
|
||||||
|
benchmark: 'kairo_unstable_unowned',
|
||||||
|
time: timing.time.toFixed(2),
|
||||||
|
gc_time: timing.gc_time.toFixed(2)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function kairo_unstable_owned() {
|
||||||
|
let run, destroy;
|
||||||
|
|
||||||
|
const destroy_owned = $.effect_root(() => {
|
||||||
|
// Do 10 loops to warm up JIT
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
const { run, destroy } = setup();
|
||||||
|
run();
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
({ run, destroy } = setup());
|
||||||
|
});
|
||||||
|
|
||||||
|
const { timing } = await fastest_test(10, () => {
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
run();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
destroy();
|
||||||
|
destroy_owned();
|
||||||
|
|
||||||
|
return {
|
||||||
|
benchmark: 'kairo_unstable_owned',
|
||||||
|
time: timing.time.toFixed(2),
|
||||||
|
gc_time: timing.gc_time.toFixed(2)
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
export function busy() {
|
||||||
|
let a = 0;
|
||||||
|
for (let i = 0; i < 1_00; i++) {
|
||||||
|
a++;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,121 @@
|
|||||||
|
import { assert, fastest_test } from '../utils.js';
|
||||||
|
import * as $ from '../../packages/svelte/src/internal/client/index.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number} n
|
||||||
|
*/
|
||||||
|
function fib(n) {
|
||||||
|
if (n < 2) return 1;
|
||||||
|
return fib(n - 1) + fib(n - 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number} n
|
||||||
|
*/
|
||||||
|
function hard(n) {
|
||||||
|
return n + fib(16);
|
||||||
|
}
|
||||||
|
|
||||||
|
const numbers = Array.from({ length: 5 }, (_, i) => i);
|
||||||
|
|
||||||
|
function setup() {
|
||||||
|
let res = [];
|
||||||
|
const A = $.source(0);
|
||||||
|
const B = $.source(0);
|
||||||
|
const C = $.derived(() => ($.get(A) % 2) + ($.get(B) % 2));
|
||||||
|
const D = $.derived(() => numbers.map((i) => i + ($.get(A) % 2) - ($.get(B) % 2)));
|
||||||
|
D.equals = function (/** @type {number[]} */ l) {
|
||||||
|
var r = this.v;
|
||||||
|
return r !== null && l.length === r.length && l.every((v, i) => v === r[i]);
|
||||||
|
};
|
||||||
|
const E = $.derived(() => hard($.get(C) + $.get(A) + $.get(D)[0]));
|
||||||
|
const F = $.derived(() => hard($.get(D)[0] && $.get(B)));
|
||||||
|
const G = $.derived(() => $.get(C) + ($.get(C) || $.get(E) % 2) + $.get(D)[0] + $.get(F));
|
||||||
|
|
||||||
|
const destroy = $.effect_root(() => {
|
||||||
|
$.render_effect(() => {
|
||||||
|
res.push(hard($.get(G)));
|
||||||
|
});
|
||||||
|
$.render_effect(() => {
|
||||||
|
res.push($.get(G));
|
||||||
|
});
|
||||||
|
$.render_effect(() => {
|
||||||
|
res.push(hard($.get(F)));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
destroy,
|
||||||
|
/**
|
||||||
|
* @param {number} i
|
||||||
|
*/
|
||||||
|
run(i) {
|
||||||
|
res.length = 0;
|
||||||
|
$.flush_sync(() => {
|
||||||
|
$.set(B, 1);
|
||||||
|
$.set(A, 1 + i * 2);
|
||||||
|
});
|
||||||
|
$.flush_sync(() => {
|
||||||
|
$.set(A, 2 + i * 2);
|
||||||
|
$.set(B, 2);
|
||||||
|
});
|
||||||
|
assert(res[0] === 3198 && res[1] === 1601 && res[2] === 3195 && res[3] === 1598);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function mol_bench_owned() {
|
||||||
|
let run, destroy;
|
||||||
|
|
||||||
|
const destroy_owned = $.effect_root(() => {
|
||||||
|
// Do 10 loops to warm up JIT
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
const { run, destroy } = setup();
|
||||||
|
run(0);
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
({ run, destroy } = setup());
|
||||||
|
});
|
||||||
|
|
||||||
|
const { timing } = await fastest_test(10, () => {
|
||||||
|
for (let i = 0; i < 1e4; i++) {
|
||||||
|
run(i);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
destroy();
|
||||||
|
destroy_owned();
|
||||||
|
|
||||||
|
return {
|
||||||
|
benchmark: 'mol_bench_owned',
|
||||||
|
time: timing.time.toFixed(2),
|
||||||
|
gc_time: timing.gc_time.toFixed(2)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function mol_bench_unowned() {
|
||||||
|
// Do 10 loops to warm up JIT
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
const { run, destroy } = setup();
|
||||||
|
run(0);
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
const { run, destroy } = setup();
|
||||||
|
|
||||||
|
const { timing } = await fastest_test(10, () => {
|
||||||
|
for (let i = 0; i < 1e4; i++) {
|
||||||
|
run(i);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
destroy();
|
||||||
|
|
||||||
|
return {
|
||||||
|
benchmark: 'mol_bench_unowned',
|
||||||
|
time: timing.time.toFixed(2),
|
||||||
|
gc_time: timing.gc_time.toFixed(2)
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,339 @@
|
|||||||
|
import { fastest_test } from '../utils.js';
|
||||||
|
import * as $ from '../../packages/svelte/src/internal/client/index.js';
|
||||||
|
|
||||||
|
const COUNT = 1e5;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number} n
|
||||||
|
* @param {any[]} sources
|
||||||
|
*/
|
||||||
|
function create_data_signals(n, sources) {
|
||||||
|
for (let i = 0; i < n; i++) {
|
||||||
|
sources[i] = $.source(i);
|
||||||
|
}
|
||||||
|
return sources;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number} i
|
||||||
|
*/
|
||||||
|
function create_computation_0(i) {
|
||||||
|
$.derived(() => i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {any} s1
|
||||||
|
*/
|
||||||
|
function create_computation_1(s1) {
|
||||||
|
$.derived(() => $.get(s1));
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param {any} s1
|
||||||
|
* @param {any} s2
|
||||||
|
*/
|
||||||
|
function create_computation_2(s1, s2) {
|
||||||
|
$.derived(() => $.get(s1) + $.get(s2));
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_computation_1000(ss, offset) {
|
||||||
|
$.derived(() => {
|
||||||
|
let sum = 0;
|
||||||
|
for (let i = 0; i < 1000; i++) {
|
||||||
|
sum += $.get(ss[offset + i]);
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number} n
|
||||||
|
*/
|
||||||
|
function create_computations_0to1(n) {
|
||||||
|
for (let i = 0; i < n; i++) {
|
||||||
|
create_computation_0(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number} n
|
||||||
|
* @param {any[]} sources
|
||||||
|
*/
|
||||||
|
function create_computations_1to1(n, sources) {
|
||||||
|
for (let i = 0; i < n; i++) {
|
||||||
|
const source = sources[i];
|
||||||
|
create_computation_1(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number} n
|
||||||
|
* @param {any[]} sources
|
||||||
|
*/
|
||||||
|
function create_computations_2to1(n, sources) {
|
||||||
|
for (let i = 0; i < n; i++) {
|
||||||
|
create_computation_2(sources[i * 2], sources[i * 2 + 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_computation_4(s1, s2, s3, s4) {
|
||||||
|
$.derived(() => $.get(s1) + $.get(s2) + $.get(s3) + $.get(s4));
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_computations_1000to1(n, sources) {
|
||||||
|
for (let i = 0; i < n; i++) {
|
||||||
|
create_computation_1000(sources, i * 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_computations_1to2(n, sources) {
|
||||||
|
for (let i = 0; i < n / 2; i++) {
|
||||||
|
const source = sources[i];
|
||||||
|
create_computation_1(source);
|
||||||
|
create_computation_1(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_computations_1to4(n, sources) {
|
||||||
|
for (let i = 0; i < n / 4; i++) {
|
||||||
|
const source = sources[i];
|
||||||
|
create_computation_1(source);
|
||||||
|
create_computation_1(source);
|
||||||
|
create_computation_1(source);
|
||||||
|
create_computation_1(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_computations_1to8(n, sources) {
|
||||||
|
for (let i = 0; i < n / 8; i++) {
|
||||||
|
const source = sources[i];
|
||||||
|
create_computation_1(source);
|
||||||
|
create_computation_1(source);
|
||||||
|
create_computation_1(source);
|
||||||
|
create_computation_1(source);
|
||||||
|
create_computation_1(source);
|
||||||
|
create_computation_1(source);
|
||||||
|
create_computation_1(source);
|
||||||
|
create_computation_1(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_computations_1to1000(n, sources) {
|
||||||
|
for (let i = 0; i < n / 1000; i++) {
|
||||||
|
const source = sources[i];
|
||||||
|
for (let j = 0; j < 1000; j++) {
|
||||||
|
create_computation_1(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_computations_4to1(n, sources) {
|
||||||
|
for (let i = 0; i < n; i++) {
|
||||||
|
create_computation_4(
|
||||||
|
sources[i * 4],
|
||||||
|
sources[i * 4 + 1],
|
||||||
|
sources[i * 4 + 2],
|
||||||
|
sources[i * 4 + 3]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {any} fn
|
||||||
|
* @param {number} count
|
||||||
|
* @param {number} scount
|
||||||
|
*/
|
||||||
|
function bench(fn, count, scount) {
|
||||||
|
let sources = create_data_signals(scount, []);
|
||||||
|
|
||||||
|
fn(count, sources);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function sbench_create_signals() {
|
||||||
|
// Do 3 loops to warm up JIT
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
bench(create_data_signals, COUNT, COUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { timing } = await fastest_test(10, () => {
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
bench(create_data_signals, COUNT, COUNT);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
benchmark: 'sbench_create_signals',
|
||||||
|
time: timing.time.toFixed(2),
|
||||||
|
gc_time: timing.gc_time.toFixed(2)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function sbench_create_0to1() {
|
||||||
|
// Do 3 loops to warm up JIT
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
bench(create_computations_0to1, COUNT, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { timing } = await fastest_test(10, () => {
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
bench(create_computations_0to1, COUNT, 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
benchmark: 'sbench_create_0to1',
|
||||||
|
time: timing.time.toFixed(2),
|
||||||
|
gc_time: timing.gc_time.toFixed(2)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function sbench_create_1to1() {
|
||||||
|
// Do 3 loops to warm up JIT
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
bench(create_computations_1to1, COUNT, COUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { timing } = await fastest_test(10, () => {
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
bench(create_computations_1to1, COUNT, COUNT);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
benchmark: 'sbench_create_1to1',
|
||||||
|
time: timing.time.toFixed(2),
|
||||||
|
gc_time: timing.gc_time.toFixed(2)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function sbench_create_2to1() {
|
||||||
|
// Do 3 loops to warm up JIT
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
bench(create_computations_2to1, COUNT / 2, COUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { timing } = await fastest_test(10, () => {
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
bench(create_computations_2to1, COUNT / 2, COUNT);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
benchmark: 'sbench_create_2to1',
|
||||||
|
time: timing.time.toFixed(2),
|
||||||
|
gc_time: timing.gc_time.toFixed(2)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function sbench_create_4to1() {
|
||||||
|
// Do 3 loops to warm up JIT
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
bench(create_computations_4to1, COUNT / 4, COUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { timing } = await fastest_test(10, () => {
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
bench(create_computations_4to1, COUNT / 4, COUNT);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
benchmark: 'sbench_create_4to1',
|
||||||
|
time: timing.time.toFixed(2),
|
||||||
|
gc_time: timing.gc_time.toFixed(2)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function sbench_create_1000to1() {
|
||||||
|
// Do 3 loops to warm up JIT
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
bench(create_computations_1000to1, COUNT / 1000, COUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { timing } = await fastest_test(10, () => {
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
bench(create_computations_1000to1, COUNT / 1000, COUNT);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
benchmark: 'sbench_create_1000to1',
|
||||||
|
time: timing.time.toFixed(2),
|
||||||
|
gc_time: timing.gc_time.toFixed(2)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function sbench_create_1to2() {
|
||||||
|
// Do 3 loops to warm up JIT
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
bench(create_computations_1to2, COUNT, COUNT / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { timing } = await fastest_test(10, () => {
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
bench(create_computations_1to2, COUNT, COUNT / 2);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
benchmark: 'sbench_create_1to2',
|
||||||
|
time: timing.time.toFixed(2),
|
||||||
|
gc_time: timing.gc_time.toFixed(2)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function sbench_create_1to4() {
|
||||||
|
// Do 3 loops to warm up JIT
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
bench(create_computations_1to4, COUNT, COUNT / 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { timing } = await fastest_test(10, () => {
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
bench(create_computations_1to4, COUNT, COUNT / 4);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
benchmark: 'sbench_create_1to4',
|
||||||
|
time: timing.time.toFixed(2),
|
||||||
|
gc_time: timing.gc_time.toFixed(2)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function sbench_create_1to8() {
|
||||||
|
// Do 3 loops to warm up JIT
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
bench(create_computations_1to8, COUNT, COUNT / 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { timing } = await fastest_test(10, () => {
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
bench(create_computations_1to8, COUNT, COUNT / 8);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
benchmark: 'sbench_create_1to8',
|
||||||
|
time: timing.time.toFixed(2),
|
||||||
|
gc_time: timing.gc_time.toFixed(2)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function sbench_create_1to1000() {
|
||||||
|
// Do 3 loops to warm up JIT
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
bench(create_computations_1to1000, COUNT, COUNT / 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { timing } = await fastest_test(10, () => {
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
bench(create_computations_1to1000, COUNT, COUNT / 1000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
benchmark: 'sbench_create_1to1000',
|
||||||
|
time: timing.time.toFixed(2),
|
||||||
|
gc_time: timing.gc_time.toFixed(2)
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,90 @@
|
|||||||
|
import fs from 'node:fs';
|
||||||
|
import path from 'node:path';
|
||||||
|
import { execSync, fork } from 'node:child_process';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
|
import { benchmarks } from '../benchmarks.js';
|
||||||
|
|
||||||
|
// if (execSync('git status --porcelain').toString().trim()) {
|
||||||
|
// console.error('Working directory is not clean');
|
||||||
|
// process.exit(1);
|
||||||
|
// }
|
||||||
|
|
||||||
|
const filename = fileURLToPath(import.meta.url);
|
||||||
|
const runner = path.resolve(filename, '../runner.js');
|
||||||
|
const outdir = path.resolve(filename, '../.results');
|
||||||
|
|
||||||
|
if (fs.existsSync(outdir)) fs.rmSync(outdir, { recursive: true });
|
||||||
|
fs.mkdirSync(outdir);
|
||||||
|
|
||||||
|
const branches = [];
|
||||||
|
|
||||||
|
for (const arg of process.argv.slice(2)) {
|
||||||
|
if (arg.startsWith('--')) continue;
|
||||||
|
if (arg === filename) continue;
|
||||||
|
|
||||||
|
branches.push(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (branches.length === 0) {
|
||||||
|
branches.push(
|
||||||
|
execSync('git symbolic-ref --short -q HEAD || git rev-parse --short HEAD').toString().trim()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (branches.length === 1) {
|
||||||
|
branches.push('main');
|
||||||
|
}
|
||||||
|
|
||||||
|
process.on('exit', () => {
|
||||||
|
execSync(`git checkout ${branches[0]}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const branch of branches) {
|
||||||
|
console.group(`Benchmarking ${branch}`);
|
||||||
|
|
||||||
|
execSync(`git checkout ${branch}`);
|
||||||
|
|
||||||
|
await new Promise((fulfil, reject) => {
|
||||||
|
const child = fork(runner);
|
||||||
|
|
||||||
|
child.on('message', (results) => {
|
||||||
|
fs.writeFileSync(`${outdir}/${branch}.json`, JSON.stringify(results, null, ' '));
|
||||||
|
fulfil();
|
||||||
|
});
|
||||||
|
|
||||||
|
child.on('error', reject);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.groupEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
const results = branches.map((branch) => {
|
||||||
|
return JSON.parse(fs.readFileSync(`${outdir}/${branch}.json`, 'utf-8'));
|
||||||
|
});
|
||||||
|
|
||||||
|
for (let i = 0; i < results[0].length; i += 1) {
|
||||||
|
console.group(`${results[0][i].benchmark}`);
|
||||||
|
|
||||||
|
for (const metric of ['time', 'gc_time']) {
|
||||||
|
const times = results.map((result) => +result[i][metric]);
|
||||||
|
let min = Infinity;
|
||||||
|
let min_index = -1;
|
||||||
|
|
||||||
|
for (let b = 0; b < times.length; b += 1) {
|
||||||
|
if (times[b] < min) {
|
||||||
|
min = times[b];
|
||||||
|
min_index = b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (min !== 0) {
|
||||||
|
console.group(`${metric}: fastest is ${branches[min_index]}`);
|
||||||
|
times.forEach((time, b) => {
|
||||||
|
console.log(`${branches[b]}: ${time.toFixed(2)}ms (${((time / min) * 100).toFixed(2)}%)`);
|
||||||
|
});
|
||||||
|
console.groupEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.groupEnd();
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
import { benchmarks } from '../benchmarks.js';
|
||||||
|
|
||||||
|
const results = [];
|
||||||
|
for (const benchmark of benchmarks) {
|
||||||
|
const result = await benchmark();
|
||||||
|
console.error(result.benchmark);
|
||||||
|
results.push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
process.send(results);
|
@ -0,0 +1,32 @@
|
|||||||
|
import * as $ from '../packages/svelte/src/internal/client/index.js';
|
||||||
|
import { benchmarks } from './benchmarks.js';
|
||||||
|
|
||||||
|
let total_time = 0;
|
||||||
|
let total_gc_time = 0;
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log('-- Benchmarking Started --');
|
||||||
|
$.push({}, true);
|
||||||
|
try {
|
||||||
|
for (const benchmark of benchmarks) {
|
||||||
|
const results = await benchmark();
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(results);
|
||||||
|
total_time += Number(results.time);
|
||||||
|
total_gc_time += Number(results.gc_time);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.error('-- Benchmarking Failed --');
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.error(e);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
$.pop();
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log('-- Benchmarking Complete --');
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log({
|
||||||
|
total_time: total_time.toFixed(2),
|
||||||
|
total_gc_time: total_gc_time.toFixed(2)
|
||||||
|
});
|
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"moduleResolution": "Bundler",
|
||||||
|
"target": "ESNext",
|
||||||
|
"module": "ESNext",
|
||||||
|
"verbatimModuleSyntax": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"sourceMap": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"allowJs": true,
|
||||||
|
"checkJs": true
|
||||||
|
},
|
||||||
|
"include": ["./run.js", "./utils.js", "./benchmarks"]
|
||||||
|
}
|
@ -0,0 +1,98 @@
|
|||||||
|
import { performance, PerformanceObserver } from 'node:perf_hooks';
|
||||||
|
import v8 from 'v8-natives';
|
||||||
|
|
||||||
|
// Credit to https://github.com/milomg/js-reactivity-benchmark for the logic for timing + GC tracking.
|
||||||
|
|
||||||
|
class GarbageTrack {
|
||||||
|
track_id = 0;
|
||||||
|
observer = new PerformanceObserver((list) => this.perf_entries.push(...list.getEntries()));
|
||||||
|
perf_entries = [];
|
||||||
|
periods = [];
|
||||||
|
|
||||||
|
watch(fn) {
|
||||||
|
this.track_id++;
|
||||||
|
const start = performance.now();
|
||||||
|
const result = fn();
|
||||||
|
const end = performance.now();
|
||||||
|
this.periods.push({ track_id: this.track_id, start, end });
|
||||||
|
|
||||||
|
return { result, track_id: this.track_id };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number} track_id
|
||||||
|
*/
|
||||||
|
async gcDuration(track_id) {
|
||||||
|
await promise_delay(10);
|
||||||
|
|
||||||
|
const period = this.periods.find((period) => period.track_id === track_id);
|
||||||
|
if (!period) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors
|
||||||
|
return Promise.reject('no period found');
|
||||||
|
}
|
||||||
|
|
||||||
|
const entries = this.perf_entries.filter(
|
||||||
|
(e) => e.startTime >= period.start && e.startTime < period.end
|
||||||
|
);
|
||||||
|
return entries.reduce((t, e) => e.duration + t, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
this.observer.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.observer.observe({ entryTypes: ['gc'] });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function promise_delay(timeout = 0) {
|
||||||
|
return new Promise((resolve) => setTimeout(resolve, timeout));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {{ (): void; (): any; }} fn
|
||||||
|
*/
|
||||||
|
function run_timed(fn) {
|
||||||
|
const start = performance.now();
|
||||||
|
const result = fn();
|
||||||
|
const time = performance.now() - start;
|
||||||
|
return { result, time };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {() => void} fn
|
||||||
|
*/
|
||||||
|
async function run_tracked(fn) {
|
||||||
|
v8.collectGarbage();
|
||||||
|
const gc_track = new GarbageTrack();
|
||||||
|
const { result: wrappedResult, track_id } = gc_track.watch(() => run_timed(fn));
|
||||||
|
const gc_time = await gc_track.gcDuration(track_id);
|
||||||
|
const { result, time } = wrappedResult;
|
||||||
|
gc_track.destroy();
|
||||||
|
return { result, timing: { time, gc_time } };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number} times
|
||||||
|
* @param {() => void} fn
|
||||||
|
*/
|
||||||
|
export async function fastest_test(times, fn) {
|
||||||
|
const results = [];
|
||||||
|
for (let i = 0; i < times; i++) {
|
||||||
|
const run = await run_tracked(fn);
|
||||||
|
results.push(run);
|
||||||
|
}
|
||||||
|
const fastest = results.reduce((a, b) => (a.timing.time < b.timing.time ? a : b));
|
||||||
|
|
||||||
|
return fastest;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {boolean} a
|
||||||
|
*/
|
||||||
|
export function assert(a) {
|
||||||
|
if (!a) {
|
||||||
|
throw new Error('Assertion failed');
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,8 @@
|
|||||||
export type { Preprocessor, PreprocessorGroup } from './preprocess/public';
|
|
||||||
|
|
||||||
export type { CompileOptions } from './types/index';
|
|
||||||
|
|
||||||
export * from './index.js';
|
export * from './index.js';
|
||||||
|
export type {
|
||||||
|
MarkupPreprocessor,
|
||||||
|
Preprocessor,
|
||||||
|
PreprocessorGroup,
|
||||||
|
Processed
|
||||||
|
} from './preprocess/public';
|
||||||
|
export type { CompileOptions, ModuleCompileOptions, CompileResult, Warning } from './types/index';
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue