darrachequesne / notepack

A fast Node.js implementation of the latest MessagePack spec
MIT License
75 stars 19 forks source link

Why bytes.push instead of Buffer #12

Open manast opened 7 years ago

manast commented 7 years ago

I wonder why the encoder is using a standard js array and calls to push. Wouldn't be much faster to work using a Buffer? I understand the challenges of growing the buffer, but it should be much faster considering the overhead of a function call for every element written to the array.

darrachequesne commented 7 years ago

How would you know the size of the buffer to use beforehand? Currently, the object to encode is passed through to get the needed size, and then the content of the array (bytes) is written to the buffer.

manast commented 7 years ago

I would create a temporary buffer, maybe 8Kbs, and then grow a destination buffer (re-alloc & copy). For tiny objects it should be much faster than now. For larger ones depends on the overhead of growing the array, but V8 does something similar for arrays anyways so probably it will still be faster.

darrachequesne commented 7 years ago

That's interesting! Would you have time to implement it, so we can benchmark it against the current implementation?

manast commented 7 years ago

I will not really have time in the short term. I saw that this project uses the buffer approach, and it is very fast according to their benchmarks: https://github.com/phretaddin/schemapack/blob/master/schemapack.js

darrachequesne commented 7 years ago

I'll keep this open then, if anyone wants to submit a pull request.

baadc0de commented 6 years ago

There is a package that could be useful for that: https://github.com/rvagg/bl

davalapar commented 5 years ago

i tried the following changes:

tiny/small/medium test cases got improvements but on large, notepack still beats it. i am also wondering why i got different ops/sec on notepack on tiny, i was using node 10 on windows 7 x64.

https://github.com/davalapar/what-the-pack

darrachequesne commented 5 years ago

@davalapar impressive, great job! I think that it will be difficult to beat those numbers...

manast commented 5 years ago

@davalapar I am wondering, any insights on why decode did not get any improvement? Also, do you have benchmarks compared to JSON. stringify/parse? JSON is currently the fastest serializer for node, so it would be great if we could see how far we are from beating it.

darrachequesne commented 5 years ago

@davalapar it seems replacing new Buffer() by Buffer.allocUnsafe() (https://github.com/darrachequesne/notepack/commit/9224f74bf23f58ebd453b505ce755f128d0e6a63) (which uses an internal Buffer pool, ref) does improve the throughput! With the new version 2.2.0 I get the following results on my machine:

MessagePack: Setting buffer limit to 4.19 MB
what-the-pack encode tiny x 1,607,116 ops/sec ±1.56% (86 runs sampled)
notepack.encode tiny x 1,711,809 ops/sec ±2.78% (80 runs sampled)
what-the-pack encode small x 421,331 ops/sec ±2.72% (85 runs sampled)
notepack encode small x 373,340 ops/sec ±1.65% (85 runs sampled)
what-the-pack encode medium x 229,224 ops/sec ±2.80% (85 runs sampled)
notepack encode medium x 196,641 ops/sec ±1.57% (81 runs sampled)
what-the-pack encode large x 338 ops/sec ±0.97% (88 runs sampled)
notepack encode large x 310 ops/sec ±2.73% (79 runs sampled)

Way to go, but that's definitely better!

davalapar commented 5 years ago

@darrachequesne goddamn that's fricken awesome!

@manast

I am wondering, any insights on why decode did not get any improvement?

I think it's due to similar decoding implementation with notepack, which is same way of reading the buffer values and creating of objects and arrays. I had the crazy idea of inlining the equivalent of function calls such as readUInt16BE, readUInt16BE, thinking that it might speed up decoding since the ones here and here have checks that can be skipped, but I still haven't tried yet (maybe the numbers could check out, maybe not lol).

Also, do you have benchmarks compared to JSON. stringify/parse? JSON is currently the fastest serializer for node, so it would be great if we could see how far we are from beating it.

Results below, I'm on Windows 7 x64 with some open apps


JSON stringify tiny x 1,364,321 ops/sec ±0.91% (90 runs sampled) << what-the-pack encode tiny x 1,203,150 ops/sec ±2.65% (84 runs sampled) notepack.encode tiny x 237,295 ops/sec ±50.03% (83 runs sampled)

JSON stringify small x 219,199 ops/sec ±0.34% (92 runs sampled) what-the-pack encode small x 352,946 ops/sec ±0.58% (92 runs sampled) << notepack encode small x 239,186 ops/sec ±0.27% (91 runs sampled)

JSON stringify medium x 110,615 ops/sec ±1.82% (90 runs sampled) what-the-pack encode medium x 168,408 ops/sec ±1.35% (86 runs sampled) << notepack encode medium x 116,409 ops/sec ±0.26% (95 runs sampled)

JSON stringify large x 24.22 ops/sec ±0.52% (44 runs sampled) what-the-pack encode large x 204 ops/sec ±2.23% (77 runs sampled) notepack encode large x 226 ops/sec ±1.28% (80 runs sampled) <<

JSON parse tiny x 1,336,891 ops/sec ±0.40% (91 runs sampled) << what-the-pack decode tiny x 1,132,375 ops/sec ±0.56% (88 runs sampled) notepack decode tiny x 1,174,634 ops/sec ±0.26% (94 runs sampled)

JSON parse small x 267,013 ops/sec ±0.22% (96 runs sampled) << what-the-pack decode small x 249,414 ops/sec ±0.96% (93 runs sampled) notepack decode small x 252,664 ops/sec ±1.28% (93 runs sampled)

JSON parse medium x 134,864 ops/sec ±0.21% (95 runs sampled) what-the-pack decode medium x 143,053 ops/sec ±0.19% (94 runs sampled) notepack decode medium x 148,638 ops/sec ±0.91% (90 runs sampled) <<

JSON parse large x 31.81 ops/sec ±0.56% (54 runs sampled) what-the-pack decode large x 215 ops/sec ±0.24% (88 runs sampled) << notepack decode large x 214 ops/sec ±0.57% (82 runs sampled)


manast commented 5 years ago

@davalapar I think these are really interesting results. In some cases even faster than JSON, very encouraging.