jsPerf.app is an online JavaScript performance benchmark test runner & jsperf.com mirror. It is a complete rewrite in homage to the once excellent jsperf.com now with hopefully a more modern & maintainable codebase.
jsperf.com URLs are mirrored at the same path, e.g:
https://jsperf.com/negative-modulo/2
Can be accessed at:
https://jsperf.app/negative-modulo/2
const BUFFER_SIZE_1 = 256;
const BUFFER_SIZE_2 = 320;
const SIMULATION_CYCLES = 100;
const testData = [];
for (let i = 0; i < SIMULATION_CYCLES; i++) {
const buffer = new Float32Array(BUFFER_SIZE_1);
for (let j = 0; j < BUFFER_SIZE_1; j++) {
buffer[j] = Math.random();
}
testData[i] = buffer;
}
class TestRingBuffer {
constructor(size, useNativeAPI = true) {
this.buffer = new Float32Array(size);
this.size = size;
this.writePos = 0;
this.readPos = 0;
this.useNativeAPI = useNativeAPI;
}
getAvailableSpace() {
return (this.readPos - this.writePos - 1 + this.size) % this.size;
}
getDataLength() {
return (this.writePos - this.readPos + this.size) % this.size;
}
write(data) {
const availableSpace = this.getAvailableSpace();
if (availableSpace < data.length) {
// Handle overflow - advance read position
const samplesToAdvance = Math.max(data.length - availableSpace + 4, 4);
const alignedAdvance = Math.ceil(samplesToAdvance / 4) * 4;
this.readPos = (this.readPos + alignedAdvance) % this.size;
}
if (this.useNativeAPI) {
// Native API approach
if (this.writePos + data.length <= this.size) {
this.buffer.set(data, this.writePos);
this.writePos += data.length;
} else {
const partitionSizeFormer = this.size - this.writePos;
const partitionSizeLatter = data.length - partitionSizeFormer;
const dataViewFormer = new Float32Array(
data.buffer, data.byteOffset, partitionSizeFormer
);
const dataViewLatter = new Float32Array(
data.buffer,
data.byteOffset + Float32Array.BYTES_PER_ELEMENT * partitionSizeFormer,
partitionSizeLatter
);
this.buffer.set(dataViewFormer, this.writePos);
this.buffer.set(dataViewLatter, 0);
this.writePos = partitionSizeLatter;
}
} else {
// Manual loop approach
for (let i = 0; i < data.length; i++) {
this.buffer[this.writePos] = data[i];
this.writePos = (this.writePos + 1) % this.size;
}
}
}
read(length) {
const availableData = this.getDataLength();
const samplesToRead = Math.min(length, availableData);
if (samplesToRead === 0) {
return new Float32Array(0);
}
if (this.useNativeAPI) {
// Native API approach
if (this.readPos + samplesToRead <= this.size) {
const result = this.buffer.subarray(this.readPos, this.readPos + samplesToRead);
this.readPos += samplesToRead;
return result;
}
const result = new Float32Array(samplesToRead);
const partitionSizeFormer = this.size - this.readPos;
const partitionSizeLatter = samplesToRead - partitionSizeFormer;
result.set(this.buffer.subarray(this.readPos, this.size), 0);
result.set(this.buffer.subarray(0, partitionSizeLatter), partitionSizeFormer);
this.readPos = partitionSizeLatter;
return result;
} else {
// Manual loop approach
const result = new Float32Array(samplesToRead);
for (let i = 0; i < samplesToRead; i++) {
result[i] = this.buffer[this.readPos];
this.readPos = (this.readPos + 1) % this.size;
}
return result;
}
}
reset() {
this.writePos = 0;
this.readPos = 0;
}
}
let ringBuffer = null;
function startTest() {
for (let cycle = 0; cycle < SIMULATION_CYCLES; cycle++) {
ringBuffer.write(testData[cycle]);
}
}
Ready to run.
| Test | Ops/sec | |
|---|---|---|
| Write - Native API (512) | | ready |
| Write - Manual Loop | | ready |
| Write - Native API (1024) | | ready |
| Write - Native API (2048) | | ready |
| Write - Native API (4096) | | ready |
You can edit these tests or add more tests to this page by appending /edit to the URL.