Skip to content

RISC-V: faster DAMAX kernel for RISCV64_ZVL256B - #6174

Open
HiderX wants to merge 1 commit into
OpenMathLib:developfrom
HiderX:riscv-zvl256b-damax
Open

HiderX wants to merge 1 commit into
OpenMathLib:developfrom
HiderX:riscv-zvl256b-damax

Conversation

@HiderX

@HiderX HiderX commented Oct 25, 2026

Copy link
Copy Markdown

Summary

On RISCV64_ZVL256B, DAMAX uses amax_vector.c. That kernel reduces every LMUL-2
strip into a scalar accumulator, which serialises the loop. This PR adds
kernel/riscv64/amax_zvl256b.c and uses it for DAMAX only. The new kernel:

  • in cache, keeps one LMUL-8 vfmax accumulator and reduces once at the end;
  • for unit-stride data larger than 2 MiB, which streams from DRAM, uses four
    LMUL-1 accumulators instead.

The second path is based on measurements on the SpacemiT X100, where the
single-core DRAM read bandwidth depends strongly on the width of the vector
loads:

  • LMUL-1 loads sustain about 8.2 GB/s at any alignment;
  • LMUL-8 loads get about 5.4 GB/s;
  • line-aligned LMUL-2 loads get 4.2–6.7 GB/s.

The result still starts from 0, so results are bit-identical to the old kernel.
C910V and SAMAX keep amax_vector.c.

Performance

Platform: SpacemiT K3, one X100 core (2.2 GHz), single thread, GCC 15.2.
cblas_damax, unit stride, called through the public API. Each number is the
median ns per call over 4 processes per build, alternating. Offsets are in
elements from a 64-byte aligned buffer: 0, 2 and 4 are the 16-byte
alignments that malloc/NumPy give, and large glibc blocks sit at offset 2.

n offset 0 offset 2 offset 4
1024 2.87x 2.87x 2.87x
32768 2.03x 2.08x 2.05x
262144 2.03x 2.05x 2.11x
4194304 1.21x 1.50x 2.04x

At every size and offset, all patched processes were faster than all develop
processes. An earlier job measured 1.45x / 1.84x / 1.99x at n = 4194304. The
develop kernel's DRAM rate at offset 0 varies between runs.

Caveat: at odd offsets (8 but not 16 byte aligned) with n = 4M, the
patched kernel measured 0.89–0.98x of develop. In the same job, the
unchanged SAMIN/DAMIN kernels also varied between 0.80x and 1.01x at odd
offsets at that size, so I consider those cells within run-to-run noise.

SAMAX was measured as well:

  • about 3x faster in cache;
  • only 1.06–1.24x faster from DRAM.

DAMIN, with this structure, is about 2.9x faster in cache but up to 9%
slower from DRAM. That is because amin_vector.c happens to stream from
x+1, where on the X100 every LMUL-2 load spans two cache lines, and that is
fast. Neither SAMAX nor DAMIN is switched in this PR.

Testing

  • OpenBLAS tests. The default make goal's tests give identical results:
    utest 141/141, extension tests 1479/1479, and all BLAS/CBLAS tests PASSED.

  • Differential check against develop, 8640 cases covering:

    • cblas_samax/samin/damax/damin;
    • lengths 1–17, 31–33, 63–65, 127–129, 1000, 1031, and both sides of the
      2 MiB switch;
    • strides 1, 2 and 3;
    • offsets 0–3;
    • NaN, Inf, all-NaN, ±0 with denormals, and huge/tiny mixes.

    The outputs are byte-identical.

amax_vector.c reduces every LMUL-2 strip into a scalar, which serialises the
loop. The new amax_zvl256b.c keeps one LMUL-8 accumulator and reduces once;
for unit-stride data larger than 2 MiB, which streams from DRAM, it uses four
LMUL-1 accumulators instead, because on the SpacemiT X100 small vector loads
sustain a markedly higher single-core DRAM read bandwidth than LMUL-8 loads.
On the X100 DAMAX is about 3x faster in cache and 1.45-2x faster from DRAM
for 16-byte aligned data. The result starts from 0 as before, so results are
unchanged. SAMAX keeps amax_vector.c, and C910V is not affected.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant