mirror of
https://github.com/nodejs/node.git
synced 2026-11-09 15:11:11 -05:00
stream: construct stream/iter byte view snapshots and batch entries
createBatchEntry() and recordChunk() snapshot every chunk in a
seven-property `{ __proto__: null, ... }` literal, and every batch gets
a `{ __proto__: null, views, byteLength }` record. V8 creates such
literals in dictionary mode, which is expensive for objects created
for every chunk.
Create them with constructors whose prototype is an empty, frozen,
null-prototype object instead, as for IterResult. They have fast
properties and a single shape, and are only used internally.
Writing 1e6 16-byte chunks into a push() stream and reading them back
is about 6x faster with writeSync(), 3.7x faster with writevSync() (4
chunks per call) and 1.7x faster with string chunks.
benchmark/streams/iter-throughput-share-sync.js improves by 67-93%,
iter-throughput-share.js by 4-8%, and iter-throughput-broadcast.js
with 4 consumers by 8%. pipeTo() with small chunks is about 1.5x
faster.
Assisted-by: OpenCode
Signed-off-by: James M Snell <jasnell@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/66648
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
This commit is contained in:
1 parent
724190cfdc
commit
e6c9c8eecd
1 file changed
+28
-17
@@ -217,23 +217,35 @@ function toUint8Array(chunk) {
|
||||
return chunk;
|
||||
}
|
||||
|
||||
// Byte view snapshots and batch entries are created for every chunk and
|
||||
// every batch, so like IterResult they are constructed rather than created
|
||||
// as `{ __proto__: null, ... }` literals (which are dictionary-mode objects),
|
||||
// and their prototype is an empty null-prototype object.
|
||||
function ByteViewSnapshot(value, buffer, sharedBufferView) {
|
||||
this.value = value;
|
||||
this.buffer = buffer;
|
||||
this.bufferByteLength = sharedBufferView === undefined ?
|
||||
ArrayBufferPrototypeGetByteLength(buffer) :
|
||||
TypedArrayPrototypeGetByteLength(sharedBufferView);
|
||||
this.byteLength = TypedArrayPrototypeGetByteLength(value);
|
||||
this.byteOffset = TypedArrayPrototypeGetByteOffset(value);
|
||||
this.detached = sharedBufferView === undefined &&
|
||||
ArrayBufferPrototypeGetDetached(buffer);
|
||||
this.sharedBufferView = sharedBufferView;
|
||||
}
|
||||
ByteViewSnapshot.prototype = ObjectFreeze({ __proto__: null });
|
||||
|
||||
function BatchEntry(views, byteLength) {
|
||||
this.views = views;
|
||||
this.byteLength = byteLength;
|
||||
}
|
||||
BatchEntry.prototype = ObjectFreeze({ __proto__: null });
|
||||
|
||||
function snapshotByteView(value) {
|
||||
const buffer = TypedArrayPrototypeGetBuffer(value);
|
||||
const sharedBufferView = isSharedArrayBuffer(buffer) ?
|
||||
new Uint8Array(buffer) : undefined;
|
||||
return {
|
||||
__proto__: null,
|
||||
value,
|
||||
buffer,
|
||||
bufferByteLength: sharedBufferView === undefined ?
|
||||
ArrayBufferPrototypeGetByteLength(buffer) :
|
||||
TypedArrayPrototypeGetByteLength(sharedBufferView),
|
||||
byteLength: TypedArrayPrototypeGetByteLength(value),
|
||||
byteOffset: TypedArrayPrototypeGetByteOffset(value),
|
||||
detached: sharedBufferView === undefined &&
|
||||
ArrayBufferPrototypeGetDetached(buffer),
|
||||
sharedBufferView,
|
||||
};
|
||||
return new ByteViewSnapshot(value, buffer, sharedBufferView);
|
||||
}
|
||||
|
||||
function validateByteView(snapshot) {
|
||||
@@ -325,7 +337,7 @@ function createBatchEntry(chunks) {
|
||||
views[i] = view;
|
||||
byteLength += view.byteLength;
|
||||
}
|
||||
return { __proto__: null, views, byteLength };
|
||||
return new BatchEntry(views, byteLength);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -345,15 +357,14 @@ function splitBatchEntry(entry, limit) {
|
||||
for (let i = 0; i < views.length; i++) {
|
||||
const view = views[i];
|
||||
if (current.length > 0 && byteLength + view.byteLength >= limit) {
|
||||
ArrayPrototypePush(entries,
|
||||
{ __proto__: null, views: current, byteLength });
|
||||
ArrayPrototypePush(entries, new BatchEntry(current, byteLength));
|
||||
current = [];
|
||||
byteLength = 0;
|
||||
}
|
||||
ArrayPrototypePush(current, view);
|
||||
byteLength += view.byteLength;
|
||||
}
|
||||
ArrayPrototypePush(entries, { __proto__: null, views: current, byteLength });
|
||||
ArrayPrototypePush(entries, new BatchEntry(current, byteLength));
|
||||
return entries;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user