performance: Blob.text and Blob.arraybuffer are 10x+ slower on 20.x

The blob/blob.js benchmark is taking hours: https://ci.nodejs.org/view/Node.js benchmark/job/benchmark-node-micro-benchmarks/1402/console

This probably didn’t take so long in the past, there is this PR that changed the Blob’s behavior a lot: https://github.com/nodejs/node/pull/45258/

From what I saw, the problem is in the JS->C++ transitions, for each piece of data it crosses JS->C++.

Furthermore, the text function expects arraybuffer and then calls decode, when we could just decode the data as soon as we get it from the C++ instead of keeping everything in memory and then discarding it.

I can do some optimizations on the JS side but I think this could be largely improved if we do the heavy operations on C++, I have no idea how to handle the asynchronous code on C++, so I accept some hints or if anyone wants to try work on this.

About this issue

  • Original URL
  • State: open
  • Created 9 months ago
  • Comments: 15 (15 by maintainers)

Commits related to this issue

Most upvoted comments

This will be a tricky one as the new mechanism underlying the C++ implementation of Blob is also going to be used for the QUIC implementation that I’m currently working on. It also serves as the underlying bit for file-backed Blob. There is lots of room for performance improvement here but I would appreciate this not being changed right at this moment as it could lead to conflicts with the ongoing QUIC implementation work. What would probably be the most valuable right now would be just identifying where the key bottlenecks – identifying those so that we can circle back around to making those pieces faster.

Some benchmark data:

NodeJS 16.20.1

name ops/sec samples
text (128) 17,269 57
text (1024) 10,257 57
arrayBuffer (128) 24,974 53
arrayBuffer (1024) 10,955 57
slice (0, 64) 48,310 67
slice (0, 512) 23,750 66

NodeJS 18.17.0

name ops/sec samples
text (128) 36,176 74
text (1024) 13,691 69
arrayBuffer (128) 36,788 74
arrayBuffer (1024) 14,305 75
slice (0, 64) 49,139 71
slice (0, 512) 26,774 76

NodeJS 20.5.0

name ops/sec samples
text (128) 3,194 74
text (1024) 380 76
arrayBuffer (128) 3,478 80
arrayBuffer (1024) 407 75
slice (0, 64) 45,076 66
slice (0, 512) 16,484 64

just stuck on how to make the pulling part async similar to how we are doing queueMicrotask in js in cpp, Is there maybe some sort of way to queue jobs in c++ part

Pretty sure you were looking for v8::Isolate::EnqueueMicrotask