Skip to content

Instantly share code, notes, and snippets.

@pfrazee
Created July 15, 2021 16:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pfrazee/4a1962cbfc771e42983ae4790b7b6ac5 to your computer and use it in GitHub Desktop.
Save pfrazee/4a1962cbfc771e42983ae4790b7b6ac5 to your computer and use it in GitHub Desktop.

Encoding benchmark in nodejs

Results:

---
Benching json
Encoding 6 values 10000 times: 58ms
Sizes: 14b, 14b, 18b, 42b, 91b, 196b
Decoding 6 values 10000 times: 73ms
---
Benching bson
Encoding 6 values 10000 times: 212ms
Sizes: 13b, 16b, 23b, 40b, 85b, 182b
Decoding 6 values 10000 times: 207ms
---
Benching bsonExt
Encoding 6 values 10000 times: 425ms
Sizes: 13b, 16b, 23b, 40b, 85b, 182b
Decoding 6 values 10000 times: 202ms
---
Benching cbor
Encoding 6 values 10000 times: 1461ms
Sizes: 8b, 10b, 14b, 28b, 60b, 131b
Decoding 6 values 10000 times: 1803ms
---
Benching json + gzip
Encoding 6 values 10000 times: 8411ms
Sizes: 34b, 34b, 38b, 62b, 73b, 85b
Decoding 6 values 10000 times: 739ms
---
Benching bson + gzip
Encoding 6 values 10000 times: 8701ms
Sizes: 33b, 35b, 41b, 57b, 67b, 80b
Decoding 6 values 10000 times: 749ms
---
Benching bsonExt + gzip
Encoding 6 values 10000 times: 9490ms
Sizes: 33b, 35b, 41b, 57b, 67b, 80b
Decoding 6 values 10000 times: 1442ms
---
Benching cbor + gzip
Encoding 6 values 10000 times: 12901ms
Sizes: 28b, 30b, 34b, 48b, 55b, 66b
Decoding 6 values 10000 times: 2769ms

Thoughts:

  • gzipSync is pretty slow, is that a bug in my code?
  • bsonExt is a native module; you'd expect perf improvements over bson but the JS/native barrier must be slowing it down. It might see better perf than BSON on larger objects? Not sure
  • cbor's native module, tinycbor, failed to compile so it didnt get tested
  • compression only gets useful after ~80b, which is expected
import bson from 'bson'
import bsonExt from 'bson-ext'
import cbor from 'cbor'
import { gzipSync, gunzipSync } from 'zlib'
const VALUES = [
{value: true},
{value: 1234},
{value: 'string'},
{foo: 'bar', thisIs: 1234, another: true},
{foo: 'bar', thisIs: 1234, another: true, sub: {foo: 'bar', thisIs: 1234, another: true}},
{foo: 'bar', thisIs: 1234, another: true, sub1: {foo: 'bar', thisIs: 1234, another: true}, sub2: {foo: 'bar', thisIs: 1234, another: true, sub2sub1: {foo: 'bar', thisIs: 1234, another: true}}}
]
const CANDIDATES = {
json: {
encode: v => JSON.stringify(v),
decode: v => JSON.parse(v)
},
bson: {
encode: v => bson.serialize(v),
decode: v => bson.deserialize(v)
},
bsonExt: {
encode: v => bsonExt.serialize(v),
decode: v => bsonExt.deserialize(v)
},
cbor: {
encode: v => cbor.encodeOne(v),
decode: v => cbor.decodeFirstSync(v)
}
}
let acc = []
let ENCODINGS = {
json: [],
bson: [],
bsonExt: [],
cbor: []
}
for (let can in CANDIDATES) {
console.log('---')
console.log('Benching', can)
let start = Date.now()
for (let value of VALUES) {
for (let i = 0; i < 10000; i++) {
if (i === 0) ENCODINGS[can].push(CANDIDATES[can].encode(value))
else acc.push(CANDIDATES[can].encode(value))
}
}
console.log('Encoding', VALUES.length, 'values 10000 times:', `${Date.now() - start}ms`)
console.log('Sizes:', ENCODINGS[can].map(enc => bytes(enc)).join(', '))
start = Date.now()
for (let encoding of ENCODINGS[can]) {
for (let i = 0; i < 10000; i++) {
acc.push(CANDIDATES[can].decode(encoding))
}
}
console.log('Decoding', VALUES.length, 'values 10000 times:', `${Date.now() - start}ms`)
}
ENCODINGS = {
json: [],
bson: [],
bsonExt: [],
cbor: []
}
for (let can in CANDIDATES) {
console.log('---')
console.log('Benching', can, '+ gzip')
let start = Date.now()
for (let value of VALUES) {
for (let i = 0; i < 10000; i++) {
if (i === 0) ENCODINGS[can].push(gzipSync(CANDIDATES[can].encode(value)))
else acc.push(gzipSync(CANDIDATES[can].encode(value)))
}
}
console.log('Encoding', VALUES.length, 'values 10000 times:', `${Date.now() - start}ms`)
console.log('Sizes:', ENCODINGS[can].map(enc => bytes(enc)).join(', '))
start = Date.now()
for (let encoding of ENCODINGS[can]) {
for (let i = 0; i < 10000; i++) {
let v = gunzipSync(encoding)
if (can === 'json') v = v.toString('utf8')
acc.push(CANDIDATES[can].decode(v))
}
}
console.log('Decoding', VALUES.length, 'values 10000 times:', `${Date.now() - start}ms`)
}
function bytes (v) {
if (typeof v === 'string') return `${(new TextEncoder().encode(v)).length}b`
return `${v.byteLength}b`
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment