|
var crypto = require('crypto'); |
|
var rounds = 5000; |
|
var arraySize = 10000; |
|
|
|
|
|
console.time('Random array generation (overhead)'); |
|
for (var i = 0; i < rounds; i++) { |
|
var buff = getRandomArray(); |
|
buff = null; |
|
} |
|
console.timeEnd('Random array generation (overhead)'); |
|
|
|
console.log(''); |
|
console.log('Create and Load in one step:'); |
|
console.time('Node Buffer'); |
|
for (var i = 0; i < rounds; i++) { |
|
var buff = new Buffer(getRandomArray()); |
|
buff = null; |
|
} |
|
console.timeEnd('Node Buffer'); |
|
|
|
console.time('ArrayBufferView (Uint8Array)'); |
|
for (var i = 0; i < rounds; i++) { |
|
var buff = new Uint8Array(getRandomArray()); |
|
buff = null; |
|
} |
|
console.timeEnd('ArrayBufferView (Uint8Array)'); |
|
|
|
console.log(''); |
|
console.log('Create, then Load:'); |
|
console.time('Node Buffer (Array access)'); |
|
for (var i = 0; i < rounds; i++) { |
|
var data = getRandomArray(); |
|
var buff = new Buffer(data.length); |
|
for (var x = 0; x < data.length; x++) { |
|
buff[x] = data[x]; |
|
} |
|
data = null; |
|
buff = null; |
|
} |
|
console.timeEnd('Node Buffer (Array access)'); |
|
|
|
console.time('Node Buffer (writeUInt8)'); |
|
for (var i = 0; i < rounds; i++) { |
|
var data = getRandomArray(); |
|
var buff = new Buffer(data.length); |
|
for (var x = 0; x < data.length; x++) { |
|
buff.writeUInt8(data[x], x); |
|
} |
|
data = null; |
|
buff = null; |
|
} |
|
console.timeEnd('Node Buffer (writeUInt8)'); |
|
|
|
console.time('ArrayBufferView (Uint8Array.set)'); |
|
for (var i = 0; i < rounds; i++) { |
|
var data = getRandomArray(); |
|
var i8 = new Uint8Array(data.length); |
|
i8.set(data); |
|
data = null; |
|
i8 = null; |
|
} |
|
console.timeEnd('ArrayBufferView (Uint8Array.set)'); |
|
|
|
console.time('ArrayBufferView (Uint8Array Array access)'); |
|
for (var i = 0; i < rounds; i++) { |
|
var data = getRandomArray(); |
|
var i8 = new Uint8Array(data.length); |
|
for (var x = 0; x < data.length; x++) { |
|
i8[x] = data[x]; |
|
} |
|
data = null; |
|
i8 = null; |
|
} |
|
console.timeEnd('ArrayBufferView (Uint8Array Array access)'); |
|
|
|
console.time('DataView'); |
|
for (var i = 0; i < rounds; i++) { |
|
var data = getRandomArray(); |
|
var i8 = new Uint8Array(data.length); |
|
var dv = new DataView(i8.buffer); |
|
for (var x = 0; x < data.length; x++) { |
|
dv.setUint8(x, data[x]); |
|
} |
|
data = null; |
|
i8 = null; |
|
dv = null; |
|
} |
|
console.timeEnd('DataView'); |
|
|
|
|
|
console.log(''); |
|
console.log('32-bit Big-endian numbers:'); |
|
console.time('Node Buffer'); |
|
for (var i = 0; i < rounds; i++) { |
|
var data = getRandomArray(); |
|
var buff = new Buffer(data.length); // Create |
|
for (var x = 0; x < data.length; x++) { |
|
buff[x] = data[x]; // Load |
|
} |
|
|
|
// Manipulate |
|
for (var x = 0; x < buff.length-10; x++) { |
|
buff.writeUInt32BE(buff.readUInt32BE(x+5), x); |
|
} |
|
data = null; |
|
buff = null; |
|
} |
|
console.timeEnd('Node Buffer'); |
|
|
|
console.time('DataView'); |
|
for (var i = 0; i < rounds; i++) { |
|
var data = getRandomArray(); |
|
var i8 = new Uint8Array(data.length); // Create |
|
for (var x = 0; x < data.length; x++) { |
|
i8[x] = data[x]; // Load |
|
} |
|
|
|
// Manipulate |
|
var buff = new DataView(i8.buffer); |
|
for (var x = 0; x < buff.byteLength-10; x++) { |
|
buff.setUint32(x, buff.getUint32(x+5), false); |
|
} |
|
data = null; |
|
buff = null; |
|
} |
|
console.timeEnd('DataView'); |
|
|
|
|
|
function getRandomArray() { |
|
var random = crypto.randomBytes(arraySize); |
|
return Array.prototype.slice.apply(random); |
|
} |
Hmmm, I am seeing a slowdown doing it that way, but I took a deeper look at the internals and found something else interesting:
It seems the generation of a Typed Array by initializing it and loading it at the same time is quite inefficient:
Initializing a Typed Array with an existing sequence object that's not another Typed Array (e.g. a vanilla Array or Buffer) seems to be a bottleneck. The "Array to ArrayBufferView" process (
new Uint8Array(new Array(arraySize))) is really slow (12,000ms), and using a Buffer (new Uint8Array(new Buffer(arraySize))) isn't much faster (9,500 ms). Using theset()method after being initialized seems to have the same issue. However, initializing (new Uint8Array(arraySize)) and then loading using the Typed Array's index accessors is much faster (550 ms).So, updating the tests to be:
I get results like:
So, I do see the "DataView" showing almost x2 "Node Buffer object" like you mentioned, but using a different init/load strategy drops that to x0.5 instead. Think that's another optimization taking effect?
I updated the
benchmark.jsfile in this gist with these updates if you want to re-run yourself!