BLAS (OpenBLAS)
Improvements to OpenBLAS 0.3.30 on RISC-V boards — built via EasyBuild, deployed through EESSI with FlexiBLAS runtime swapping.
Verification microbenchmarks live in opensolvers/benchmarks/OpenBLAS (bench_dgemm, difftest, verify_ctrsm). Alternative BLAS: BLIS RVV vs OpenBLAS DGEMM A/B on X60. Stack probes: NumPy (bench_blas.py). Full repo: opensolvers/benchmarks.
Base stack: GCC 14.3.0, OpenBLAS 0.3.30, EESSI 2025.06-001 (dev.eessi.io/riscv).
OpenBLAS 0.3.34 — end-to-end verify (Orange Pi RV2, 2026-08-25)
EESSI 2025.06-001 still ships 0.3.29 / 0.3.30 only. We built upstream tag v0.3.34 locally with EESSI GCC 14.3.0 (TARGET=RISCV64_ZVL256B; Ubuntu GCC 13 cannot compile ZVL256 SGEMM tuple intrinsics). Harness: run-034-tests.sh in opensolvers/benchmarks/OpenBLAS.
Correctness (difftest, 1 thread)
| Backend | dgemv NaN |
dgemm NaN |
dtrsm NaN |
dgemv sum |
|---|---|---|---|---|
| 0.3.34 ZVL256B | 0 | 0 | 0 | 42.06549 |
| Stock EESSI 0.3.30 | 768 | 0 | 0 | 0 (broken) |
| Stock EESSI 0.3.29 | 0 | 0 | 0 | 42.06549 |
| Patched 0.3.30 (#26444) | 0 | 0 | 0 | 42.06549 |
SYRK PSD (OpenBLAS#5811 repro, N=K=50): max_err=0, min_diag=+12.56, PASS (fixes the 0.3.33 ZVL256 regression).
CTRSM sweep (verify_ctrsm): 2400 cases, 0 fails — new ZVL TRSM RVV kernels in 0.3.34 (OpenBLAS#5895).
Performance — bench_dgemm (N=2048, 8 threads)
| Backend | GFLOP/s | C[0] |
|---|---|---|
| 0.3.34 | 15.54 | 245.24 |
| Stock EESSI 0.3.30 | 9.81 | 245.24 |
~1.6× over stock 0.3.30, bit-identical output. Verdict: 0.3.34 has a working RVV path on X60 — ready for an EESSI package bump when upstream lands in the stack.
HPL end-to-end (same xhpl, FlexiBLAS → 0.3.34)
| Config | OpenBLAS 0.3.34 | Patched 0.3.30 | 0.3.34 vs patched |
|---|---|---|---|
HPL.dat (N=8000, 1×8) |
11.04 GFLOP/s, PASSED | 7.72 GFLOP/s, PASSED | 1.43× |
HPL-sweep.dat (N=20000, 2×4) |
10.97 GFLOP/s, PASSED | 10.27 GFLOP/s, PASSED | 1.07× |
Residuals ~3–4e-03. See HPL and run-hpl-034.sh.
Improvements
| Board / CPU | Problem (stock 0.3.30) | Fix | Result |
|---|---|---|---|
| VisionFive 2 — SiFive U74 (scalar) | No U74 kernel; falls back to generic RISCV64_GENERIC C 2×2 GEMM |
New 4×4 DGEMM micro-kernel in RV64 assembly, TARGET=U74 |
Single-core DGEMM ~1.4 → 1.77 GFLOP/s; 4-core DGEMM 6.31 GFLOP/s; HPL 1.69× |
| Orange Pi RV2 — SpacemiT X60 (RVV VLEN=256) | RVV gemv_n zeroes an uninitialized vector register → dgemv returns NaN |
Backport upstream gemv_n fix; TARGET=RISCV64_ZVL256B |
Verification 2.3×; NumPy DGEMM 2.4×; HPL 10.53 GFLOP/s |
| Banana Pi F3 — same K1 / X60 SoC | Same RVV gemv_n bug as RV2 |
Same easyconfigs#26444 fix | Verification 2.35×; NumPy DGEMM 3.6×; HPL 11.52 GFLOP/s |
Packages
| Target | EasyBuild PR | Upstream OpenBLAS | Walkthrough |
|---|---|---|---|
| SiFive U74 | easyconfigs#26436 | OpenBLAS#5903 | EESSI/docs#818 |
| SpacemiT X60 | easyconfigs#26444 | OpenBLAS#5408, #5476 | EESSI blog · YouTube |
Build with eb --from-pr <num> --robot into an EESSI-extend user install, then flexiblas add / flexiblas default — no downstream rebuild.
Verification
Small, self-contained programs in opensolvers/benchmarks/OpenBLAS for BLAS performance and per-routine correctness — used to isolate broken RVV kernels before trusting downstream apps.
| File | Purpose |
|---|---|
bench_dgemm.c |
Times square C = A×B (3 reps), reports GFLOP/s, prints C[0] |
difftest.c |
dlopens a BLAS .so, runs level-1/2/3 routines, reports sum / NaN counts |
verify_ctrsm.c |
Full-parameter TRSM correctness sweep (localizes OpenBLAS#5928 VLEN bug in _rvv_v1 kernels) |
run-034-tests.sh |
Build + verify OpenBLAS 0.3.34 on RV2 (difftest, SYRK PSD, CTRSM, DGEMM A/B) |
Both switch backends at runtime via FlexiBLAS or OPENBLAS_CORETYPE — no recompile.
gcc -O2 bench_dgemm.c -o bench_dgemm -lflexiblas
gcc -O2 difftest.c -o difftest -ldl -lm
OPENBLAS_NUM_THREADS=8 ./bench_dgemm 4096
./difftest /path/to/libopenblas.so
Correctness — difftest (X60, RV2 & F3)
Bit-identical on Orange Pi RV2 and Banana Pi F3:
| Backend | dgemv NaN |
dgemm NaN |
dtrsm NaN |
dgemv sum |
|---|---|---|---|---|
| Stock EESSI, default RVV | 192 | 0 | 0 | 198.94 (wrong) |
| Forced scalar | 0 | 0 | 0 | 42.06549 (reference) |
Patched RVV (gemv_n fix) |
0 | 0 | 0 | 42.06549 (matches) |
Fault is in dgemv only — plain dgemm and dtrsm look fine on the broken gemv_n build, which is why HPL, Quantum ESPRESSO, and PETSc dense/direct paths can fail while a GEMM micro-benchmark passes.
A second bug — RVV _rvv_v1 TRSM kernels not VLEN-agnostic (OpenBLAS#5928) — is caught by verify_ctrsm on ZVL128B builds where GEMM_UNROLL_M ≠ VSETVL_MAX.
Performance — bench_dgemm
Orange Pi RV2 (1 core, N=2048)
| Backend | GFLOP/s | C[0] |
|---|---|---|
| Scalar | 1.16 | 245.24 |
| Patched RVV | 2.62 | 245.24 |
2.3× faster, numerically identical.
Banana Pi F3 (cross-board)
| Backend | GFLOP/s | C[0] |
|---|---|---|
| Scalar | 1.26 | 245.24 |
| Patched RVV | 2.96 | 245.24 |
2.35× at 1 core. Threaded (8 cores, N=4096): 17.71 GFLOP/s on patched RVV.
Notes
- U74 — performance kernel; stock OpenBLAS works but leaves FP throughput on the table.
- X60 — correctness fix first. Stock EESSI
DYNAMIC_ARCHdoes dispatch RVV, but 0.3.30’s brokengemv_ncorrupts BLAS-2 paths. OpenBLAS ≥ 0.3.34 fixes this natively — verified on Orange Pi RV2 (see above). - Pin a valid
-marchviaEASYBUILD_OPTARCHon the experimentaldev.eessi.io/riscvtoolchain (see board walkthroughs).