Skip to content

Instantly share code, notes, and snippets.

@slavafomin
Last active January 9, 2024 18:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save slavafomin/b5074e1473295ad5f9c931de0d5311fb to your computer and use it in GitHub Desktop.
Save slavafomin/b5074e1473295ad5f9c931de0d5311fb to your computer and use it in GitHub Desktop.
JavaScript bytes copy benchmark (Uint8Array)

The most optimal way to copy bytes in JavaScript (Uint8Array)

Please read my post in Telegram: Don't use spread operator with byte arrays

Short summary

  1. Use target.set(source, offset) MDN
  2. Pre-alocate the entire array once
  3. Don't use ...spread operator with bytes

Also, tinybench is a great modern library to do benchmarks.

import { randomBytes } from 'node:crypto';
import { Bench, hrtimeNow } from 'tinybench';
const bench = new Bench({
time: 1_000,
now: hrtimeNow,
});
const bytes1 = randomBytes(5_000);
const bytes2 = randomBytes(3_000);
const bytes3 = randomBytes(2_000);
const totalSize = (
bytes1.length +
bytes2.length +
bytes3.length
);
(bench
.add('bytes.set', () => {
const result = new Uint8Array(totalSize);
result.set(bytes1, 0);
result.set(bytes2, bytes1.length);
result.set(bytes3, bytes1.length + bytes2.length);
})
.add('bytes.set (stages)', () => {
let result = new Uint8Array();
result = append(result, bytes1);
result = append(result, bytes2);
result = append(result, bytes3);
function append(
bytes1: Uint8Array,
bytes2: Uint8Array
): Uint8Array {
const result = new Uint8Array(
bytes1.length +
bytes2.length
);
result.set(bytes1, 0);
result.set(bytes2, bytes1.length);
return result;
}
})
.add('bytes ...spread', async () => {
new Uint8Array([
...bytes1,
...bytes2,
...bytes3,
]);
})
.add('bytes writer', async () => {
// Uses bytes.set under the hood,
// but enables more readable code.
// -----
const writer = new BytesWriter({
size: totalSize,
});
(writer
.writeBytes(bytes1)
.writeBytes(bytes2)
.writeBytes(bytes3)
);
})
);
await bench.warmup();
await bench.run();
console.table(
bench.table()
);
[10,000 BYTES]
┌──────────────────────┬───────────┬─────────────────┬──────────┬─────────┐
│ Task Name │ ops/sec │ Avg. Time (ns) │ Margin │ Samples │
├──────────────────────┼───────────┼─────────────────┼──────────┼─────────┤
│ bytes.set │ 674,823 │ 1481.86 │ '±0.50%' │ 674,827 │ <----- WINNER
│ bytes ...spread │ 4,504 │ 221985.41 │ '±0.20%' │ 4,505 │ 149.82 times slower
│ bytes.set (stages) │ 235,420 │ 4247.71 │ '±0.91%' │ 235,421 │ 2.86 times slower
│ bytes writer │ 583,673 │ 1713.28 │ '±0.52%' │ 583,674 │ 1.15 times slower
└──────────────────────┴───────────┴─────────────────┴──────────┴─────────┘
[1,000 BYTES]
┌──────────────────────┬───────────┬─────────────────┬──────────┬─────────┐
│ Task Name │ ops/sec │ Avg. Time (ns) │ Margin │ Samples │
├──────────────────────┼───────────┼─────────────────┼──────────┼─────────┤
│ bytes.set │ 801,084 │ 1248.30 │ '±2.21%' │ 801,085 │ <----- WINNER
│ bytes ...spread │ 43,298 │ 23095.55 │ '±0.16%' │ 43,299 │ 18.50 times slower
│ bytes.set (stages) │ 252,794 │ 3955.78 │ '±3.43%' │ 252,795 │ 3.16 times slower
│ bytes writer │ 692,139 │ 1444.79 │ '±3.35%' │ 692,140 │ 1.15 times slower
└──────────────────────┴───────────┴─────────────────┴──────────┴─────────┘
[100 BYTES]
┌──────────────────────┬─────────────┬─────────────────┬──────────┬───────────┐
│ Task Name │ ops/sec │ Avg. Time (ns) │ Margin │ Samples │
├──────────────────────┼─────────────┼─────────────────┼──────────┼───────────┤
│ bytes.set │ 2,088,572 │ 478.79 │ '±0.28%' │ 2,088,573 │ <----- WINNER
│ bytes ...spread │ 319,625 │ 3128.66 │ '±0.25%' │ 319,626 │ 6.50 times slower
│ bytes.set (stages) │ 852,849 │ 1172.53 │ '±0.27%' │ 852,853 │ 2.44 times slower
│ bytes writer │ 1,269,895 │ 787.46 │ '±0.24%' │ 1,269,897 │ 1.64 times slower
└──────────────────────┴─────────────┴─────────────────┴──────────┴───────────┘

Was this helpful?

Please add a star. Also, join my Telegram channel for more useful guides and insights on JavaScript/TypeScript development.

Have questions/feedback?

Be my guest to comment in the section below or under posts in my Telegram channel.

Need professional consultancy? You can contact me directly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment