Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

SVE small SGEMM/DGEMM writes output padding at VL384 (QEMU)

未关闭
#6,103 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 1 天内回复

还没有人认领这个 Issue。

评估

难度
4/5
预计耗时
3-5 天
新手友好度
58/100
Issue 类型
缺陷
描述清晰度
描述清楚
活跃度
活跃
技术栈
c
领域
performance

调研方向

Start with the two named files, kernel/arm64/sgemm_small_kernel_nn_sve.c near lines 250–251 and kernel/arm64/dgemm_small_kernel_nn_sve.c near lines 222–223, and inspect how their row-count bounds behave at VL384. Build OpenBLAS with the supplied AArch64/QEMU setup and run the repro.c SGEMM and DGEMM cases. Done means both calls produce nine zeros while preserving every allocated padding value of 17; verify other vector lengths remain unaffected.

由索引模型根据 Issue 内容生成。

描述

SVE small SGEMM/DGEMM writes output padding at VL384 (QEMU)

On OpenBLAS develop 277ef7801416412ee970873701fdf14d603d2c3f and release
v0.3.34, a public row-major 1-by-9 SGEMM or DGEMM with K=0 and beta=0
writes into padding beyond the nine output elements at SVE VL384 with
forced ARMV8SVE dispatch under QEMU. The one-call reproducer below
initializes the nine outputs to NaN and all remaining allocated elements
to 17. Correct output is nine zeros with every other element still 17.
The first padding element instead becomes zero.

QEMU 8.2.2 and 10.2.1 agree with ARMV8SVE, A64FX and NEOVERSEV1
dispatch. ARMV8 and NEOVERSEV2 preserve padding at VL384; the affected
tables pass these vectors at VL128, 256, 512, 1024 and 2048. Original
Reference BLAS v3.12.1 SGEMM/DGEMM, with equivalent column-major
dimensions, preserves the padding on both emulators at all six lengths.
All accesses demonstrated by this reproducer remain within its allocated
128-element arrays; the incorrect writes are outside the logical output.

Suspected cause

Row-major dimensions 1-by-9 become internal M=9, N=1. K=0 bypasses
GEMM-to-GEMV forwarding, while the small-matrix permit accepts the call.
Beta=0 selects sgemm_small_kernel_b0_nn or dgemm_small_kernel_b0_nn,
so this does not depend on the regular GEMM packers.

kernel/arm64/sgemm_small_kernel_nn_sve.c
near lines 250-251 and
kernel/arm64/dgemm_small_kernel_nn_sve.c
near lines 222-223 compute row counts as M & -(2*v_size) and
M & -v_size. At VL384, the respective lane counts are 12 and 6;
these masks do not compute floor-to-multiple counts. For example,
the float two-vector bound is 9 & -24 = 8, which enters a full
24-row store even though there are only nine output rows. The double
one-vector bound is 9 & -6 = 8, which permits two six-row stores.
Both explain the change to the first padding element without reading A
or B. Arithmetic count calculation is a candidate direction; no source
fix has been tested here.

Hardware scope

The names above select OpenBLAS dispatch tables on QEMU's max CPU.
Documented maximum SVE lengths for the named processors are 128 bits for
Neoverse N2/V2, 256 bits for Neoverse V1, and 512 bits for A64FX
(Arm, NVIDIA).
SVE permits non-power-of-two multiples of 128 bits;
VL384 is an architectural conformance case supported by QEMU. These forced
table/VL combinations do not establish a failure on the named native
processors. Native confirmation is unavailable.

Reproduce

On Linux, use Git, GNU Make, host GCC, an AArch64 GCC cross toolchain
with its glibc sysroot, and QEMU user mode. GCC 15.2 was used for the
reported builds. Save the C block below as repro.c in a clean
working directory, then run these commands from that directory:

git init openblas-src
git -C openblas-src fetch --depth=1 https://github.com/OpenMathLib/OpenBLAS.git 277ef7801416412ee970873701fdf14d603d2c3f
git -C openblas-src checkout --detach FETCH_HEAD
cd openblas-src
make -j4 ARCH=arm64 BINARY=64 TARGET=ARMV8 DYNAMIC_ARCH=1 \
  'DYNAMIC_LIST=ARMV8SVE A64FX NEOVERSEV1 NEOVERSEN2' \
  NOFORTRAN=1 NO_LAPACK=1 USE_THREAD=0 NUM_THREADS=1 HOSTCC=gcc \
  CC=aarch64-linux-gnu-gcc AR=aarch64-linux-gnu-ar RANLIB=aarch64-linux-gnu-ranlib
make ARCH=arm64 BINARY=64 TARGET=ARMV8 DYNAMIC_ARCH=1 \
  'DYNAMIC_LIST=ARMV8SVE A64FX NEOVERSEV1 NEOVERSEN2' \
  NOFORTRAN=1 NO_LAPACK=1 USE_THREAD=0 NUM_THREADS=1 HOSTCC=gcc \
  CC=aarch64-linux-gnu-gcc AR=aarch64-linux-gnu-ar RANLIB=aarch64-linux-gnu-ranlib \
  PREFIX="$PWD/install" install
aarch64-linux-gnu-gcc -O2 -Wall -Wextra -Iinstall/include ../repro.c \
  install/lib/libopenblas.a -lm -lpthread -o small-repro
OPENBLAS_CORETYPE=ARMV8SVE OPENBLAS_NUM_THREADS=1 \
  qemu-aarch64 -L /usr/aarch64-linux-gnu \
  -cpu max,sve-default-vector-length=48 ./small-repro 384 s
OPENBLAS_CORETYPE=ARMV8SVE OPENBLAS_NUM_THREADS=1 \
  qemu-aarch64 -L /usr/aarch64-linux-gnu \
  -cpu max,sve-default-vector-length=48 ./small-repro 384 d

The QEMU property is in bytes: 48 requests VL384.
Replace qemu-aarch64 with QEMU 8.2.2's qemu-aarch64-static to
repeat with the second emulator.
The program checks the actual vector length with PR_SVE_GET_VL and
prints the selected OpenBLAS core; confirm that the printed core matches
the requested dispatch table. Exit 0 means the checked values are right,
1 means a numerical or padding mismatch, and 2 means a setup/argument
failure rather than a valid numerical result. Each mode makes one public
BLAS call.

repro.c
/* Public beta-only SGEMM/DGEMM: SVE small-kernel VL384 count witness. */
#include <cblas.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/prctl.h>
int main(int argc,char **argv) {
    int requested=argc>1?atoi(argv[1]):384;
    int vl=prctl(51,0,0,0,0);
    if(vl<0 || (vl&65535)*8!=requested)return 2;
    int isdouble=argc>2&&!strcmp(argv[2],"d");
    float af[128]={0},bf[128]={0},cf[128];
    double ad[128]={0},bd[128]={0},cd[128];
    for(int i=0;i<128;i++){cf[i]=cd[i]=i<9?NAN:17;}
    if(isdouble)cblas_dgemm(CblasRowMajor,CblasNoTrans,CblasNoTrans,1,9,0,1,ad,1,bd,9,0,cd,12);
    else cblas_sgemm(CblasRowMajor,CblasNoTrans,CblasNoTrans,1,9,0,1,af,1,bf,9,0,cf,12);
    int wrong=0;
    for(int i=0;i<128;i++)wrong+=(isdouble?cd[i]:cf[i])!=(i<9?0:17);
    printf("SMALL-VL: %s precision=%c core=%s VL=%d m=1 n=9 k=0 padding=%g want=17 wrong=%d first_surfaced_by=differential\n",
           wrong?"WRONG":"RIGHT",isdouble?'d':'s',openblas_get_corename(),requested,
           isdouble?cd[9]:cf[9],wrong);
    return wrong?1:0;
}

First surfaced by differential testing (first_surfaced_by: differential).

主要语言
C
星标
7.6k
派生
1.7k
平均合并
1 天 19 小时
30 天内合并 PR
53

环境准备

这个项目没有提供开发容器、Dockerfile 或贡献指南,环境需要你自己搭建:先看它的 README,通用步骤见我们的新手贡献指南。

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

OpenMathLib/OpenBLAS 的其他 Issue

查看 OpenMathLib/OpenBLAS 的全部 Issue

相似的 Issue

更多 C Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。