var bench1buffer;
var bench2buffer;
var bench3buffer;
var size = 1_000_000;
{
const stride = 10;
bench1buffer = new ArrayBuffer(stride * size);
/*
0 u16 id
2 f32 x
6 f32 y
*/
for (let i = 0; i < size; i++) {
const struct = new DataView(bench1buffer, i * stride, stride);
struct.setUint16(0, i, true);
struct.setFloat32(2, i, true);
struct.setFloat32(6, i * 2, true);
}
}
{
const stride = 12;
bench2buffer = new ArrayBuffer(stride * size);
/*
0 u16 id
4 f32 x
8 f32 y
*/
for (let i = 0; i < size; i++) {
const struct = new DataView(bench2buffer, i * stride, stride);
struct.setUint16(0, i, true);
struct.setFloat32(4, i, true);
struct.setFloat32(8, i * 2, true);
}
}
{
bench3buffer = {
id: new Uint16Array(size),
x: new Float32Array(size),
y: new Float32Array(size),
};
for (let i = 0; i < size; i++) {
bench3buffer.id[i] = i;
bench3buffer.x[i] = i;
bench3buffer.y[i] = i * 2;
}
}
const stride = 10;
/*
0 u16 id
2 f32 x
6 f32 y
*/
let sum = 0;
for (let i = 0; i < size; i++) {
const struct = new DataView(bench1buffer, i * stride, stride);
const id = struct.getUint16(0, true);
const x = struct.getFloat32(2, true);
const y = struct.getFloat32(6, true);
sum += id + x * y;
}
console.log(1, sum);
const stride = 12;
/*
0 u16 id
4 f32 x
8 f32 y
*/
let sum = 0;
for (let i = 0; i < size; i++) {
const struct = new DataView(bench2buffer, i * stride, stride);
const id = struct.getUint16(0, true);
const x = struct.getFloat32(4, true);
const y = struct.getFloat32(8, true);
sum += id + x * y;
}
console.log(2, sum);
const stride = 12;
/*
0 u16 id
4 f32 x
8 f32 y
*/
const f32s = new Float32Array(bench2buffer);
const u16s = new Uint16Array(bench2buffer);
let sum = 0;
for (let i = 0; i < size; i++) {
const offset = i * stride;
const id = u16s[offset / 2];
const x = f32s[offset / 4 + 1];
const y = f32s[offset / 4 + 2];
sum += id + x * y;
}
console.log(3, sum);
let sum = 0;
const idbuf = bench3buffer.id;
const xbuf = bench3buffer.x;
const ybuf = bench3buffer.y;
for (let i = 0; i < size; i++) {
const id = idbuf[i];
const x = xbuf[i];
const y = ybuf[i];
sum += id + x * y;
}
console.log(3, sum);
--enable-precise-memory-info
flag.
Test case name | Result |
---|---|
DataView AoS | |
DataView byte-aligned AoS | |
TypedArray byte-aligned AoS | |
TypeArray SoA |
Test name | Executions per second |
---|---|
DataView AoS | 3.0 Ops/sec |
DataView byte-aligned AoS | 3.0 Ops/sec |
TypedArray byte-aligned AoS | 14.9 Ops/sec |
TypeArray SoA | 14.9 Ops/sec |
Let's break down the provided benchmark and explain what's being tested, compared, and their pros and cons.
Benchmark Overview
The benchmark measures the performance of accessing data in various formats: Array of Structures (AoS), DataView AoS, TypedArray byte-aligned AoS, and TypeArray SoA. Each test case accesses a large array of 1 million elements with different stride sizes (10, 12, and 12).
What's being tested
The benchmark tests the performance of accessing data in different formats:
DataView
to access each element individually. This is compared to other approaches.Float32Array
and Uint16Array
with optimized indexing for byte-aligned access.id
, x
, y
) is stored separately.Comparison of approaches
The benchmark compares the performance of three main approaches:
DataView
to access each element individually. The pros are:Float32Array
and Uint16Array
with optimized indexing for byte-aligned access. The pros are:DataView
.
However, the cons are:Benchmark Results
The latest benchmark results show the performances of each approach:
TestName | ExecutionsPerSecond |
---|---|
TypeArray SoA | 14.944602012634277 |
TypedArray byte-aligned AoS | 14.940752029418945 |
DataView byte-aligned AoS | 3.0188679695129395 |
DataView AoS | 3.0090270042419434 |
The results indicate that the TypeArray SoA approach is the fastest, followed closely by TypedArray byte-aligned AoS. The original DataView approaches are significantly slower.
Conclusion
In conclusion, the benchmark highlights the importance of choosing the right data access pattern and memory layout for performance-critical applications. While DataView AoS is simple to implement, it's slower than other optimized approaches like TypedArray byte-aligned AoS and TypeArray SoA. By understanding the trade-offs between these approaches, developers can make informed decisions about which one to use based on their specific requirements.