Skip to content

[Feature Request] Activate existing RISCV64 QEMU build/test path in CI #32465

Description

@garybeihl

Describe the feature request

ONNX Runtime already has everything needed to build and test riscv64 under emulation, and as far as I can tell from the repository nothing exercises it.

What's already there:

  • cmake/riscv64.toolchain.cmake (SiFive, 2024) sets CMAKE_CROSSCOMPILING_EMULATOR to ${RISCV_QEMU_PATH}, so ctest runs
    cross-compiled tests under QEMU automatically.
  • build.py supports --rv64, --riscv_toolchain_root and --riscv_qemu_path, and explicitly requires the QEMU path when tests are not
    skipped: "The --riscv_qemu_path option is required for testing riscv64."
  • tools/scripts/build_riscv64.sh is a working sample of the whole flow.
  • There is real code to exercise: 13 RVV kernel files under onnxruntime/core/mlas/lib/riscv64 added between April and July, plus
    test_activation_rvv.cpp, test_qnbitgemm_rvv_fp16.cpp, and six benchmarks under test/mlas/bench/riscv64.

What I can't find is anything that runs it. Searching the tree for riscv/rv64 turns up no pipeline definitions, and grepping .github/, tools/ci_build/ and tools/scripts/ finds only the build plumbing above. I also looked at the check runs on a recent main commit -- 192 of them, across both GitHub Actions and Azure Pipelines -- and none is riscv64.

Scheduled pipelines wouldn't appear in per-commit check runs, so I can't rule those out from outside the project. If riscv64 is already covered somewhere I can't see, please just say so and I'll drop this.

Suggested scope, kept deliberately small:

  • build.py --rv64 with the existing toolchain and QEMU paths
  • run the MLAS unit tests only, not the full suite, to bound runtime
  • trigger nightly, or on changes under onnxruntime/core/mlas/**
  • build with -march=rv64gcv so the RVV paths are actually taken, and run at more than one vlen -- see below

On emulation, which I think is the right tool here rather than a compromise. RVV is vector-length agnostic: the same binary runs at whatever VLEN the hardware provides, and a kernel can be correct at one vector length and wrong at another. A physical board has exactly one. QEMU takes VLEN as a CPU option -- -cpu rv64,v=true,vlen=256 -- and validates it (an invalid value is rejected with "Vector extension VLEN must be power of 2"), so an emulated job can sweep vector lengths that no single piece of hardware can cover. For that property emulation isn't a weaker stand-in for silicon; it tests something a single board can't.

On where it should run. I notice most workflows here use self-hosted runners, so adding a job is a request to spend your capacity. I'd suggest avoiding that: a GitHub-hosted ubuntu-latest job in the style of lint.yml should be able to apt install the riscv64 cross toolchain and qemu-user-static, build MLAS and its tests, and run them under emulation. That costs none of the self-hosted pool and means any contributor can reproduce and debug it.

I haven't verified an MLAS-only build fits comfortably in a hosted runner's limits -- that is the first thing I'd measure before proposing anything concrete.

Questions:

  1. Is riscv64 already covered by a pipeline I can't see from the repo?
  2. If not, is a QEMU-based job welcome in principle, scoped to the MLAS tests?
  3. Any objection to it being a GitHub-hosted Actions workflow rather than an Azure pipeline?

Happy to put it together and report the timings if there's interest.

Describe scenario use case

The scenario is catching architecture-specific correctness regressions in MLAS before they reach users on riscv64.

#20030 is a case study rather than a complaint. A packing width mismatch in the non-SIMD SGEMM path produced silently wrong results on riscv64 -- about 15% accuracy on a small CNN, and garbage output from whisper-tiny. It was reported in March 2024, and the reply was entirely reasonable:

Sorry our team doesn't have access to the kind of hardware. We cannot debug the issue.

It was fixed in March 2026 by #27819, a PR titled "[wasm] fix non-SIMD sgemm implementation", which repaired the shared non-WASM pack path that riscv64 also uses -- so RISC-V was fixed as a side effect rather than deliberately. The fix was first confirmed on riscv64 in August 2026, when a contributor cross-compiled and ran it under QEMU by hand. #20030 is still open.

That is roughly two years during which a silent numerical error was present on an architecture the project supports, and the eventual verification was one person doing manually what a CI job could do on every change.

Meanwhile the surface has grown considerably: 13 RVV kernel files landed between April and July this year, covering convolution, activation, LLM operators, INT8 GEMM/GEMV and QNBitGemm. These are hand-written vector intrinsics, which is the code most likely to be subtly wrong and least likely to be caught by review.

A job running the existing tests under the existing emulator would have caught the 2024 bug in 2024, and would give the contributors adding RVV kernels today a signal they currently don't get.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    feature requestrequest for unsupported feature or enhancementplatform:webissues related to ONNX Runtime web; typically submitted using template

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions