From 74291e4a7ba6185c1b78a110538ed3db3bc6b244 Mon Sep 17 00:00:00 2001 From: Brian White Date: Sun, 2 Feb 2020 10:49:30 -0500 Subject: [PATCH] buffer: improve from() performance PR-URL: https://github.com/nodejs/node/pull/31615 Reviewed-By: James M Snell Reviewed-By: Anna Henningsen --- benchmark/buffers/buffer-from.js | 54 ++++++++++++++++++++++---------- lib/buffer.js | 29 ++++++++--------- 2 files changed, 51 insertions(+), 32 deletions(-) diff --git a/benchmark/buffers/buffer-from.js b/benchmark/buffers/buffer-from.js index 1df1b5b362fefa..d0f7d42f5e4369 100644 --- a/benchmark/buffers/buffer-from.js +++ b/benchmark/buffers/buffer-from.js @@ -12,37 +12,37 @@ const bench = common.createBenchmark(main, { 'string-utf8', 'string-base64', 'object', + 'uint8array', + 'uint16array', ], len: [100, 2048], n: [8e5] }); function main({ len, n, source }) { - const array = new Array(len).fill(42); - const arrayBuf = new ArrayBuffer(len); - const str = 'a'.repeat(len); - const buffer = Buffer.allocUnsafe(len); - const uint8array = new Uint8Array(len); - const obj = { length: null }; // Results in a new, empty Buffer - let i = 0; switch (source) { - case 'array': + case 'array': { + const array = new Array(len).fill(42); bench.start(); for (i = 0; i < n; i++) { Buffer.from(array); } bench.end(n); break; - case 'arraybuffer': + } + case 'arraybuffer': { + const arrayBuf = new ArrayBuffer(len); bench.start(); for (i = 0; i < n; i++) { Buffer.from(arrayBuf); } bench.end(n); break; - case 'arraybuffer-middle': + } + case 'arraybuffer-middle': { + const arrayBuf = new ArrayBuffer(len); const offset = ~~(len / 4); const length = ~~(len / 2); bench.start(); @@ -51,48 +51,70 @@ function main({ len, n, source }) { } bench.end(n); break; - case 'buffer': + } + case 'buffer': { + const buffer = Buffer.allocUnsafe(len); bench.start(); for (i = 0; i < n; i++) { Buffer.from(buffer); } bench.end(n); break; - case 'uint8array': + } + case 'uint8array': { + const uint8array = new Uint8Array(len); bench.start(); for (i = 0; i < n; i++) { Buffer.from(uint8array); } bench.end(n); break; - case 'string': + } + case 'uint16array': { + const uint16array = new Uint16Array(len); + bench.start(); + for (i = 0; i < n; i++) { + Buffer.from(uint16array); + } + bench.end(n); + break; + } + case 'string': { + const str = 'a'.repeat(len); bench.start(); for (i = 0; i < n; i++) { Buffer.from(str); } bench.end(n); break; - case 'string-utf8': + } + case 'string-utf8': { + const str = 'a'.repeat(len); bench.start(); for (i = 0; i < n; i++) { Buffer.from(str, 'utf8'); } bench.end(n); break; - case 'string-base64': + } + case 'string-base64': { + const str = 'a'.repeat(len); bench.start(); for (i = 0; i < n; i++) { Buffer.from(str, 'base64'); } bench.end(n); break; - case 'object': + } + case 'object': { + const obj = { length: null }; // Results in a new, empty Buffer bench.start(); for (i = 0; i < n; i++) { Buffer.from(obj); } bench.end(n); break; + } default: assert.fail('Should not get here'); } diff --git a/lib/buffer.js b/lib/buffer.js index bf7ae972eff6e5..d83a5a30d9e1b8 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -452,14 +452,6 @@ function fromString(string, encoding) { return fromStringFast(string, ops); } -function fromArrayLike(obj) { - const length = obj.length; - const b = allocate(length); - for (let i = 0; i < length; i++) - b[i] = obj[i]; - return b; -} - function fromArrayBuffer(obj, byteOffset, length) { // Convert byteOffset to integer if (byteOffset === undefined) { @@ -491,17 +483,22 @@ function fromArrayBuffer(obj, byteOffset, length) { return new FastBuffer(obj, byteOffset, length); } -function fromObject(obj) { - if (isUint8Array(obj)) { - const b = allocate(obj.length); - - if (b.length === 0) - return b; - - _copy(obj, b, 0, 0, obj.length); +function fromArrayLike(obj) { + if (obj.length <= 0) + return new FastBuffer(); + if (obj.length < (Buffer.poolSize >>> 1)) { + if (obj.length > (poolSize - poolOffset)) + createPool(); + const b = new FastBuffer(allocPool, poolOffset, obj.length); + b.set(obj, 0); + poolOffset += obj.length; + alignPool(); return b; } + return new FastBuffer(obj); +} +function fromObject(obj) { if (obj.length !== undefined || isAnyArrayBuffer(obj.buffer)) { if (typeof obj.length !== 'number') { return new FastBuffer();