Skip to content
This repository was archived by the owner on Oct 16, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 72 additions & 52 deletions benchmark/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,75 +10,95 @@ https://stackoverflow.com/questions/28524653/what-do-the-results-from-benchmark-
## Counter Benchmark

```ts
1. Zustand x 30,591 ops/sec ±1.15% (61 runs sampled)
2. Redux x 30,239 ops/sec ±1.64% (63 runs sampled)
3. Mobx x 29,032 ops/sec ±1.24% (64 runs sampled)
4. AgileTs x 28,327 ops/sec ±2.96% (60 runs sampled)
5. Redux-Toolkit x 22,808 ops/sec ±1.79% (65 runs sampled)
6. Jotai x 22,479 ops/sec ±5.79% (63 runs sampled)
7. Valtio x 20,784 ops/sec ±2.75% (63 runs sampled)
8. Recoil x 14,351 ops/sec ±1.55% (65 runs sampled)
1. AgileTs.............43028 ops/se ±2.45 (63 runs sampled)
2. PulseJs.............41086 ops/se ±2.60 (63 runs sampled)
3. Nano Stores.........31933 ops/se ±1.27 (63 runs sampled)
4. Zustand.............29329 ops/se ±1.30 (62 runs sampled)
5. Redux...............28845 ops/se ±2.47 (61 runs sampled)
6. Hookstate...........27555 ops/se ±5.00 (59 runs sampled)
7. Mobx................27427 ops/se ±3.69 (62 runs sampled)
8. Redux-Toolkit.......22191 ops/se ±1.06 (65 runs sampled)
9. Jotai...............22157 ops/se ±4.10 (63 runs sampled)
10. Valtio..............21089 ops/se ±0.77 (63 runs sampled)
11. Recoil..............13926 ops/se ±2.12 (62 runs sampled)

Fastest is AgileTs
```

## 1000 Fields

```ts
// 1 Field
Agile Collection x 13,729 ops/sec ±3.42% (60 runs sampled) [updatedFieldsCount: 76468, renderFieldsCount: 73]
Agile State x 19,008 ops/sec ±1.87% (66 runs sampled) [updatedFieldsCount: 103559, renderFieldsCount: 72]
Agile nested State x 21,119 ops/sec ±1.45% (64 runs sampled) [updatedFieldsCount: 116226, renderFieldsCount: 72]
Hookstate x 20,026 ops/sec ±0.68% (64 runs sampled) [updatedFieldsCount: 112513, renderFieldsCount: 112513]
Jotai x 16,372 ops/sec ±3.34% (63 runs sampled) [updatedFieldsCount: 90275, renderFieldsCount: 90275]
Mobx x 15,892 ops/sec ±3.42% (60 runs sampled) [updatedFieldsCount: 82400, renderFieldsCount: 82400]
Nano Stores x 21,455 ops/sec ±1.00% (66 runs sampled) [updatedFieldsCount: 114136, renderFieldsCount: 114136]
Recoil x 11,504 ops/sec ±3.44% (63 runs sampled) [updatedFieldsCount: 61553, renderFieldsCount: 61554]
Redux x 13,070 ops/sec ±2.73% (62 runs sampled) [updatedFieldsCount: 69239, renderFieldsCount: 69240]
Valtio x 9,962 ops/sec ±2.60% (60 runs sampled) [updatedFieldsCount: 54290, renderFieldsCount: 108579]
1. Agile nested State..27992 ops/se ±1.73 (64 runs sampled)
2. Pulse Collection....25547 ops/se ±1.04 (64 runs sampled)
3. Agile State.........23962 ops/se ±2.16 (64 runs sampled)
4. Nano Stores.........20662 ops/se ±1.76 (65 runs sampled)
5. Hookstate...........19430 ops/se ±1.81 (61 runs sampled)
6. Agile Collection....18491 ops/se ±2.13 (65 runs sampled)
7. Jotai...............16029 ops/se ±3.39 (62 runs sampled)
8. Mobx................15631 ops/se ±3.42 (61 runs sampled)
9. Redux...............12698 ops/se ±2.86 (61 runs sampled)
10. Recoil..............11183 ops/se ±3.73 (61 runs sampled)
11. Valtio..............9728 ops/se ±2.81 (62 runs sampled)

Fastest is Agile nested State

// 10 Fields
Agile Collection x 10,651 ops/sec ±4.14% (58 runs sampled) [updatedFieldsCount: 56668, renderFieldsCount: 582]
Agile State x 16,175 ops/sec ±1.55% (65 runs sampled) [updatedFieldsCount: 87481, renderFieldsCount: 80]
Agile nested State x 20,703 ops/sec ±1.27% (65 runs sampled) [updatedFieldsCount: 113946, renderFieldsCount: 712]
Hookstate x 18,733 ops/sec ±3.14% (59 runs sampled) [updatedFieldsCount: 105792, renderFieldsCount: 105801]
Jotai x 15,602 ops/sec ±3.65% (61 runs sampled) [updatedFieldsCount: 85977, renderFieldsCount: 85986]
Mobx x 9,283 ops/sec ±3.16% (52 runs sampled) [updatedFieldsCount: 50806, renderFieldsCount: 508060]
Nano Stores x 20,125 ops/sec ±1.62% (62 runs sampled) [updatedFieldsCount: 108704, renderFieldsCount: 108713]
Recoil x 11,103 ops/sec ±4.50% (61 runs sampled) [updatedFieldsCount: 62920, renderFieldsCount: 62939]
Redux x 8,728 ops/sec ±1.61% (64 runs sampled) [updatedFieldsCount: 50794, renderFieldsCount: 507950]
Valtio x 3,557 ops/sec ±2.96% (23 runs sampled) [updatedFieldsCount: 22473, renderFieldsCount: 449450]
1. Agile nested State..27658 ops/se ±1.99 (64 runs sampled)
2. Pulse Collection....24839 ops/se ±1.31 (65 runs sampled)
3. Agile State.........19853 ops/se ±2.15 (64 runs sampled)
4. Nano Stores.........19479 ops/se ±2.12 (60 runs sampled)
5. Hookstate...........18104 ops/se ±3.37 (60 runs sampled)
6. Jotai...............15472 ops/se ±2.45 (62 runs sampled)
7. Agile Collection....13352 ops/se ±3.67 (61 runs sampled)
8. Recoil..............10522 ops/se ±3.79 (58 runs sampled)
9. Mobx................9477 ops/se ±1.94 (62 runs sampled)
10. Redux...............8434 ops/se ±2.67 (47 runs sampled)
11. Valtio..............3532 ops/se ±2.27 (23 runs sampled)

Fastest is Agile nested State

// 100 Fields
Agile Collection x 3,897 ops/sec ±3.01% (25 runs sampled) [updatedFieldsCount: 24427, renderFieldsCount: 2502]
Agile State x 8,355 ops/sec ±0.85% (67 runs sampled) [updatedFieldsCount: 46249, renderFieldsCount: 173]
Agile nested State x 18,641 ops/sec ±1.17% (63 runs sampled) [updatedFieldsCount: 98669, renderFieldsCount: 6802]
Hookstate x 14,865 ops/sec ±2.51% (61 runs sampled) [updatedFieldsCount: 81616, renderFieldsCount: 81715]
Jotai x 12,676 ops/sec ±3.09% (61 runs sampled) [updatedFieldsCount: 65930, renderFieldsCount: 66029]
Mobx x 1,812 ops/sec ±1.49% (63 runs sampled) [updatedFieldsCount: 9639, renderFieldsCount: 963900]
Nano Stores x 16,283 ops/sec ±1.39% (62 runs sampled) [updatedFieldsCount: 84772, renderFieldsCount: 84871]
Recoil x 9,418 ops/sec ±2.94% (62 runs sampled) [updatedFieldsCount: 52425, renderFieldsCount: 52624]
Redux x 1,896 ops/sec ±1.74% (62 runs sampled) [updatedFieldsCount: 10133, renderFieldsCount: 1013400]
Valtio x 472 ops/sec ±2.97% (61 runs sampled) [updatedFieldsCount: 2494, renderFieldsCount: 498700]
1. Agile nested State..24124 ops/se ±1.05 (65 runs sampled)
2. Pulse Collection....21912 ops/se ±1.35 (66 runs sampled)
3. Nano Stores.........15638 ops/se ±1.63 (62 runs sampled)
4. Hookstate...........13986 ops/se ±2.28 (59 runs sampled)
5. Jotai...............12167 ops/se ±2.78 (63 runs sampled)
6. Agile State.........9175 ops/se ±1.56 (51 runs sampled)
7. Recoil..............8717 ops/se ±3.51 (49 runs sampled)
8. Agile Collection....4177 ops/se ±1.64 (61 runs sampled)
9. Redux...............1763 ops/se ±1.06 (63 runs sampled)
10. Mobx................1699 ops/se ±1.82 (62 runs sampled)
11. Valtio..............432 ops/se ±2.18 (60 runs sampled)

Fastest is Agile nested State

// 1000 Fields
Agile Collection x 503 ops/sec ±2.23% (62 runs sampled) [updatedFieldsCount: 2616, renderFieldsCount: 3520]
Agile State x 1,437 ops/sec ±1.48% (59 runs sampled) [updatedFieldsCount: 7569, renderFieldsCount: 1061]
Agile nested State x 9,411 ops/sec ±1.54% (56 runs sampled) [updatedFieldsCount: 46693, renderFieldsCount: 33243]
Hookstate x 4,539 ops/sec ±3.61% (27 runs sampled) [updatedFieldsCount: 26381, renderFieldsCount: 27380]
Jotai x 4,014 ops/sec ±5.35% (53 runs sampled) [updatedFieldsCount: 20390, renderFieldsCount: 21389]
Mobx x 151 ops/sec ±0.75% (59 runs sampled) [updatedFieldsCount: 786, renderFieldsCount: 786000]
Nano Stores x 5,511 ops/sec ±6.27% (32 runs sampled) [updatedFieldsCount: 31266, renderFieldsCount: 32265]
Recoil x 3,562 ops/sec ±3.16% (58 runs sampled) [updatedFieldsCount: 18503, renderFieldsCount: 20502]
Redux x 165 ops/sec ±1.40% (57 runs sampled) [updatedFieldsCount: 858, renderFieldsCount: 859000]
Valtio x 38.76 ops/sec ±5.50% (42 runs sampled) [updatedFieldsCount: 215, renderFieldsCount: 429000]
1. Agile nested State..10756 ops/se ±1.43 (58 runs sampled)
2. Pulse Collection....9774 ops/se ±2.39 (58 runs sampled)
3. Hookstate...........4737 ops/se ±4.33 (58 runs sampled)
4. Nano Stores.........4638 ops/se ±6.40 (28 runs sampled)
5. Jotai...............3352 ops/se ±4.17 (53 runs sampled)
6. Recoil..............3139 ops/se ±4.69 (54 runs sampled)
7. Agile State.........1389 ops/se ±1.52 (57 runs sampled)
8. Agile Collection....500 ops/se ±1.89 (61 runs sampled)
9. Redux...............154 ops/se ±1.48 (57 runs sampled)
10. Mobx................144 ops/se ±1.06 (55 runs sampled)
11. Valtio..............37 ops/se ±4.26 (40 runs sampled)

Fastest is Agile nested State
```

## Computed

```ts
Agile Hard Coded x 23,201 ops/sec ±1.39% (64 runs sampled)
Agile Auto Tracking x 22,661 ops/sec ±3.31% (60 runs sampled)
Jotai x 18,489 ops/sec ±5.43% (62 runs sampled)
Recoil x 10,312 ops/sec ±2.57% (64 runs sampled)
1. Agile Hard Coded....32079 ops/se ±1.51 (62 runs sampled)
2. Agile Auto Tracking.30974 ops/se ±2.21 (64 runs sampled)
3. Nano Stores.........28821 ops/se ±1.49 (64 runs sampled)
4. Jotai...............18922 ops/se ±2.12 (61 runs sampled)
5. Recoil..............10103 ops/se ±2.47 (64 runs sampled)

Fastest is Agile Hard Coded
```

## 🏃 Running Benchmarks
Expand Down
73 changes: 73 additions & 0 deletions benchmark/benchmarkManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
export interface CycleResultInterface {
name: string;
opsInSec: number;
failRate: number;
ranSampleCount: number;
ui: any;
}

export function getCycleResult(event: any): CycleResultInterface {
return {
name: event.target.name,
opsInSec: Math.round(event.target.hz),
failRate: event.target.stats.rme.toFixed(2),
ranSampleCount: event.target.stats.sample.length,
ui: {
count: event.target.output,
},
};
}

export function startBenchmarkLog(testSuiteName: string): void {
console.log(`{white Starting Benchmark "{magenta.bold ${testSuiteName}}"..}`);
}

export function cycleLog(
cycleResult: CycleResultInterface,
...addition: any[]
): void {
console.log(
`{gray ..Proceeded {green.bold ${cycleResult.name}} - {yellow ${cycleResult.opsInSec} ops/sec}}`,
...addition
);
}

export function endBenchmarkLog(
testSuiteName: string,
results: CycleResultInterface[],
fastest: string[]
): void {
console.log(`{white ..End Benchmark "{magenta.bold ${testSuiteName}}"}\n\n`);

results.sort((a, b) => {
if (a.opsInSec < b.opsInSec) return 1;
return -1;
});

let resultString = '';
for (let i = 0; i < results.length; i++) {
const cycleResult = results[i];

// Build Cycle Result Log
const cycleString = `{bold.bgGreen ${
i + 1
}.} {bold.blue ${cycleResult.name
.padEnd(20, '.')
.replace(/(\.+)$/, '{red $1}')}}{yellow ${
cycleResult.opsInSec
} ops/se} {gray ±${cycleResult.failRate}%} (${
cycleResult.ranSampleCount
} runs sampled)`;

resultString += `${cycleString}${i < results.length - 1 ? '\n' : ''}`;
}

// Build Leaderboard Header
console.log('{bgYellow.white.bold Leaderboard:}\n');

// Print Leaderboard
console.log(resultString);

// Print fastest
console.log(`\n{bold Fastest is {bold.green ${fastest}}}\n`);
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import React from 'react';
import ReactDom from 'react-dom';
import { createCollection } from '@agile-ts/core';
import { createCollection, LogCodeManager } from '@agile-ts/core';
import { useAgile, useValue } from '@agile-ts/react';

LogCodeManager.getLogger().isActive = false;

export default function (target: HTMLElement, fieldsCount: number) {
const FIELDS = createCollection({
initialData: Array.from(Array(fieldsCount).keys()).map((i) => ({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { createState, State } from '@agile-ts/core';
import { createState, LogCodeManager, State } from '@agile-ts/core';
import { useAgile } from '@agile-ts/react';

LogCodeManager.getLogger().isActive = false;

export default function (target: HTMLElement, fieldsCount: number) {
const FIELDS = createState(
Array.from(Array(fieldsCount).keys()).map((i) =>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import React from 'react';
import ReactDom from 'react-dom';
import { createState } from '@agile-ts/core';
import { createState, LogCodeManager } from '@agile-ts/core';
import { useAgile } from '@agile-ts/react';

LogCodeManager.getLogger().isActive = false;

export default function (target: HTMLElement, fieldsCount: number) {
const FIELDS = createState(
Array.from(Array(fieldsCount).keys()).map((i) => `Field #${i + 1}`)
Expand Down
25 changes: 18 additions & 7 deletions benchmark/benchmarks/react/1000fields/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import Benchmark, { Suite, Options } from 'benchmark';
import ReactDOM from 'react-dom';
import Benchmark, { Suite, Options } from 'benchmark';
import {
cycleLog,
CycleResultInterface,
endBenchmarkLog,
getCycleResult,
startBenchmarkLog,
} from '../../../benchmarkManager';

// Files to run the Benchmark on
import agileCollection from './bench/agilets/collection';
Expand Down Expand Up @@ -66,14 +73,16 @@ function configTest(
};
}

const results: CycleResultInterface[] = [];

// Add Tests to the Benchmark Test Suite
suite
.add('Agile Collection', configTest(agileCollection))
.add('Agile State', configTest(agileState))
.add('Agile nested State', configTest(agileNestedState))
.add('Pulse Collection', configTest(pulseCollection))
.add('Pulse State', configTest(pulseState))
.add('Pulse nested State', configTest(pulseNestedState))
// .add('Pulse State', configTest(pulseState))
// .add('Pulse nested State', configTest(pulseNestedState))
.add('Hookstate', configTest(hookstate))
.add('Jotai', configTest(jotai))
.add('Mobx', configTest(mobx))
Expand All @@ -84,16 +93,18 @@ suite

// Add Listener
.on('start', function (this: any) {
console.log(`Starting ${this.name}`);
startBenchmarkLog(this.name);
})
.on('cycle', (event: any) => {
console.log(
String(event.target),
const cycleResult = getCycleResult(event);
cycleLog(
cycleResult,
`[updatedFieldsCount: ${event.target.updatedFieldsCount}, renderFieldsCount: ${event.target.renderFieldsCount}]`
);
results.push(cycleResult);
})
.on('complete', function (this: any) {
console.log(`Fastest is ${this.filter('fastest').map('name')}`);
endBenchmarkLog(this.name, results, this.filter('fastest').map('name'));

// @ts-ignore
// Notify server that the Benchmark Test Suite has ended
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React from 'react';
import ReactDom from 'react-dom';
import { createComputed, createState } from '@agile-ts/core';
import { createComputed, createState, LogCodeManager } from '@agile-ts/core';
import { useAgile } from '@agile-ts/react';

LogCodeManager.getLogger().isActive = false;
const COUNT = createState(0);
const COMPUTED_COUNT = createComputed(() => {
return COUNT.value * 5;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React from 'react';
import ReactDom from 'react-dom';
import { createComputed, createState } from '@agile-ts/core';
import { createComputed, createState, LogCodeManager } from '@agile-ts/core';
import { useAgile } from '@agile-ts/react';

LogCodeManager.getLogger().isActive = false;
const COUNT = createState(0);
const COMPUTED_COUNT = createComputed(
() => {
Expand Down
21 changes: 16 additions & 5 deletions benchmark/benchmarks/react/computed/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import ReactDOM from 'react-dom';
import Benchmark, { Suite, Options } from 'benchmark';
import {
cycleLog,
CycleResultInterface,
endBenchmarkLog,
getCycleResult,
startBenchmarkLog,
} from '../../../benchmarkManager';

// Files to run the Benchmark on
import agileAutoTracking from './bench/agilets/autoTracking';
Expand All @@ -13,7 +20,7 @@ import recoil from './bench/recoil';
window.Benchmark = Benchmark;

// Create new Benchmark Test Suite
const suite = new Suite('Count');
const suite = new Suite('Computed');

// Retrieve the Element to render the Benchmark Test Suite in
const target = document.getElementById('bench')!;
Expand Down Expand Up @@ -53,6 +60,8 @@ function configTest(renderElement: (target: HTMLElement) => void): Options {
};
}

const results: CycleResultInterface[] = [];

// Add Tests to the Benchmark Test Suite
suite
.add('Agile Auto Tracking', configTest(agileAutoTracking))
Expand All @@ -63,16 +72,18 @@ suite

// Add Listener
.on('start', function (this: any) {
console.log(`Starting ${this.name}`);
startBenchmarkLog(this.name);
})
.on('cycle', (event: any) => {
console.log(
String(event.target),
const cycleResult = getCycleResult(event);
cycleLog(
cycleResult,
`[Count: ${event.target.output}, ComputedCount: ${event.target.computedOutput}]`
);
results.push(cycleResult);
})
.on('complete', function (this: any) {
console.log(`Fastest is ${this.filter('fastest').map('name')}`);
endBenchmarkLog(this.name, results, this.filter('fastest').map('name'));

// @ts-ignore
// Notify server that the Benchmark Test Suite has ended
Expand Down
Loading