318 lines
8.0 KiB
JavaScript
318 lines
8.0 KiB
JavaScript
/*
|
|
* Copyright (c) 2024 Huawei Technologies Co.,Ltd.
|
|
*
|
|
* openInula is licensed under Mulan PSL v2.
|
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
* You may obtain a copy of Mulan PSL v2 at:
|
|
*
|
|
* http://license.coscl.org.cn/MulanPSL2
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
* See the Mulan PSL v2 for more details.
|
|
*/
|
|
|
|
/**
|
|
* Extracted from: https://github.com/Riim/cellx#benchmark
|
|
*/
|
|
import chalk from 'chalk';
|
|
import * as solid from './solid-reactive.js';
|
|
import * as reactively from '@reactively/core';
|
|
import Table from 'cli-table';
|
|
import { reactive, computed, RNode } from '../dist/index.js';
|
|
|
|
const BATCHED = true;
|
|
const RUNS_PER_TIER = 150;
|
|
const LAYER_TIERS = [10, 100, 500, 1000, 2000];
|
|
|
|
const med = array => array.sort((a, b) => (a - b < 0 ? 1 : -1))[Math.floor(array.length / 2)] || 0;
|
|
|
|
const SOLUTIONS = {
|
|
10: [2, 4, -2, -3],
|
|
100: [-2, -4, 2, 3],
|
|
500: [-2, 1, -4, -4],
|
|
1000: [-2, -4, 2, 3],
|
|
2000: [-2, 1, -4, -4],
|
|
// 2500: [-2, -4, 2, 3],
|
|
};
|
|
|
|
/**
|
|
* @param {number} layers
|
|
* @param {number[]} answer
|
|
*/
|
|
const isSolution = (layers, answer) => answer.every((_, i) => SOLUTIONS[layers][i] === _);
|
|
|
|
async function main() {
|
|
const report = {};
|
|
report.solid = { fn: runSolid, runs: [] };
|
|
report.reactively = { fn: runReactively, runs: [], avg: [] };
|
|
report.inluaReactive = { fn: runInulaReactive, runs: [], avg: [] };
|
|
// report.inluaDeepReactive = { fn: runInulaDeepReactive, runs: [], avg: [] };
|
|
|
|
for (const lib of Object.keys(report)) {
|
|
const current = report[lib];
|
|
|
|
for (let i = 0; i < LAYER_TIERS.length; i += 1) {
|
|
let layers = LAYER_TIERS[i];
|
|
const runs = [];
|
|
|
|
for (let j = 0; j < RUNS_PER_TIER; j += 1) {
|
|
runs.push(await start(current.fn, layers));
|
|
}
|
|
// Give cellx time to release its global pendingCells array
|
|
await new Promise(resolve => setTimeout(resolve, 0));
|
|
|
|
current.runs[i] = med(runs) * 1000;
|
|
}
|
|
}
|
|
|
|
const table = new Table({
|
|
head: ['', ...LAYER_TIERS.map(n => chalk.bold(chalk.cyan(n)))],
|
|
});
|
|
|
|
for (let i = 0; i < LAYER_TIERS.length; i += 1) {
|
|
let min = Infinity,
|
|
max = -1,
|
|
fastestLib,
|
|
slowestLib;
|
|
|
|
for (const lib of Object.keys(report)) {
|
|
const time = report[lib].runs[i];
|
|
|
|
if (time < min) {
|
|
min = time;
|
|
fastestLib = lib;
|
|
}
|
|
|
|
if (time > max) {
|
|
max = time;
|
|
slowestLib = lib;
|
|
}
|
|
}
|
|
report[fastestLib].runs[i] = chalk.green(report[fastestLib].runs[i].toFixed(2));
|
|
report[slowestLib].runs[i] = chalk.red(report[slowestLib].runs[i].toFixed(2));
|
|
}
|
|
|
|
for (const lib of Object.keys(report)) {
|
|
table.push([chalk.magenta(lib), ...report[lib].runs.map(n => (typeof n === 'number' ? n.toFixed(2) : n))]);
|
|
}
|
|
|
|
console.log(table.toString());
|
|
}
|
|
|
|
async function start(runner, layers) {
|
|
return new Promise(done => {
|
|
runner(layers, done);
|
|
}).catch(e => {
|
|
console.error(e.message);
|
|
});
|
|
}
|
|
|
|
function runInulaReactive(layers, done) {
|
|
const start = {
|
|
a: new RNode(1),
|
|
b: new RNode(2),
|
|
c: new RNode(3),
|
|
d: new RNode(4),
|
|
};
|
|
|
|
let layer = start;
|
|
|
|
for (let i = layers; i--; ) {
|
|
layer = (m => {
|
|
return {
|
|
a: new RNode(() => m.b.get()),
|
|
b: new RNode(() => m.a.get() - m.c.get()),
|
|
c: new RNode(() => m.b.get() + m.d.get()),
|
|
d: new RNode(() => m.c.get()),
|
|
};
|
|
})(layer);
|
|
}
|
|
|
|
const startTime = performance.now();
|
|
|
|
start.a.set(4), start.b.set(3), start.c.set(2), start.d.set(1);
|
|
|
|
const end = layer;
|
|
const solution = [end.a.get(), end.b.get(), end.c.get(), end.d.get()];
|
|
const endTime = performance.now() - startTime;
|
|
|
|
done(isSolution(layers, solution) ? endTime : -1);
|
|
}
|
|
|
|
|
|
function runInulaDeepReactive(layers, done) {
|
|
const start = {
|
|
a: new reactive({ v: 1 }),
|
|
b: new reactive({ v: 2 }),
|
|
c: new reactive({ v: 3 }),
|
|
d: new reactive({ v: 4 }),
|
|
};
|
|
|
|
let layer = start;
|
|
|
|
for (let i = layers; i--; ) {
|
|
layer = (l => {
|
|
return {
|
|
a: new computed(() => ({
|
|
v: l.b.v.get(),
|
|
})),
|
|
b: new computed(() => ({
|
|
v: l.a.v.get() - l.c.v.get(),
|
|
})),
|
|
c: new computed(() => ({
|
|
v: l.b.v.get() + l.d.v.get(),
|
|
})),
|
|
d: new computed(() => ({
|
|
v: l.c.v.get(),
|
|
})),
|
|
};
|
|
})(layer);
|
|
}
|
|
|
|
const startTime = performance.now();
|
|
|
|
start.a.v.set(4), start.b.v.set(3), start.c.v.set(2), start.d.v.set(1);
|
|
|
|
const end = layer;
|
|
const solution = [end.a.v.get(), end.b.v.get(), end.c.v.get(), end.d.v.get()];
|
|
const endTime = performance.now() - startTime;
|
|
done(isSolution(layers, solution) ? endTime : -1);
|
|
}
|
|
|
|
function runInulaDeepReactive3Layers(layers, done) {
|
|
const start = {
|
|
a: new reactive({ v: { v: { v: 1 } } }),
|
|
b: new reactive({ v: { v: { v: 2 } } }),
|
|
c: new reactive({ v: { v: { v: 3 } } }),
|
|
d: new reactive({ v: { v: { v: 4 } } }),
|
|
};
|
|
|
|
let layer = start;
|
|
|
|
for (let i = layers; i--; ) {
|
|
layer = (l => {
|
|
return {
|
|
a: new computed(() => ({
|
|
v: {
|
|
v: {
|
|
v: l.b.v.v.v.get(),
|
|
},
|
|
},
|
|
})),
|
|
b: new computed(() => ({
|
|
v: {
|
|
v: {
|
|
v: l.a.v.v.v.get() - l.c.v.v.v.get(),
|
|
},
|
|
},
|
|
})),
|
|
c: new computed(() => ({
|
|
v: {
|
|
v: {
|
|
v: l.b.v.v.v.get() + l.d.v.v.v.get(),
|
|
},
|
|
},
|
|
})),
|
|
d: new computed(() => ({
|
|
v: {
|
|
v: {
|
|
v: l.c.v.v.v.get(),
|
|
},
|
|
},
|
|
})),
|
|
};
|
|
})(layer);
|
|
}
|
|
|
|
const startTime = performance.now();
|
|
|
|
start.a.v.v.v.set(4), start.b.v.v.v.set(3), start.c.v.v.v.set(2), start.d.v.v.v.set(1);
|
|
|
|
const end = layer;
|
|
const solution = [end.a.v.v.v.get(), end.b.v.v.v.get(), end.c.v.v.v.get(), end.d.v.v.v.get()];
|
|
const endTime = performance.now() - startTime;
|
|
done(isSolution(layers, solution) ? endTime : -1);
|
|
}
|
|
|
|
/**
|
|
* @see {@link https://github.com/solidjs/solid}
|
|
*/
|
|
function runSolid(layers, done) {
|
|
solid.createRoot(async dispose => {
|
|
const [a, setA] = solid.createSignal(1),
|
|
[b, setB] = solid.createSignal(2),
|
|
[c, setC] = solid.createSignal(3),
|
|
[d, setD] = solid.createSignal(4);
|
|
|
|
const start = { a, b, c, d };
|
|
|
|
let layer = start;
|
|
|
|
for (let i = layers; i--; ) {
|
|
layer = (m => {
|
|
const props = {
|
|
a: solid.createMemo(() => m.b()),
|
|
b: solid.createMemo(() => m.a() - m.c()),
|
|
c: solid.createMemo(() => m.b() + m.d()),
|
|
d: solid.createMemo(() => m.c()),
|
|
};
|
|
|
|
return props;
|
|
})(layer);
|
|
}
|
|
|
|
const startTime = performance.now();
|
|
|
|
const run = BATCHED ? solid.batch : fn => fn();
|
|
run(() => {
|
|
setA(4), setB(3), setC(2), setD(1);
|
|
});
|
|
|
|
const end = layer;
|
|
const solution = [end.a(), end.b(), end.c(), end.d()];
|
|
const endTime = performance.now() - startTime;
|
|
|
|
dispose();
|
|
done(isSolution(layers, solution) ? endTime : -1);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* @see {@link https://github.com/modderme123/reactively}
|
|
*/
|
|
function runReactively(layers, done) {
|
|
const start = {
|
|
a: new reactively.Reactive(1),
|
|
b: new reactively.Reactive(2),
|
|
c: new reactively.Reactive(3),
|
|
d: new reactively.Reactive(4),
|
|
};
|
|
|
|
let layer = start;
|
|
|
|
for (let i = layers; i--; ) {
|
|
layer = (m => {
|
|
return {
|
|
a: new reactively.Reactive(() => m.b.get()),
|
|
b: new reactively.Reactive(() => m.a.get() - m.c.get()),
|
|
c: new reactively.Reactive(() => m.b.get() + m.d.get()),
|
|
d: new reactively.Reactive(() => m.c.get()),
|
|
};
|
|
})(layer);
|
|
}
|
|
|
|
const startTime = performance.now();
|
|
|
|
start.a.set(4), start.b.set(3), start.c.set(2), start.d.set(1);
|
|
|
|
const end = layer;
|
|
const solution = [end.a.get(), end.b.get(), end.c.get(), end.d.get()];
|
|
const endTime = performance.now() - startTime;
|
|
|
|
done(isSolution(layers, solution) ? endTime : -1);
|
|
}
|
|
|
|
main();
|