diff --git a/docs/index.md b/docs/index.md index 4037a4c..dcaccea 100644 --- a/docs/index.md +++ b/docs/index.md @@ -7,7 +7,7 @@ algebra, all with cgo disabled. Ruby has no cgo-free ndarray (`Numo::NArray`, `NMatrix` are C extensions) and `gonum`'s optimized assembly is amd64-only. go-ndarray pairs a portable pure-Go -core with **multicore fan-out + go-asmgen SIMD** (amd64, arm64, ppc64le, loong64 and riscv64), +core with **multicore fan-out + go-asmgen SIMD** (amd64, arm64, ppc64le, loong64, riscv64 and s390x), and a **`Workspace`** arena that takes the garbage collector out of loops. **100% coverage**, differentially checked against NumPy. diff --git a/docs/performance.md b/docs/performance.md index 8b4af1d..d9854e4 100644 --- a/docs/performance.md +++ b/docs/performance.md @@ -4,7 +4,7 @@ Honest, reproducible head-to-head of `go-ndarray/ndarray` against **NumPy 2.2.4** on identical hardware. "On n'a pas le droit de se tromper": every number here is measured, every win is real, and where NumPy still leads it says so. -> **Where it stands at v0.7.1.** This page grew round by round: the sections +> **Where it stands at v0.8.0.** This page grew round by round: the sections > up to *Where go-ndarray still loses* were measured on an arm64 Tart VM > (4 vCPU, NumPy 2.2.4, OpenBLAS 0.3.29); the dated sections after it on an > AMD Zen 3, 16 cores, against **NumPy 2.5.3 + OpenBLAS 0.3.34**, except the @@ -36,10 +36,10 @@ here is measured, every win is real, and where NumPy still leads it says so. > micro-kernel from 7.0 to 27.5 GFLOP/s and the serial GEMM from 5.3 to 20.0 > GFLOP/s at 512², against the scalar code; no NumPy or BLAS reference was > available on that host (see *loong64: LASX kernels*). -> SIMD kernels exist on **amd64, arm64, ppc64le, loong64 and riscv64** (LASX -> and RVV used only when the CPU reports them); the other targets run the -> pure-Go reference code. For s390x that is work not yet done, not a toolchain -> limit (see *SIMD coverage* at the end). +> SIMD kernels exist on **amd64, arm64, ppc64le, loong64, riscv64 and s390x** (LASX, +> RVV and the s390x vector facility used only when the CPU reports them); the +> 32-bit targets run the pure-Go reference code; the s390x kernels are validated +> under emulation only (see *SIMD coverage* at the end). ## How a pure-Go library can beat NumPy @@ -912,7 +912,19 @@ stay dynamic, so its slower efficiency cores are handled as before. 2.1 GFLOP/s on one core this is still far from the hardware: VLEN = 256 with LMUL=4 uses half of each register group, which keeps one tile portable to every VLEN at that cost. -- The remaining 64-bit Go target — **s390x** — keeps +- **s390x (vector facility)**, since v0.8.0, when AT_HWCAP reports it: + sum, dot, sqrt and add/sub/mul/div, eight float64 per loop in four + two-lane registers plus a scalar tail, every instruction a Go mnemonic. + max/min and the GEMM micro-kernel stay scalar (the vector max with NumPy's + NaN rule needs the z14, beyond the z13 Go supports). The operand order of + `VFSDB`/`VFDDB`/`VFMADB` was **measured**, not read: each run once on known + inputs (`VFSDB V1, V2, V3` is V3 = V2 − V1). ⚠ **Validated under emulation + only** (Docker's qemu-s390x locally, qemu-s390x in CI): the whole suite, the + fence tests, and two sabotaged kernels that both failed. **Not measured**: + the LinuxONE host did not answer. AT_HWCAP is read in the machine's byte + order, which on big-endian s390x is not the little-endian the parser first + assumed. +- The 32-bit targets keep the validated scalar oracles, using the same four-accumulator max/min, direct sqrt loop, and a **scalar 4×4 GEMM micro-kernel** over the packed panels, and still get the **packing + cache blocking + multicore** structure (they have @@ -925,8 +937,8 @@ stay dynamic, so its slower efficiency cores are handled as before. load (`XVMOVQ off(R), X.V4` = `xvldrepl.d`), but no vector FMA, which go-asmgen v0.14.0 encodes (transitionally), so loong64 has kernels; **s390x** has them, FMA included (`VFADB`, `VFMADB`); **riscv64** has them - (`VFADDVV`, `VFMACCVV`) and has had kernels since v0.7.0. So s390x kernels are - work not yet done, not a toolchain wall. (s390x additionally exercises the big-endian path in CI.) + (`VFADDVV`, `VFMACCVV`) and has had kernels since v0.7.0, s390x since v0.8.0. + (s390x additionally exercises the big-endian path in CI.) All six are exercised in CI (native amd64/arm64 + qemu for the rest); each per-arch job regenerates the committed `.s`, fails if it is stale, vets diff --git a/docs/security.md b/docs/security.md index 520967f..20c480f 100644 --- a/docs/security.md +++ b/docs/security.md @@ -1,6 +1,6 @@ # Security -> Mirrored from [`SECURITY.md`](https://github.com/go-ndarray/ndarray/blob/main/SECURITY.md) at v0.7.0. +> Mirrored from [`SECURITY.md`](https://github.com/go-ndarray/ndarray/blob/main/SECURITY.md) at v0.8.0. ## Reporting @@ -12,7 +12,7 @@ issue for it. go-ndarray is pure Go (`CGO_ENABLED=0`) except for its SIMD kernels, which are Plan 9 assembly generated by [go-asmgen](https://github.com/go-asmgen/asmgen) -for amd64, arm64, ppc64le, loong64 and riscv64. Those kernels are the only code Go's +for amd64, arm64, ppc64le, loong64, riscv64 and s390x. Those kernels are the only code Go's bounds checks do not cover, so they are held to the following: - **Every wrapper checks the reach of its kernel.** Before an assembly call, the @@ -59,6 +59,16 @@ standard library's known vulnerabilities; `govulncheck ./...` reports none. ## Audit log +**2026-10-08 (v0.8.0).** New s390x vector-facility kernels, held to the same +guards (wrappers check each kernel's reach; the PROT_NONE fence tests now +include s390x). ⚠ They were validated **under emulation only** (Docker's +qemu-s390x locally, qemu-s390x in CI): the whole suite and the fence tests +pass, and two sabotaged kernels (a subtraction with swapped operands, a dot +that does not advance `b`) both failed. No s390x host was reachable. Found on +the way: `hwcapFrom` read `/proc/self/auxv` as little-endian; on big-endian +s390x that would have read the wrong word, so it now uses the machine's byte +order, and `useVX` comes out true under emulation as it should. + **2026-10-08 (v0.7.0).** New riscv64 RVV kernels. They are held to the same guards: each wrapper checks the reach of its kernel (`TestWrappersRefuseShortOperands`), and the PROT_NONE fence tests pass on a real SpacemiT X60 with V (cfarm95), as