llama.cpp RISC-V 64 交叉编译实战:面向 SpacemiT SoC 的 IME 矩阵加速构建与 QEMU 仿真验证
【免费下载链接】llama.cppLLM inference in C/C++项目地址: https://gitcode.com/GitHub_Trending/ll/llama.cpp
本文基于仓库内 docs/build-riscv64-spacemit.md 展开,完整覆盖在 x86 主机上交叉编译 llama.cpp 以运行于 SpacemiT(香山/X60、A100 等)RISC-V 64 位 SoC 的全流程:工具链准备、CMake 构建选项、QEMU 仿真运行、矩阵量化类型支持矩阵,并结合ggml/src/ggml-cpu/spacemit/源码深入解释 IME1/IME2 两套矩阵扩展的自动检测与量化内核分发机制。读完后,你可以独立完成一次可部署的 riscv64 构建、在无 RISC-V 硬件的主机上仿真验证,并理解不同量化格式在不同芯片上的加速路径选择。
适用范围与硬件背景
该构建文档仅针对 SpacemiT 的 RISC-V SoC(原文档开头即以 IMPORTANT 注明)。从运行时源码看,llama.cpp 支持的 SpacemiT 核心架构定义在 ggml/src/ggml-cpu/spacemit/ime_env.h 中:
| 架构 ID | 枚举值 | 说明 |
|---|---|---|
core_arch_x60 | 0x503C | 通用计算核心(X60) |
core_arch_x100 | 0x5064 | X100 |
core_arch_x200 | 0x50C8 | X200 |
core_arch_a60 | 0xA03C | AI 矩阵核心(IME1 能力) |
core_arch_a100 | 0xA064 | AI 矩阵核心(IME2 能力) |
core_arch_a200 | 0xA0C8 | A200 |
运行时的核心识别逻辑在 ime_env.cpp:解析/proc/cpuinfo中每个 processor 的marchid,并与内置映射表比对。文档性能章节给出的marchid(如 X60 为0x8000000058000001、A100 为0x8000000041000002)与映射表一致,可印证芯片型号识别方式。
两套加速能力在 ggml/src/ggml-cpu/cmake/FindSMTIME.cmake 中定义:
- IME1:通过尝试编译内联汇编
vmadot v2, v0, v1检测,能力齐备则定义RISCV64_SPACEMIT_IME1; - IME2:需要
vmadot ... , i4(4-bit 点积累加)同时支持vpack.vv与vnspack.vv(打包/解包指令)才定义RISCV64_SPACEMIT_IME2; - 若编译器为 GCC ≥ 15,march 字符串还会追加
_xsmtvdotii(见 ggml/src/ggml-cpu/CMakeLists.txt)。
检测出的规格以宏的形式注入编译,见 CMakeLists.txt:target_compile_definitions(... GGML_USE_CPU_RISCV64_SPACEMIT ${RISCV64_SPACEMIT_IME_SPEC}),随后加入spacemit/目录下的全部内核源文件(ime.cpp、ime1_kernels.cpp、ime2_kernels.cpp、rvv_kernels.cpp、spine_mem_pool.cpp等)。
第一步:准备 RISC-V 交叉工具链
在 x86_64 主机上交叉编译,先下载 SpacemiT 官方工具链(来自原文档):
wget https://github.com/spacemit-com/toolchain/releases/download/v1.2.4/spacemit-toolchain-linux-glibc-x86_64-v1.2.4.tar.xz解压后必须导出根目录环境变量,这是构建的硬性前提:
export RISCV_ROOT_PATH={your_compiler_path}工具链文件 cmake/riscv64-spacemit-linux-gnu-gcc.cmake 的机制值得注意:
- 若主机本身就是 riscv 架构(
CMAKE_HOST_SYSTEM_PROCESSOR以riscv开头),则走本机原生编译分支,不再需要交叉工具链; - 否则从
RISCV_ROOT_PATH环境变量读取编译器路径,未设置时直接FATAL_ERROR(第 9–13 行),并配置riscv64-unknown-linux-gnu-gcc/g++/strip与 sysroot; - 统一追加编译标志(第 27–29 行):
set(CMAKE_C_FLAGS "-march=rv64gcv_zfh_zvfh_zba_zicbop -mabi=lp64d -fno-tree-vectorize -fno-tree-loop-vectorize ${CMAKE_C_FLAGS}")其中-fno-tree-vectorize系列标志用于关闭 GCC 的自动向量化,因为 SpacemiT 内核使用的是显式 RVV/IME 汇编,自动向量化反而可能干扰;链接阶段追加-latomic。此外CMAKE_FIND_ROOT_PATH_MODE_*设置为ONLY/NEVER,确保交叉链接只使用目标 sysroot 中的库与头文件。
第二步:CMake 配置与构建
原文档给出的完整构建脚本如下(需启用GGML_CPU_RISCV64_SPACEMIT,并配合 RISC-V 向量扩展选项):
cmake -B build \ -DCMAKE_BUILD_TYPE=Release \ -DGGML_CPU_RISCV64_SPACEMIT=ON \ -DGGML_CPU_REPACK=OFF \ -DLLAMA_OPENSSL=OFF \ -DGGML_RVV=ON \ -DGGML_RV_ZVFH=ON \ -DGGML_RV_ZFH=ON \ -DGGML_RV_ZICBOP=ON \ -DGGML_RV_ZIHINTPAUSE=ON \ -DGGML_RV_ZBA=ON \ -DCMAKE_TOOLCHAIN_FILE=${PWD}/cmake/riscv64-spacemit-linux-gnu-gcc.cmake \ -DCMAKE_INSTALL_PREFIX=build/installed cmake --build build --parallel $(nproc) --config Release pushd build make install popd各选项的作用(结合源码逐一说明):
| 选项 | 作用与依据 |
|---|---|
GGML_CPU_RISCV64_SPACEMIT=ON | 总开关。开启后 CMake 引入FindSMTIME.cmake做 IME 能力探测,并把ggml-cpu/spacemit/下 12 个源文件加入编译(见 CMakeLists.txt) |
GGML_RVV=ON | 启用标准 RISC-V 向量扩展(V 扩展)基线路径。march 字符串在rv64gc基础上追加v(CMakeLists.txt) |
GGML_RV_ZFH/GGML_RV_ZVFH | 单精度浮点压缩(zfh)与向量浮点压缩(zvfh)。ime.cpp 中显式检查__riscv_zfh与__riscv_zvfh宏,缺失则直接#error中断编译,所以这两项是硬依赖 |
GGML_RV_ZBA | bitmanip 扩展,同样是 ime.cpp 强制检查项 |
GGML_RV_ZICBOP/GGML_RV_ZIHINTPAUSE | 缓存预取与线程暂停提示指令,用于多线程内核同步的优化,属可选增强 |
GGML_CPU_REPACK=OFF | 关闭通用的 repack 后端缓冲区。从源码结构看,SpacemiT 自带专用的 repack 缓冲与张量布局重排(spacemit/repack.cpp),关闭通用 repack 避免两条路径冲突 |
LLAMA_OPENSSL=OFF | 交叉编译环境下关闭 OpenSSL 依赖,减少目标平台库的查找负担 |
CMAKE_TOOLCHAIN_FILE=...riscv64-spacemit-linux-gnu-gcc.cmake | 指定上文分析的 SpacemiT 专用工具链文件 |
CMAKE_INSTALL_PREFIX=build/installed | 安装输出目录,供make install使用 |
构建产物为build/bin/下的llama-cli、llama-server等可执行文件。
第三步:QEMU 仿真验证(无 RISC-V 硬件时)
原文档提供了在 x86 等架构上用 QEMU 仿真运行构建产物的方法:
- 下载 SpacemiT 定制版 QEMU:
wget https://archive.spacemit.com/spacemit-ai/qemu/jdsk-qemu-v0.0.14.tar.gz- 运行仿真(以
llama-cli加载 Qwen2.5-0.5B 模型为例):
export QEMU_ROOT_PATH={your QEMU file path} export RISCV_ROOT_PATH_IME1={your RISC-V compiler path} ${QEMU_ROOT_PATH}/bin/qemu-riscv64 -L ${RISCV_ROOT_PATH_IME1}/sysroot \ -cpu max,vlen=256,elen=64,vext_spec=v1.0 \ ${PWD}/build/bin/llama-cli -m ${PWD}/models/Qwen2.5-0.5B-Instruct-Q4_0.gguf -t 1要点解析:
-L ${RISCV_ROOT_PATH_IME1}/sysroot指定 guest 的库搜索根目录,即交叉工具链自带的 glibc sysroot,保证动态链接可解析;-cpu max,vlen=256,elen=64,vext_spec=v1.0选择 QEMU 最完整的 CPU 模型,向量寄存器长度设为 256 位(与 X60 的 RVV 宽度匹配),向量扩展规范锁定为 v1.0;- 仿真主要用于功能验证(指令正确性、模型加载、推理链路),不代表真实性能,性能数据以真机运行为准。
另外,仿真环境还有一个特殊处理:QEMU 下/proc/cpuinfo拿不到真实的marchid,spine_core_info::get_spine_core_info()会返回空列表,此时 ime_env.cpp 会回退到读取SPACEMIT_CORE_ARCH环境变量(十六进制架构 ID)来伪造核心架构信息;若两者都拿不到,构造函数会直接抛出 "Failed to get SPACEMIT_CORE_ARCH from environment or failed to parse it from /proc/cpuinfo" 异常。因此仿真 SpacemiT 后端时,建议按目标芯片设置该变量(例如SPACEMIT_CORE_ARCH=A064模拟 A100 的 IME2 路径)。
量化类型支持矩阵:X60 与 A100
原文档给出了矩阵乘法量化支持表:
| 量化类型 | X60 | A100 |
|---|---|---|
| Q2_K | ✅ | |
| Q3_K | ✅ | |
| Q4_0 | ✅ | ✅ |
| Q4_1 | ✅ | ✅ |
| Q4_K | ✅ | ✅ |
| Q5_0 | ✅ | |
| Q5_1 | ✅ | |
| Q5_K | ✅ | |
| Q6_K | ✅ | |
| Q8_0 | ✅ |
这张表与源码中的 repack 类型分发表完全对应。ggml_riscv64_spacemit_get_optimal_repack_type 按张量类型选择专用矩阵内核,其选择逻辑同时受编译宏(RISCV64_SPACEMIT_IME1/IME2)与运行时核心架构(use_ime1/use_ime2)双重约束:
- IME1 路径(X60/A60、X100 核心,要求行维度
ne[1] % 16 == 0):仅 Q4_0、Q4_1、Q4_K 三种类型有 16×32 形状的 IME1 内核——与表中 X60 一列严格一致; - IME2 路径(A100 核心,要求
ne[1] % 32 == 0):Q2_K、Q3_K、Q4_0(另有ne[0] % 256 == 0时的 32×256 变体)、Q4_1、Q4_K、Q5_0、Q5_1、Q5_K、Q6_K、Q8_0 全部具备 32×32 形状的 IME2 内核——与表中 A100 一列严格一致; - 未命中任何专用内核的张量会回退到通用 RVV 基线实现(
rvv_impl),保证可运行但吞吐较低; GGML_TYPE_MXFP4在 ime.cpp 中尚为 TODO 注释状态,暂未启用。
值得注意的一个细节:IME1 与 IME2 的选择由运行时核心架构自动决定(ime_env.cpp:perfer_core_arch_id为 A60/X100 时置use_ime1,为 A100 时置use_ime2)。X60 SoC 的混合核心(通用核 + 少量 AI 核)在初始化时有专门处理:8 核且前 4 核为 x60 架构时,会把前 4 核按 a60 对待(ime_env.cpp),这正是 "X60 只支持 Q4_0/Q4_1/Q4_K" 的硬件根源。
运行时调优环境变量
除构建期选项外,SpacemiT 运行时还提供一组环境变量(全部解析逻辑位于 ggml/src/ggml-cpu/spacemit/ime_env.cpp),原文档未展开,此处补充:
| 环境变量 | 取值 | 作用 |
|---|---|---|
SPACEMIT_CORE_ARCH | 十六进制架构 ID(如A064) | 核心列表为空时(典型场景:QEMU 仿真)伪造核心架构,取值见上文架构 ID 表 |
SPACEMIT_PERFER_CORE_ARCH | 十六进制架构 ID | 指定优先使用的核心架构;未设置时默认自动挑选架构号高字节为0xA的 AI 核心(A 系列核) |
SPACEMIT_PERFER_CORE_ID | 逗号分隔的核心 ID 列表(如4,5,6,7) | 精确指定优先核心;列表中任何核心架构与SPACEMIT_PERFER_CORE_ARCH不符会直接 abort |
SPACEMIT_MEM_BACKEND | NONE/POSIX/HPAGE/HPAGE1GB | 内部内存池分配后端:默认HPAGE(透明大页),可切换posix_memalign、1GB 大页或关闭内存池 |
SPACEMIT_DISABLE_TCM | 非0即禁用 | 关闭 TCM(片上计算存储)相关优化;未禁用时自动探测 TCM 可用性并记录块大小(调试日志输出tcm is available, blk_size: ...) |
这些变量在模型加载初始化阶段一次性读取并缓存于全局global_spine_env_info(ime_env.h),配合-v详细日志可以看到核心的解析结果(num_cores、num_perfer_cores、use_ime1/use_ime2、mem_backend、cpu_mask等)。
官方性能参考数据
以下为原文档给出的真机llama-bench风格基准(均为 CPU 后端,n_ubatch=128、启用 Flash Attention),引用时请注意测试条件与模型规模:
Spacemit(R) X60(marchid: 0x8000000058000001,4 线程,RVV 宽度 256 位):
| model | size | params | threads | test | t/s |
|---|---|---|---|---|---|
| qwen35 2B Q4_1 | 1.19 GiB | 1.88 B | 4 | pp128 | 10.32 ± 0.02 |
| qwen35 2B Q4_1 | 1.19 GiB | 1.88 B | 4 | tg128 | 3.07 ± 0.01 |
| qwen3 0.6B Q4_0 | 358.78 MiB | 596.05 M | 4 | pp128 | 49.15 ± 0.25 |
| qwen3 0.6B Q4_0 | 358.78 MiB | 596.05 M | 4 | tg128 | 11.73 ± 0.02 |
Spacemit(R) A100(marchid: 0x8000000041000002,8 线程):
| model | size | params | threads | test | t/s |
|---|---|---|---|---|---|
| qwen3 0.6B Q4_0 | 358.78 MiB | 596.05 M | 8 | pp128 | 565.83 ± 0.31 |
| qwen3 0.6B Q4_0 | 358.78 MiB | 596.05 M | 8 | tg128 | 55.77 ± 0.02 |
| qwen3 4B Q4_0 | 2.21 GiB | 4.02 B | 8 | pp128 | 79.74 ± 0.04 |
| qwen3 4B Q4_0 | 2.21 GiB | 4.02 B | 8 | tg128 | 11.29 ± 0.00 |
| qwen3moe 30B.A3B Q4_0 | 16.18 GiB | 30.53 B | 8 | pp128 | 57.88 ± 0.31 |
| qwen3moe 30B.A3B Q4_0 | 16.18 GiB | 30.53 B | 8 | tg128 | 12.79 ± 0.00 |
| qwen35 2B Q4_1 | 1.19 GiB | 1.88 B | 8 | pp128 | 115.23 ± 0.04 |
| qwen35 2B Q4_1 | 1.19 GiB | 1.88 B | 8 | tg128 | 16.49 ± 0.01 |
| gemma4 E4B Q4_K - Medium | 4.76 GiB | 7.52 B | 8 | pp128 | 21.13 ± 0.01 |
| gemma4 E4B Q4_K - Medium | 4.76 GiB | 7.52 B | 8 | tg128 | 5.66 ± 0.00 |
从数据可以看出两点:A100 的 IME2 矩阵核心在 0.6B 小模型上的 prompt 处理吞吐(565 t/s)显著高于 X60(49 t/s),印证了 IME2 更宽的矩阵单元;而 X60 上测试的模型均为 Q4_1/Q4_0 量化,正好落在 IME1 支持矩阵内——若给 X60 使用 Q2_K/Q5_K 等量化则会退回 RVV 基线路径。
小结:关键路径速查
| 阶段 | 关键命令 / 文件 |
|---|---|
| 工具链 | 设置RISCV_ROOT_PATH;工具链文件 cmake/riscv64-spacemit-linux-gnu-gcc.cmake |
| IME 能力探测 | ggml/src/ggml-cpu/cmake/FindSMTIME.cmake(编译宏RISCV64_SPACEMIT_IME1/IME2) |
| 构建 | cmake -B build -DGGML_CPU_RISCV64_SPACEMIT=ON ...(完整脚本见上文第二步) |
| 仿真 | qemu-riscv64 -L <sysroot> -cpu max,vlen=256,elen=64,vext_spec=v1.0 ...;必要时设SPACEMIT_CORE_ARCH |
| 内核分发 | ggml/src/ggml-cpu/spacemit/ime.cpp(量化类型 → IME1/IME2/RVV 内核选择) |
| 运行调优 | SPACEMIT_PERFER_CORE_ARCH、SPACEMIT_PERFER_CORE_ID、SPACEMIT_MEM_BACKEND、SPACEMIT_DISABLE_TCM(解析于 ime_env.cpp) |
需要强调的是:该路径只适用于 SpacemiT SoC;其他 RISC-V 64 平台(如通用 RVV 芯片)应走不带GGML_CPU_RISCV64_SPACEMIT的标准GGML_RVV构建。所有性能数字仅反映文档所列机型与量化组合,换用其他硬件或量化类型前应先自行基准测试。
【免费下载链接】llama.cppLLM inference in C/C++项目地址: https://gitcode.com/GitHub_Trending/ll/llama.cpp
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考