From bf3abceff459bbd0579417f6a29c12449490df44 Mon Sep 17 00:00:00 2001 From: tannevaled Date: Sun, 4 Oct 2026 17:16:09 +0200 Subject: [PATCH] docs: three passages the v0.2.1 docs still had wrong Found while mirroring README/perf.md to the docs site: - plan-ndarray.md said every unary ufunc goes through Map; Sqrt has a SIMD kernel and Exp/Log/Log10 have their own kernels since v0.2.0. - perf.md's "where it still loses" table put Exp/Log at NumPy parity through Map. They are fixed (own kernels); Sin/Cos/Tan still go through Map and measured at about parity on a Zen 3 core (10.5 vs 10.4 ns, 11.1 vs 10.7, tanh 16.5 vs 13.5). - perf.md's last paragraph called every GEMM micro-kernel bit-identical to the ikj oracle and said amd64 was validated under qemu-x86_64. CI has no qemu-x86_64 job, and the kernels match the oracle exactly only on integer-valued data (above KC the partials regroup; FMA rounds once). Co-Authored-By: Claude Opus 5.5 --- docs/perf.md | 9 ++++++--- docs/plan-ndarray.md | 6 ++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/docs/perf.md b/docs/perf.md index e4f957f..93668ee 100644 --- a/docs/perf.md +++ b/docs/perf.md @@ -311,7 +311,8 @@ The SIMD kernels are also validated against the scalar oracle per-arch in CI: | `Sqrt` | **FIXED — go wins 2.8× at 4 M, *Into* 1.8× small** | packed `SQRTPD` (amd64) / packed NEON `FSQRT V.2D` (arm64) / intrinsic `FSQRTD` (others), off a non-`func`-pointer seam | | `Max` / `Min` | **FIXED — go wins 1.4× at 4 M, ~4× small** | builtin-`max` NaN-propagating oracle + 4-accumulator reducer + amd64 `MAXPD`+NaN-scan | | `MatMul` vs tuned BLAS (OpenBLAS) | **FIXED — parity at n=1024 (~0.99×, ~203 GFLOP/s); 0.97× at n=512** | by-lane FMLA micro-kernel (`FMLA Vd.2D,Vn.2D,Vm.D[i]` via `WORD`) closed the prior 0.76× gap. Only small n=256 trails (0.67×) on per-call overhead, not throughput — see above | -| other `Map` ufuncs (`Exp`, `Log`, `Sin`…) | NumPy ~parity (libm-bound) | a packed `VEXP`/`VLOG` is libm-accuracy work; the math, not the dispatch, dominates here | +| `Exp`, `Log`, `Log10` | **FIXED in v0.2.0** — own kernels | ports of Arm's optimized-routines, 2–3.5× `math.Exp`/`math.Log`; see the Exp and Log sections below | +| `Sin`, `Cos`, `Tan`, … (through `Map`) | ~parity with NumPy | per element on one Zen 3 core: Go `math.Sin` 10.5 ns vs NumPy 10.4, `math.Cos` 11.1 vs 10.7, `math.Tanh` 16.5 vs 13.5 (2026-10-04); `Map`'s call per element adds 15–20% | ## Allocation: `Workspace` (2026-10-04) @@ -606,5 +607,7 @@ per-arch job regenerates the committed `.s`, fails if it is stale, vets (asmdecl), builds (cmd/asm encodes), and runs the bit/NaN-correctness suite. The multicore path and the packed/cache-blocked GEMM driver are architecture-independent; only the GEMM micro-kernel is per-arch (NEON 4×8 on -arm64, AVX2/FMA 6×8 or SSE2 on amd64, scalar 4×4 on the other four — all bit-identical to the -scalar ikj oracle, validated per-arch in CI incl. amd64 under qemu-x86_64). +arm64, AVX2/FMA 6×8 or SSE2 on amd64, scalar 4×4 on the other four), each held to +the scalar ikj oracle in CI: exactly on integer-valued data, within tolerance on +general data, since above KC the block partials regroup the sum and the FMA +kernels round once per step where the scalar oracle may round twice. diff --git a/docs/plan-ndarray.md b/docs/plan-ndarray.md index 262ddc5..c40c9b0 100644 --- a/docs/plan-ndarray.md +++ b/docs/plan-ndarray.md @@ -81,8 +81,10 @@ suite (plus the per-arch CI jobs already wired in `.github/workflows/ci.yml`). - **More creation — DONE.** `Linspace(start,stop,num)` (endpoint inclusive, final sample pinned to stop), `Eye(n,m,k)` / `Identity(n)` (k-th diagonal, non-positive m defaults to square), and `Reshape` `-1` dimension inference. -- **Ufuncs — DONE.** Unary math via the `Map` seam (`Sqrt`/`Exp`/`Log`/`Log2`/ - `Log10`/`Sin`/`Cos`/`Tan`/`Floor`/`Ceil`/`Round`/`Square`/`Power`) and +- **Ufuncs — DONE.** Unary math (`Sqrt`/`Exp`/`Log`/`Log2`/`Log10`/`Sin`/`Cos`/ + `Tan`/`Floor`/`Ceil`/`Round`/`Square`/`Power`): `Sqrt` has a SIMD kernel, + `Exp`/`Log`/`Log10` run ports of Arm's optimized-routines (v0.2.0), and the + rest go through the `Map` seam over Go's `math`; and broadcasting comparisons returning 0/1 float masks (`Equal`/`NotEqual`/ `Greater`/`GreaterEqual`/`Less`/`LessEqual`) plus pairwise `Maximum`/`Minimum`. (`Round` is math.Round / half-away-from-zero, unlike numpy's banker's