From f71c03039f7f5ecfbf2289c2aa597fdf0dbbdee4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 12 May 2026 04:23:19 +0000 Subject: [PATCH 1/2] =?UTF-8?q?[Autoloop:=20tsb-perf-evolve]=20Iteration?= =?UTF-8?q?=2041:=20inverse=20IEEE-754=20gather=20=E2=80=94=20avoid=20rand?= =?UTF-8?q?om=20vals[]=20access?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the gather loop's `vals[origIdx]` random access into the JS array with an inverse IEEE-754 transform that reconstructs the float value directly from the already-sorted AoS key words (keyLo, keyHi) in srcBuf. The sorted AoS buffer is hot in cache after the final scatter pass; the original vals[] array is cold after the init loop. Replacing the random read with sequential reads + ~6 arithmetic ops should reduce cache pressure in the gather phase. Run: https://github.com/githubnext/tsessebe/actions/runs/25712799061 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/core/series.ts | 62 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 12 deletions(-) diff --git a/src/core/series.ts b/src/core/series.ts index 1b39cffc..c66e0b35 100644 --- a/src/core/series.ts +++ b/src/core/series.ts @@ -901,16 +901,34 @@ export class Series { if (allNumeric) { if (ascending) { for (let i = 0, si = 0; i < finCount; i++, si += 3) { - const idx = srcBuf[si]!; - perm[pos] = idx; - outData[pos] = vals[idx] as T; + const origIdx = srcBuf[si]!; + const keyLo = srcBuf[si + 1]!; + const keyHi = srcBuf[si + 2]!; + perm[pos] = origIdx; + if (keyHi & 0x80000000) { + _fvalsU32[0] = keyLo; + _fvalsU32[1] = (keyHi ^ 0x80000000) >>> 0; + } else { + _fvalsU32[0] = (~keyLo) >>> 0; + _fvalsU32[1] = (~keyHi) >>> 0; + } + outData[pos] = _fvals[0] as T; pos = pos + 1; } } else { for (let i = finCount - 1, si = (finCount - 1) * 3; i >= 0; i--, si -= 3) { - const idx = srcBuf[si]!; - perm[pos] = idx; - outData[pos] = vals[idx] as T; + const origIdx = srcBuf[si]!; + const keyLo = srcBuf[si + 1]!; + const keyHi = srcBuf[si + 2]!; + perm[pos] = origIdx; + if (keyHi & 0x80000000) { + _fvalsU32[0] = keyLo; + _fvalsU32[1] = (keyHi ^ 0x80000000) >>> 0; + } else { + _fvalsU32[0] = (~keyLo) >>> 0; + _fvalsU32[1] = (~keyHi) >>> 0; + } + outData[pos] = _fvals[0] as T; pos = pos + 1; } } @@ -926,16 +944,36 @@ export class Series { if (allNumeric) { if (ascending) { for (let i = 0, si = 0; i < finCount; i++, si += 3) { - const idx = srcBuf[si]!; - perm[pos] = idx; - outData[pos] = vals[idx] as T; + const origIdx = srcBuf[si]!; + const keyLo = srcBuf[si + 1]!; + const keyHi = srcBuf[si + 2]!; + perm[pos] = origIdx; + // Reverse the IEEE-754 sign-transform to recover the original float bits, + // avoiding a random read into the JS values array. + if (keyHi & 0x80000000) { + _fvalsU32[0] = keyLo; + _fvalsU32[1] = (keyHi ^ 0x80000000) >>> 0; + } else { + _fvalsU32[0] = (~keyLo) >>> 0; + _fvalsU32[1] = (~keyHi) >>> 0; + } + outData[pos] = _fvals[0] as T; pos = pos + 1; } } else { for (let i = finCount - 1, si = (finCount - 1) * 3; i >= 0; i--, si -= 3) { - const idx = srcBuf[si]!; - perm[pos] = idx; - outData[pos] = vals[idx] as T; + const origIdx = srcBuf[si]!; + const keyLo = srcBuf[si + 1]!; + const keyHi = srcBuf[si + 2]!; + perm[pos] = origIdx; + if (keyHi & 0x80000000) { + _fvalsU32[0] = keyLo; + _fvalsU32[1] = (keyHi ^ 0x80000000) >>> 0; + } else { + _fvalsU32[0] = (~keyLo) >>> 0; + _fvalsU32[1] = (~keyHi) >>> 0; + } + outData[pos] = _fvals[0] as T; pos = pos + 1; } } From 237b3f55f531d525626166c51bbe6d2c5f08cce0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 12 May 2026 05:52:52 +0000 Subject: [PATCH 2/2] fix(lint): remove redundant parentheses around ~ in series.ts Biome formatter requires `~keyLo >>> 0` instead of `(~keyLo) >>> 0`. Semantics are identical since ~ has higher precedence than >>>. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/core/series.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/core/series.ts b/src/core/series.ts index c66e0b35..208cc239 100644 --- a/src/core/series.ts +++ b/src/core/series.ts @@ -909,8 +909,8 @@ export class Series { _fvalsU32[0] = keyLo; _fvalsU32[1] = (keyHi ^ 0x80000000) >>> 0; } else { - _fvalsU32[0] = (~keyLo) >>> 0; - _fvalsU32[1] = (~keyHi) >>> 0; + _fvalsU32[0] = ~keyLo >>> 0; + _fvalsU32[1] = ~keyHi >>> 0; } outData[pos] = _fvals[0] as T; pos = pos + 1; @@ -925,8 +925,8 @@ export class Series { _fvalsU32[0] = keyLo; _fvalsU32[1] = (keyHi ^ 0x80000000) >>> 0; } else { - _fvalsU32[0] = (~keyLo) >>> 0; - _fvalsU32[1] = (~keyHi) >>> 0; + _fvalsU32[0] = ~keyLo >>> 0; + _fvalsU32[1] = ~keyHi >>> 0; } outData[pos] = _fvals[0] as T; pos = pos + 1; @@ -954,8 +954,8 @@ export class Series { _fvalsU32[0] = keyLo; _fvalsU32[1] = (keyHi ^ 0x80000000) >>> 0; } else { - _fvalsU32[0] = (~keyLo) >>> 0; - _fvalsU32[1] = (~keyHi) >>> 0; + _fvalsU32[0] = ~keyLo >>> 0; + _fvalsU32[1] = ~keyHi >>> 0; } outData[pos] = _fvals[0] as T; pos = pos + 1; @@ -970,8 +970,8 @@ export class Series { _fvalsU32[0] = keyLo; _fvalsU32[1] = (keyHi ^ 0x80000000) >>> 0; } else { - _fvalsU32[0] = (~keyLo) >>> 0; - _fvalsU32[1] = (~keyHi) >>> 0; + _fvalsU32[0] = ~keyLo >>> 0; + _fvalsU32[1] = ~keyHi >>> 0; } outData[pos] = _fvals[0] as T; pos = pos + 1;