Skip to content

Commit

Permalink
docs: add performance section in the readme
Browse files Browse the repository at this point in the history
  • Loading branch information
elbywan committed Sep 4, 2022
1 parent 8f1df34 commit 71b523c
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 19 deletions.
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,21 @@ dispose(calculateSum)

*Hyperactiv websocket implementation.*

## Performance

This repository includes a [benchmark folder](https://github.com/elbywan/hyperactiv/tree/master/bench) which pits `hyperactiv` against other similar libraries.

While not the best in terms of raw performance it is still reasonably fast and I encourage you to have a look at the different implementations to compare the library APIs. [For instance there is no `.get()` and `.set()` wrappers when using `hyperactiv`](https://github.com/elbywan/hyperactiv/blob/master/bench/layers.mjs#L302).

**Here are the raw results: _(50 runs per tiers, average time ignoring the 10 best & 10 worst runs)_**

![bench](./docs/bench.png)

> Each tier nests observable objects X (10/100/500/1000…) times and performs some computations on the deepest one. This causes reactions to propagate to the whole observable tree.

_**Disclaimer**: I adapted the code from [`maverickjs`](https://github.com/maverick-js/observables/tree/main/bench) which was itself a rewrite of the benchmark from [`cellx`](https://github.com/Riim/cellx#benchmark). I also wrote some MobX code which might not be the best in terms of optimization since I am not very familiar with the API._

## Code samples

#### A simple sum and a counter
Expand Down
45 changes: 27 additions & 18 deletions bench/layers.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@

import kleur from 'kleur'
import * as cellx from 'cellx'

import * as Sjs from 's-js'
import * as mobx from 'mobx'
import * as maverick from '@maverick-js/observables'
import hyperactiv from 'hyperactiv'
import Table from 'cli-table'
import pkgs from './pkgs.cjs'

const RUNS_PER_TIER = 25
const RUNS_PER_TIER = 50
const DISCARD_BEST_WORST_X_RUNS = 10
const LAYER_TIERS = [10, 100, 500, 1000, 2000, 2500, 5000, 10000]

const sum = array => array.reduce((a, b) => a + b, 0)
Expand All @@ -37,21 +38,23 @@ const SOLUTIONS = {
*/
const isSolution = (layers, answer) => answer.every((s, i) => s === SOLUTIONS[layers][i])

const pkgKey = pkg => `${pkgs[pkg].name}@${pkgs[pkg].version}`

async function main() {
const report = {
cellx: { fn: runCellx, runs: [] },
hyperactiv: { fn: runHyperactiv, runs: [] },
maverick: { fn: runMaverick, runs: [], avg: [] },
mobx: { fn: runMobx, runs: [] },
S: { fn: runS, runs: [] }
[pkgKey('cellx')]: { fn: runCellx, runs: [] },
[pkgKey('hyperactiv')]: { fn: runHyperactiv, runs: [] },
[pkgKey('maverick')]: { fn: runMaverick, runs: [], avg: [] },
[pkgKey('mobx')]: { fn: runMobx, runs: [] },
[pkgKey('S')]: { fn: runS, runs: [] }
}

for(const lib of Object.keys(report)) {
const current = report[lib]

for(let i = 0; i < LAYER_TIERS.length; i += 1) {
const layers = LAYER_TIERS[i]
const runs = []
let runs = []
let result = null

for(let j = 0; j < RUNS_PER_TIER; j += 1) {
Expand All @@ -64,6 +67,9 @@ async function main() {
if(typeof result !== 'number') {
current.runs[i] = result
} else {
if(DISCARD_BEST_WORST_X_RUNS) {
runs = runs.sort().slice(DISCARD_BEST_WORST_X_RUNS, -DISCARD_BEST_WORST_X_RUNS)
}
current.runs[i] = avg(runs) * 1000
}
}
Expand Down Expand Up @@ -119,7 +125,7 @@ async function start(runner, layers) {
runner(layers, done)
}).catch(error => {
console.error(error)
return 'error'
return error.message.toString()
})
}

Expand Down Expand Up @@ -262,12 +268,12 @@ function runMobx(layers, done) {

for(let i = layers; i--;) {
layer = (prev => {
const next = mobx.observable({
const next = {
a: mobx.computed(() => prev.b.get()),
b: mobx.computed(() => prev.a.get() - prev.c.get()),
c: mobx.computed(() => prev.b.get() + prev.d.get()),
d: mobx.computed(() => prev.c.get())
})
}

return next
})(layer)
Expand All @@ -294,21 +300,24 @@ function runMobx(layers, done) {
}

function runHyperactiv(layers, done) {
const start = hyperactiv.observe({
const observe = obj => hyperactiv.observe(obj, { batch: true })
const computed = fn => hyperactiv.computed(fn, { disableTracking: true })

const start = observe({
a: 1,
b: 2,
c: 3,
d: 4
}, { batch: true })
})
let layer = start

for(let i = layers; i--;) {
layer = (prev => {
const next = hyperactiv.observe({}, { batch: true })
hyperactiv.computed(() => next.a = prev.b, { disableTracking: true })
hyperactiv.computed(() => next.b = prev.a - prev.c, { disableTracking: true })
hyperactiv.computed(() => next.c = prev.b + prev.d, { disableTracking: true })
hyperactiv.computed(() => next.d = prev.c, { disableTracking: true })
const next = observe({})
computed(() => next.a = prev.b)
computed(() => next.b = prev.a - prev.c)
computed(() => next.c = prev.b + prev.d)
computed(() => next.d = prev.c)
return next
})(layer)
}
Expand Down
2 changes: 1 addition & 1 deletion bench/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions bench/pkgs.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module.exports = {
cellx: require('cellx/package.json'),
hyperactiv: require('hyperactiv/package.json'),
maverick: require('@maverick-js/observables/package.json'),
mobx: require('mobx/package.json'),
S: require('s-js/package.json')
}
Binary file added docs/bench.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 71b523c

Please sign in to comment.