onnxruntime
b2f6e151 - [MLAS] RVV-Optimized LLM Operators for RISC-V (#28518)

Commit
92 days ago
[MLAS] RVV-Optimized LLM Operators for RISC-V (#28518) ## Description Added RVV implementations for a subset of LLM inference operators. Optimization of activation functions is in #28308. All tests were conducted on a Spacemit K3 CPU (VLEN=256). | Operator | File | Speedup vs Scalar | Precision | | :--- | :--- | :--- | :--- | | FP16 GEMM | `riscv64/halfgemm_kernel_rvv.cpp` | 51–191x | max_abs ≤ 0.0005 (PASS) | | FP16↔FP32 Cast | `riscv64/cast_kernel_rvv.cpp` | 4–12x | Bit-exact (PASS) | | RotaryEmbedding | `riscv64/rotary_embedding_kernel_rvv.cpp` | 3.1x | max_abs ~6e-08 (PASS) | | SimplifiedLayerNorm | `layer_norm_impl.cc` (inline RVV) | 4.3x | Bit-exact (PASS) | ## Operator Performance ### **FP16 GEMM** | Shape (M×N×K) | ORT Scalar | RVV | Speedup | Max Abs Error | | :--- | :--- | :--- | :--- | :--- | | 1×768×768 | 7.32 ms | 0.14 ms | 51.6x | 1.22e-04 | | 32×768×768 | 235 ms | 1.25 ms | 187.9x | 3.66e-04 | | 64×768×768 | 469 ms | 2.49 ms | 188.8x | 2.44e-04 | | 128×3072×768 | 5718 ms | 30.4 ms | 187.8x | 4.88e-04 | --- ### **FP16↔FP32 Cast** | Elements | Direction | ORT Scalar | RVV | Speedup | | :--- | :--- | :--- | :--- | :--- | | 1K | F16→F32 | 0.002 ms | 0.000 ms | 9.6x | | 1K | F32→F16 | 0.002 ms | 0.000 ms | 10.5x | | 64K | F16→F32 | 0.127 ms | 0.013 ms | 9.7x | | 64K | F32→F16 | 0.150 ms | 0.013 ms | 11.3x | | 1M | F16→F32 | 2.03 ms | 0.26 ms | 7.7x | | 1M | F32→F16 | 2.39 ms | 0.50 ms | 4.8x | --- ### **RotaryEmbedding** | Dim | Mode | ORT Scalar | RVV | Speedup | Max Abs Error | | :--- | :--- | :--- | :--- | :--- | :--- | | 64 | non-interleaved | 0.32 us | 0.05 us | 7.1x | 5.96e-08 | | 64 | interleaved | 0.22 us | 0.07 us | 3.2x | 0 | | 128 | non-interleaved | 0.64 us | 0.07 us | 9.7x | 5.96e-08 | | 128 | interleaved | 0.44 us | 0.13 us | 3.4x | 0 | | 256 | non-interleaved | 1.28 us | 0.10 us | 13.0x | 1.19e-07 | | 256 | interleaved | 1.05 us | 0.25 us | 4.3x | 0 | --- ### **RMSNorm** | Hidden | ORT Scalar | RVV | Speedup | Max Abs Error | | :--- | :--- | :--- | :--- | :--- | | 512 | 2.31 us | 0.38 us | 6.0x | 2.38e-07 | | 1024 | 4.64 us | 0.71 us | 6.5x | 2.38e-07 | | 2048 | 9.24 us | 1.42 us | 6.5x | 3.58e-07 | | 4096 | 18.5 us | 2.82 us | 6.6x | 3.58e-06 | > **Note**: ORT's LayerNorm ComputeJob is in an anonymous namespace — there's no public API to call it separately. So I rewrite the benchmark using the same algorithm as ORT's ComputeJob. ## Model Performance The ONNX model comes from: https://huggingface.co/onnx-community/Qwen3-0.6B-ONNX | Metric | FP32 | FP16 | | :--- | :--- | :--- | | Prompt processing | 61.1 tok/s (255 ms p50) | 58.8 tok/s (272 ms p50) | | Token generation | 6.5 tok/s (152 ms p50) | 6.1 tok/s (162 ms p50) | | E2E (16+32 tokens) | 4987 ms p50 | 5357 ms p50 | | Peak memory | 3.1 GB | 4.1 GB | > **Note**: FP32 is slightly faster because it runs SGEMM directly without the FP16↔FP32 cast overhead. FP16 uses ~1 GB less storage on disk but more runtime memory (the cast creates FP32 copies). Both use the RVV SGEMM kernel for the actual compute.
Author
Parents
Loading