-
Notifications
You must be signed in to change notification settings - Fork 0
/
bench.js
125 lines (122 loc) · 4.65 KB
/
bench.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
require('./objix')
const _ = require('lodash')
const assert = require('assert')
//const ph = require('node:perf_hooks')
const hdr = require('hdr-histogram-js')
const iters = process.argv[2] || 1000 // Number of iterations per heat
const heats = process.argv[3] || 100 // Number of randomised heats
const nSimp = process.argv[4] || 10 // Number of simple object entries
const nDeep = process.argv[5] || 1 // Number of complex object entries
const round = (v, p = 2) => Math.round(v * (10 ** p)) / (10 ** p)
/*
Calculate run time for *heats* batches of *iters* executions of each function, with a randomised execution order for each batch.
Each batch run also includes a 100 iteration warmup verifying the results of the function against objix
*/
function compare(funcs) {
let hist = funcs.map(v => null), start
for (let r = 0; r < heats; r++) for (let [key,fun] of _.shuffle(funcs.entries())) if (fun) {
for (let i = 0; i < 100; i++) assert.deepEqual(funcs.objix(), fun(), fun)
if (!hist[key]) hist[key] = hdr.build()
start = performance.now()
for (let i = 0; i < iters; i++) fun()
hist[key].recordValue(Math.round(iters/(performance.now() - start)))
}
/*
return hist.flatMap((k,v) => [
[k + ' 75%', v.percentiles.get(75)],
[k + ' avg', v.mean],
[k + ' Err', round(100*v.stddev/v.mean)],
[k + ' Inc', round((100*v.mean/hist.lodash.mean)-100)],
])
*/
let res = hist.map(v => v?.mean)
res['% Inc'] = round(100*(hist.objix.mean - hist.lodash.mean)/hist.lodash.mean)
//res['% Err'] = round(100*(hist.objix.stddev + hist.lodash.stddev)/(hist.objix.mean + hist.lodash.mean))
return res
}
function report(title, ob) {
console.log(title)
console.table({
Map: {
objix : () => ob.map(v => v+1),
lodash: () => _.mapValues(ob, v => v+1),
vanilla: () => Object.fromEntries(Object.entries(ob).map(([k,v]) => [k, v+1])),
},
Pick: {
objix: () => ob.pick(v => v == 1),
lodash: () => _.pickBy(ob, v => v == 1),
vanilla: () => Object.fromEntries(Object.entries(ob).flatMap(([k,v]) => v == 1 ? [[k,v]] : [])),
},
/*
'Pick (list)': {
objix: () => ob.pick(['s1','s2','s3']),
lodash: () => _.pick(ob,['s1','s2','s3']),
vanilla: () => Object.fromEntries(Object.entries(ob).flatMap(([k,v]) => ['s1','s2','s3'].includes(k) ? [[k,v]] : [])),
},
*/
Find: {
objix: () => ob.find(v => v == 1),
lodash: () => _.findKey(ob, v => v == 1),
vanilla: () => { for (let [k,v] of Object.entries(ob)) if (v == 1) return k },
},
FlatMap: {
objix: () => ob.flatMap((k,v) => [[k,v],[k+1, v+1]]),
lodash: () => Object.fromEntries(_.flatMap(ob, (v,k) => [[k,v],[k+1, v+1]])),
/*
_lodash: () => {
let r = {}
for (let [k,v] of _.flatMap(ob, (v,k) => [[k,v],[k+1, v+1]])) r[k] = v
return r
}
*/
//vanilla: () => { for (let [k,v] of Object.entries(ob)) if (v == 1) return k },
},
Has: {
objix: () => ob.has(3),
lodash: () => _.includes(ob, 3),
vanilla: () => Object.values(ob).includes(3)
},
KeyBy: {
objix: () => [{a:1},{a:2},{a:3}].keyBy('a'),
lodash: () => _.keyBy([{a:1},{a:2},{a:3}], 'a'),
},
Equals: {
objix: () => ob.eq(ob.clone(), -1),
lodash: () => _.isEqual(ob, ob.clone()),
vanilla: () => { try { return assert.deepEqual(ob,ob.clone()) || true } catch { return false }},
},
Clone: {
objix: () => ob.clone(),
lodash: () => _.clone(ob),
vanilla: () => Object.assign({}, ob), //No Construcotrs!
},
Deep: {
objix: () => ob.clone(-1),
vanilla: typeof structuredClone !== 'undefined' ? () => structuredClone(ob) : null,
lodash: () => _.cloneDeep(ob),
},
Extend: {
objix: () => ob.extend({a: 1, b: 2, c: 3}),
lodash: () => _.defaults(ob, {a: 1, b:2, c: 2}),
vanilla: () => Object.assign({}, {a: 1, b: 2, c: 3}, ob)
},
Some: {
objix: () => ob.some(v => v == 'x'),
vanilla: () => Object.values(ob).some(v => v == 'x'),
lodash: () => _.some(_.values(ob), v => v == 'x'),
},
Every: {
objix: () => ob.every(v => v),
lodash: () => _.every(_.values(ob), v => v),
vanilla: () => Object.values(ob).every(v => v),
}
}.map(compare))
}
const d1 = new Date()
const d2 = new Date()
const testOb = { }
//const deepOb = { a: { b: { c: [1, 2, 3], d: d1, e:[] }}}
const deepOb = { a: { b: [ 1,2,3,d1, { c: 0, d: d2 }], e:1, f:2, g: 3, h: 4, i: 5, j: []}}
for (let i=0; i < nSimp; i++) testOb['s'+i] = i
for (let i=0; i < nDeep; i++) testOb['d'+i] = deepOb
report(`Ops/sec (iters: ${iters}, heats: ${heats}, simple: ${nSimp}, complex: ${nDeep})`, testOb)