Fix CORTEXA72 Level-3 correctness (SYMM/TRMM/SYRK) - #6002
Conversation
The A72 6x8 DGEMM path left SYMM packer remainders as (n-n/6), wired DTRMM to a 2x2 ukernel against 6x8 packs, and left GEMM_UNROLL_MN at MAX(6,8)=8. Correct the packers, add a contiguous 6x8 TRMM ukernel, and set UNROLL_MN=6. Fixes OpenMathLib#5997. Co-authored-by: Cursor <cursoragent@cursor.com>
CORTEXA72 sets DGEMM_UNROLL_MN=6 so SYRK diagonals match MR=6 packs. The ~(MN-1) form only works for power-of-two MN; use the same division as syrk_kernel.c. Co-authored-by: Cursor <cursoragent@cursor.com>
Graviton1 verification (a1.metal, Cortex-A72 ×16)Tested HEAD
So this restores the reporter’s DSYMM/DTRMM failures on real A72; DSYRK/DSYR2K still need a follow-up (diagonal tiles / non-PoT Artifacts: arm-benchmarks results ( |
SYRK packs B in UNROLL_MN-wide strips then calls GEMM with full panel N. With MN=6 that layout does not match NR=8, so DSYRK/DSYR2K failed on real A72. MN must be a multiple of UNROLL_N; MR=6 ICOPY handles width 8 as 6+2. Keeps the syr2k division stepping fix. Co-authored-by: Cursor <cursoragent@cursor.com>
SYRK/SYR2K diagonal kernels advance packed A/B by UNROLL_MN and require panel-aligned starts for both MR and NR. MN=8 fixed NR packing but broke MR=6 A panels; MN=24 is the common multiple. Keeps non-PoT division stepping. Co-authored-by: Cursor <cursoragent@cursor.com>
Graviton1 verification (a1.metal, 16 cores)Correctness: All Fix: Performance vs stock CORTEXA57:
Multicore uplift from the 6×8 kernel is preserved. |
Replace the correctness-first generic C trmmkernel_6x8 with an ASM ukernel derived from dgemm_kernel_6x8_cortexa72.S (TRMM offset/K stepping and overwrite SAVE). Restores DTRMM throughput vs stock A57 on multicore Graviton1. Co-authored-by: Cursor <cursoragent@cursor.com>
ASM DTRMM follow-upReplaced generic Correctness (a1.metal): DTRMM perf vs prior C ukernel / stock CORTEXA57 (16 threads):
ST DTRMM still ~5–8% behind A57 (same pattern as ST DGEMM); MT DTRMM now matches/beats A57 at n≥1024. |
Rem panels of size 4/5 used (m & ~(i-1))-i, which assumes power-of-two M alignment. With MR=6 that misplaces the rem-4 block (cblas N=5/35). Walk the rem start position from the end instead. Co-authored-by: Cursor <cursoragent@cursor.com>
Full
|
| Suite | Threads | Exit |
|---|---|---|
make tests |
OPENBLAS_NUM_THREADS=1 |
0 |
make tests |
OPENBLAS_NUM_THREADS=16 |
0 |
Includes Fortran BLAT2/BLAT3 (S/D/C/Z), CBLAS (incl. cblas_dtrsm col+row 3528 calls), and utest. No FATAL/FAILED lines in either log.
Isolated re-check after the LN rem fix: xdcblat3 < din3 — all Level-3 double CBLAS PASS, including cblas_dtrsm.
Summary
Fixes #5997 — after #5970,
TARGET=CORTEXA72DGEMM 6×8 still produced wrong DSYMM / DTRMM / DSYRK / DSYR2K on real Cortex-A72 (Pi 400). DGEMM/TRSM were already addressed; these cousins share the GEMM unroll and were left inconsistent.Root causes
generic/symm_{l,u}copy_6.cremainders used(n - n/6) & {4,2,1}, which is wrong for non-power-of-two width 6 (e.g. n=7 → treats remainder as 4).trmm_*copy_6.calready usedn % 6.KERNEL.CORTEXA72selectedtrmmkernel_2x2.cwhile packs are contiguous MR=6 / NR=8.UNROLL_M=6,UNROLL_N=8, defaultUNROLL_MN = MAX(6,8) = 8makes every SYRK diagonal tile an 8×8 GEMM against 6-wide A packs (always 6+2 edges). SetDGEMM_DEFAULT_UNROLL_MN 6so diagonal stepping matches MR=6. Thread width math uses(mask+1)withmask=MN-1(works for non-PoT);syr2k_kernelmust not use~(MN-1)bit clearing.Changes
symm_lcopy_6.c/symm_ucopy_6.c: remainder →n % 6generic/trmmkernel_6x8.c(offset-aware; M rem 6→4→2→1, N rem 8→4→2→1) wired inKERNEL.CORTEXA72param.h(CORTEXA72):#define DGEMM_DEFAULT_UNROLL_MN 6syr2k_kernel.c: division form formmstepping (same idea assyrk_kernel.c)DGEMM 6×8 ukernel / panel packers unchanged (HPL path kept).
Test plan
make TARGET=CORTEXA72 USE_THREAD=0 NO_FORTRAN=1 NO_LAPACK=1 libs(arm64)OPENBLAS_NUM_THREADS=1)OPENBLAS_NUM_THREADS>1SYRK pass (MN=6 thread splits)Remaining risks
trmmkernel_6x8.cis correctness-first C (not a tuneddtrmm_kernel_6x8.S); DTRMM may be slower until an asm TRMM exists.Made with Cursor