Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
28 changes: 20 additions & 8 deletions docs/performance.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
14 changes: 12 additions & 2 deletions docs/security.md
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
Loading