During testing a memory mapped vector wrapper class, it became obvious that the same property accessor code attached to numeric properties is at least 100x slower than if attached to non-numeric properties:
class Vec2 {
constructor(buf, off) {
this.buf = new Float32Array(buf, off, 2);
}
get x() {
return this.buf[0];
}
get y() {
return this.buf[1];
}
set x(x) {
this.buf[0] = x;
}
set y(y) {
this.buf[1] = y;
}
get "0"() {
return this.buf[0];
}
get "1"() {
return this.buf[1];
}
set "0"(x) {
this.buf[0] = x;
}
set "1"(y) {
this.buf[1] = y;
}
}
const bench = require("@thi.ng/bench").bench;
const tx = require("@thi.ng/transducers");
const N = 10000;
const buf = new Float32Array(N * 2).fill(1);
const pts = [...tx.map((i) => new Vec2(buf.buffer, i * 8), tx.range(N))];
const updateXY = () => {
for (let i = 0; i < N; i++) {
pts[i].x += 1;
pts[i].y += 2;
}
};
const update01 = () => {
for (let i = 0; i < N; i++) {
pts[i]["0"] += 1;
pts[i]["1"] += 2;
}
};
bench(updateXY, 1000);
// 58ms
bench(update01, 1000);
// 6604ms
Could anyone care to explain possible reasons? For this specific case here, a possible workaround is extending the class from Float32Array, which does make a noticeable difference (both versions now ~70ms), but my question is more general...
class Vec2 extends Float32Array {
constructor(buf, off) {
super(buf, off, 2);
}
get x() {
return this[0];
}
get y() {
return this[1];
}
set x(x) {
this[0] = x;
}
set y(y) {
this[1] = y;
}
}