diff --git a/docs/doc/assets/rvv_performance_comparison.jpg b/docs/doc/assets/rvv_performance_comparison.jpg new file mode 100644 index 00000000..c7c2fd6f Binary files /dev/null and b/docs/doc/assets/rvv_performance_comparison.jpg differ diff --git a/docs/doc/en/pro/rvv.md b/docs/doc/en/pro/rvv.md new file mode 100644 index 00000000..ae27c1df --- /dev/null +++ b/docs/doc/en/pro/rvv.md @@ -0,0 +1,485 @@ +--- +title: Using RVV Acceleration +--- + +## Introduction + +MaixPy ships an `rvv` Python extension module that hardware-accelerates NumPy-compatible vector and matrix operations on platforms with the RISC-V Vector extension (RVV), such as SG2002 / C906FDV. On platforms without RVV it falls back to a scalar implementation automatically. + +- **Module name**: `rvv` +- **Target platform**: SG2002 / C906FDV with RVV 0.7.1 +- **Data type**: `float32` only +- **Design goals**: + - Accept NumPy `ndarray` or any object implementing the buffer protocol + - Convert inputs internally to the `float32` + C-contiguous buffers the kernel expects + - Return `numpy.ndarray` when NumPy is available (pybind11 `py::array_t`) + - Provide a scalar fallback so the same source can be built and tested on non-RISC-V hosts + +Source code and release notes: [yangwenjie1231/sg2002_rvv](https://github.com/yangwenjie1231/sg2002_rvv). + +## Installation + +Install the prebuilt wheel on MaixCAM: + +```bash +pip install --force-reinstall ./clib/rvv-0.1.3-py3-none-any.whl +``` + +You can then check whether RVV acceleration is available, and fall back to CPU computation when it is not: + +```python +try: + import rvv + # Check that the rvv module exposes the required functions + if hasattr(rvv, 'add') and hasattr(rvv, 'sub') and hasattr(rvv, 'norm_l2'): + _RVV_AVAILABLE = True + print("✓ RVV hardware acceleration available") + else: + _RVV_AVAILABLE = False + rvv = None + print("⚠ rvv module found but missing required functions, falling back to CPU") +except ImportError: + _RVV_AVAILABLE = False + rvv = None + print("⚠ rvv module unavailable, falling back to CPU") +``` + +> **Note**: the wheel itself does not depend on NumPy (`install_requires=[]`). However, passing `numpy.ndarray` inputs, or running comparison tests against NumPy, requires NumPy to be installed in the target environment. On embedded Linux, building or installing NumPy is usually not possible. + +## Performance comparison + +![RVV vs NumPy performance comparison](../../assets/rvv_performance_comparison.jpg) + +On SG2002, element-wise operations such as `add` / `sub` / `scale` show the clearest RVV gains. Whether `matmul` beats NumPy depends on whether NumPy is linked against a high-performance BLAS — embedded NumPy builds usually are not, or perform poorly. + +## Input data model + +All `rvv` functions read their inputs through the **buffer protocol** (PEP 3118). + +### Supported input types + +- `numpy.ndarray(dtype=np.float32)` +- Other objects implementing the buffer protocol (some tensor libraries, custom buffers) + +### Hard requirements + +- **dtype must be float32** + - PEP 3118 `format == 'f'` + - `itemsize == 4` +- **Must be C-contiguous (row-major contiguous)** + - Non-contiguous or sliced views (strides that do not describe a contiguous layout) raise an exception + +### Automatic conversion + +The internal `as_f32_buffer()` tries the NumPy path first: + +- `py::array_t` + +This means: + +- When NumPy is available, `float64` or non-contiguous arrays are copied/converted to contiguous `float32` before computation. +- When NumPy is unavailable, only the generic buffer path is used, and inputs that violate the requirements above raise an error immediately. + +For zero-copy behaviour and best performance, make sure the input already satisfies the requirements: + +```python +x = np.ascontiguousarray(x, dtype=np.float32) +``` + +## API reference + +The top-level module is named `rvv` and provides the following functions: + +| Function | Description | +| --- | --- | +| `rvv.add(a, b)` | 1-D element-wise addition | +| `rvv.sub(a, b)` | 1-D element-wise subtraction | +| `rvv.scale(a, k)` | 1-D vector scaled by a scalar | +| `rvv.dot(a, b)` | 1-D dot product (inner product) | +| `rvv.norm_l2(a)` | 1-D L2 norm | +| `rvv.matmul(A, B)` | 2-D matrix multiplication | + +### rvv.add(a, b) -> ndarray[float32] + +**What it does**: element-wise addition. + +**Parameters**: + +- `a`: 1-D float32 buffer (expected `ndim=1`) +- `b`: 1-D float32 buffer (expected `ndim=1`) + +**Returns**: a 1-D `float32` array with the same length as `a` + +**Errors**: + +- `ValueError` + - `a` or `b` is not 1-D: `a must have ndim=1, got ndim=...` + - `a` and `b` have different lengths: `add: a and b must have the same length` + - input is not C-contiguous: `a must be C-contiguous float32 buffer` +- `TypeError`: input is not float32 (`format != 'f'` or `itemsize != 4`) + +**Example**: + +```python +import numpy as np +import rvv + +a = np.arange(8, dtype=np.float32) +b = np.ones(8, dtype=np.float32) +print(rvv.add(a, b)) +``` + +### rvv.sub(a, b) -> ndarray[float32] + +**What it does**: element-wise subtraction, i.e. `out[i] = a[i] - b[i]`. + +Parameters, return value and errors are the same as `add`; the two vectors must have equal length. + +```python +import numpy as np +import rvv + +a = np.arange(8, dtype=np.float32) +b = np.ones(8, dtype=np.float32) +print(rvv.sub(a, b)) +``` + +### rvv.scale(a, k) -> ndarray[float32] + +**What it does**: scales a vector by a scalar. + +**Parameters**: + +- `a`: 1-D float32 buffer +- `k`: Python `float` + +**Returns**: a 1-D float32 array + +**Errors**: `ValueError` / `TypeError`, validated the same way as `add` + +```python +import numpy as np +import rvv + +a = np.arange(8, dtype=np.float32) +print(rvv.scale(a, 0.5)) +``` + +### rvv.dot(a, b) -> float + +**What it does**: dot product (inner product), i.e. `sum_i a[i] * b[i]`. + +**Parameters**: + +- `a`: 1-D float32 buffer +- `b`: 1-D float32 buffer + +**Returns**: a Python `float` + +**Errors**: + +- `ValueError`: length mismatch, `dot: a and b must have the same length` +- dtype / contiguity / ndim errors as above + +```python +import numpy as np +import rvv + +a = np.arange(8, dtype=np.float32) +print(rvv.dot(a, a)) +``` + +### rvv.norm_l2(a) -> float + +**What it does**: L2 (Euclidean) norm, defined as `sqrt(dot(a, a))`. + +**Parameters**: `a`: 1-D float32 buffer + +**Returns**: a Python `float` + +**A note on numerical error**: `dot` and `norm_l2` are reduction operations. For very large vectors (for example 1e6 elements), different reduction orders (RVV blocking, scalar loops, NumPy/BLAS vectorisation) can produce a **very small relative error** compared with NumPy. Compare with a relative tolerance (for example `1e-4 ~ 1e-3`) rather than strict equality. + +```python +import numpy as np +import rvv + +a = np.random.randn(1000000).astype(np.float32) +print(rvv.norm_l2(a)) +``` + +### rvv.matmul(A, B) -> ndarray[float32] + +**What it does**: matrix multiplication. + +- Input: `A` of shape `(m, k)`, `B` of shape `(k, n)` +- Output: `C` of shape `(m, n)` + +**Parameters**: + +- `A`: 2-D float32 buffer (`ndim=2`, C-contiguous, row-major) +- `B`: 2-D float32 buffer (`ndim=2`, C-contiguous, row-major) + +**Returns**: a 2-D float32 array + +**Errors**: + +- `ValueError` + - dimension is not 2: `A must have ndim=2, got ndim=...` + - shape mismatch: `matmul: shape mismatch: A is (m,k) but B is (k2,n)` + +```python +import numpy as np +import rvv + +A = np.random.randn(2, 3).astype(np.float32) +B = np.random.randn(3, 4).astype(np.float32) +C = rvv.matmul(A, B) +print(C.shape) +``` + +### Combined example + +```python +import numpy as np +import rvv + +a = np.arange(8, dtype=np.float32) +b = np.arange(8, dtype=np.float32) + +print(rvv.add(a, b)) +print(rvv.sub(a, b)) +print(rvv.scale(a, 2.0)) +print(rvv.dot(a, b)) +print(rvv.norm_l2(a)) + +A = np.arange(6, dtype=np.float32).reshape(2, 3) +B = np.arange(12, dtype=np.float32).reshape(3, 4) +print(rvv.matmul(A, B)) +``` + +## Common errors + +### `... must be float32-compatible buffer ...` + +The input is not float32. Fix: + +```python +x = x.astype(np.float32, copy=False) +``` + +### `... must be C-contiguous float32 buffer` + +The input is a non-contiguous view, such as a slice or a transpose. Fix: + +```python +x = np.ascontiguousarray(x, dtype=np.float32) +``` + +### `add/sub/dot: a and b must have the same length` + +The two vectors have different lengths. + +## Performance tips + +- Make sure inputs are **float32** and **C-contiguous** to avoid unnecessary copies. +- On large arrays, `add` / `sub` / `scale` are where RVV gains show up most clearly. +- Whether `matmul` beats NumPy depends on whether NumPy is linked against a high-performance BLAS — embedded NumPy builds usually are not, or perform poorly. + +## Building from source + +This section is for users who need to build the module on SG2002 themselves, or to develop on top of it. + +### Implementation map + +- Python bindings: `rvv_ext/main/src/bind_rvv.cpp` +- C++ public interface declarations: `rvv_ext/main/include/rvv.hpp` +- RVV 0.7.1 implementation: `rvv_ext/main/src/rvv_rvv071.cpp` (compiled only when `__riscv_vector` is defined) +- Scalar implementation: `rvv_ext/main/src/rvv_scalar.cpp` + +### Choosing a build mode: cross-compile (MaixCAM) vs host test (Linux) + +`main/CMakeLists.txt` supports two build modes: + +- **Cross-compile to SG2002 (recommended)**: enable `MaixCam` + - Enables the RVV ISA flags (such as `-march=rv64imafdcv0p7xthead`) + - Links against the SDK's `python3_lib_maixcam_musl_3.11.6` headers/libraries, avoiding a missing `Python.h` +- **Host Linux test**: enable `Linux` + - Tries the system `Python.h` first (`python3-dev`), then falls back to the SDK python component + +The target Python is **3.11.6** (SDK component `python3_lib_maixcam_musl_3.11.6`). + +> If you see `fatal error: Python.h: No such file or directory`, the current build mode did not pick up the Python development headers. + +### Build caveats + +- Always run the build from the project root `rvv_ext/`, not from `rvv_ext/main/`. Otherwise the configuration is generated under `rvv_ext/main/build/...` and the output looks like an infinite loop. +- The `MY_SDK_PATH` environment variable must be set, otherwise the build reports a missing `/tools/cmds`. +- When cross-compiling, `TOOLCHAIN_PATH` **must be an absolute path**, otherwise CMake reports `TOOLCHAIN_PATH set error: ...`. +- `distclean` removes `build/`, after which `cmake --build build ...` fails with `Error: could not load cache`. You must re-run `python3 project.py build` to regenerate `build/CMakeCache.txt` first. +- NumPy usually **cannot be built or installed** on embedded Linux. This library's wheel does not depend on NumPy, but comparing results or speed against NumPy requires NumPy in the target environment. +- `norm_l2` / `dot` can differ slightly from NumPy on very large vectors (for example 1e6) due to floating-point error from reduction ordering. Compare with a relative tolerance, not strict equality. + +### Building with Auto-bind-Python-from-CC--main + +This project uses the same build system as `Auto-bind-Python-from-CC--main/examples/demo`. + +**0) Set the SDK environment variable (required)** + +```bash +export MY_SDK_PATH=/root/xmusic/Auto-bind-Python-from-CC--main/Auto-bind-Python-from-CC--main +``` + +**1) Open menuconfig** + +```bash +cd /root/xmusic/rvv_ext +python3 project.py menuconfig +``` + +**2) Configure the toolchain (cross-compiling to SG2002)** + +- `-mcpu=c906fdv` +- `-march=rv64imafdcv0p7xthead` +- `-mcmodel=medany` +- `-mabi=lp64d` + +You can also configure without menuconfig by passing flags: + +```bash +python3 project.py config \ + --toolchain /root/xmusic/host-tools/gcc/riscv64-linux-musl-x86_64/bin \ + --toolchain-prefix riscv64-unknown-linux-musl- +``` + +Or by using the environment variable read by the project's top-level `CMakeLists.txt`: + +```bash +export MY_TOOLCHAIN_PATH=/root/xmusic/toolchains/maixcam/host-tools/gcc/riscv64-linux-musl-x86_64/bin +``` + +**3) Build and produce the wheel** + +```bash +python3 project.py build +``` + +Artifacts: + +- Compiled extension: `build/main/libmain.so` +- Wheel: `dist/*.whl` + +**4) Verify RVV is enabled (optional)** + +After `python3 project.py build`, check whether the compile command lines in the build log contain: + +- `-march=rv64imafdcv0p7xthead` + +If the flag is present, `__riscv_vector` should be defined and the RVV implementation (`rvv_rvv071.cpp`) is compiled into the library. + +### IDE code completion + +`rvv` is a binary extension module (`rvv.so`), so an IDE cannot infer function signatures from source the way it can for pure Python. The project provides type hints through **PEP 561**: + +- `rvv_ext/rvv.pyi`: module stub providing signatures and docs for `add/sub/scale/dot/norm_l2/matmul` +- `rvv_ext/py.typed`: marker file telling tools and IDEs that the package ships type information + +Both are included in the wheel (see `rvv_ext/setup.py`). + +**Option A: install the wheel to get completion (recommended)** + +```bash +pip install --no-deps --force-reinstall dist/*.whl +``` + +**Option B: get completion while developing directly in the source tree** + +- Make sure your IDE's interpreter/project index can see `rvv_ext/rvv.pyi` +- In PyCharm, mark `rvv_ext/` as **Sources Root** (or add it to `PYTHONPATH`) + +> Either way, the runtime import is still `import rvv`. + +### Testing + +Tests live in `rvv_ext/tests` and require NumPy plus pytest: + +```bash +pytest -q +``` + +A performance comparison script that does not depend on pytest: + +```bash +python3 tests/test_rvv.py +``` + +On SG2002 you can also run the micro-benchmark: + +```bash +python3 tests/bench_perf.py +``` + +### Troubleshooting + +**`Error: could not load cache`** + +Raised by `cmake --build build ...` when the CMake cache (`build/CMakeCache.txt`) is missing. Common causes: + +- You ran `python3 project.py distclean` and did **not** re-run the CMake configure step afterwards +- The `build/` directory was deleted or is empty + +Fix: + +```bash +cd /path/to/rvv_ext + +# Re-run configure (generates build/CMakeCache.txt) +python3 project.py build + +# Then compile +cmake --build build --target main -- -j"$(nproc)" +``` + +**`setup.py` reports `Native library not found: build/main/libmain.so`** + +This means the extension has not been built yet, or it was built into a different directory. Check with: + +```bash +find build -maxdepth 4 -name 'libmain.so' -o -name '*.so' | sort +``` + +If `libmain.so` exists but is not under `build/main/`, adjust `SO_FILE_PATH` in `setup.py` accordingly. + +### Copy-paste commands (embedded Linux) + +```bash +cd /path/to/rvv_ext # adjust to your real path + +# (Optional) full clean: removes build/ and CMakeCache.txt +python3 project.py distclean + +# 1) Configure CMake (re-creates build/ and build/CMakeCache.txt) +python3 project.py build + +# Sanity check (should exist after configure) +ls -la build/CMakeCache.txt + +# 2) Compile the extension shared library (creates build/main/libmain.so) +cmake --build build --target main -- -j"$(nproc)" + +# Sanity check (should exist after compile) +ls -la build/main/libmain.so + +# 3) Build the wheel (creates dist/*.whl) +python3 setup.py bdist_wheel + +# 4) List the wheel +ls -la dist +``` + +> If you only want to remove compiled objects but keep the CMake cache, prefer `python3 project.py clean` over `distclean`. + +## License + +This project is licensed under LGPL-3.0. See the LICENSE file in the repository for details. + +Copyright (C) 2026 ywj <yangwenjie1231@qq.com> diff --git a/docs/doc/en/sidebar.yaml b/docs/doc/en/sidebar.yaml index 37febd53..f12bba96 100644 --- a/docs/doc/en/sidebar.yaml +++ b/docs/doc/en/sidebar.yaml @@ -273,3 +273,5 @@ items: label: MaixCDK development - file: pro/compile_os.md label: Build OS + - file: pro/rvv.md + label: Using RVV Acceleration diff --git a/docs/doc/zh/pro/rvv.md b/docs/doc/zh/pro/rvv.md index 0767a126..5385bcc7 100644 --- a/docs/doc/zh/pro/rvv.md +++ b/docs/doc/zh/pro/rvv.md @@ -1,113 +1,75 @@ --- title: 使用RVV加速 --- -## License -Copyright (C) 2026 ywj +## 简介 -This library is free software; you can redistribute it and/or modify it -under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation. +MaixPy 提供了 `rvv` Python 扩展模块,在支持 RISC-V 向量扩展(RVV)的 SG2002 / C906FDV 平台上,为 NumPy 兼容的向量与矩阵运算提供硬件加速;在没有 RVV 的平台上自动回退到标量实现。 -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. +- **模块名**:`rvv` +- **目标平台**:SG2002 / C906FDV,支持 RVV 0.7.1 +- **数据类型**:仅支持 `float32` +- **设计目标**: + - 直接接受 NumPy `ndarray` 或实现了 buffer protocol 的输入 + - 内部自动转换为内核期望的 `float32` + C 连续缓冲区 + - NumPy 可用时返回 `numpy.ndarray`(pybind11 `py::array_t`) + - 提供标量回退,使同一份源码可以在非 RISC-V 主机上构建和测试 -You should have received a copy of the GNU Lesser General Public -License along with this library. If not, see . +源码仓库与发布说明见 [yangwenjie1231/sg2002_rvv](https://github.com/yangwenjie1231/sg2002_rvv)。 -SPDX-License-Identifier: LGPL-3.0 +## 安装 -# sg2002_rvv v0.1.0 — 首次开源发布 -仓库地址:[https://github.com/yangwenjie1231/sg2002_rvv/releases](https://github.com/yangwenjie1231/sg2002_rvv/releases)记得给个star,手动狗头 -发布日期:2026-03-03 +在 MaixCAM 上安装预编译的 wheel 包: -概述 -本次发布公开了 sg2002_rvv 的实现、示例、测试与文档。项目旨在为 RISC‑V 向量扩展(RVV)相关研究与工程提供参考实现与可复现的基准。 - -主要变更 -- 初始开源:公开 src/, examples/, scripts/, docs/ -- 添加础构建脚本与单元测试 -- 提供性能基准脚本与示例数据 - -许可 -本仓库采用LGPL3.0 许可(请见 LICENSE 文件)。 +```bash +pip install --force-reinstall ./clib/rvv-0.1.3-py3-none-any.whl +``` -贡献 -欢迎通过 Issues 和 Pull Requests 参与贡献。详细指南请见 CONTRIBUTING.md。 +安装后可以这样检查 RVV 加速是否可用,并在不可用时降级到 CPU 计算: -联系方式 -维护者:yangwenjie1231(https://github.com/yangwenjie1231) -# 性能对比 -![](https://maixhub.com/public/sharing/24278-2a9ef5bc220a4c0d8fc973c12f55f93f.jpg) -- 导入示例 ```python try: import rvv - # 检查rvv模块是否有必要的函数 + # 检查 rvv 模块是否有必要的函数 if hasattr(rvv, 'add') and hasattr(rvv, 'sub') and hasattr(rvv, 'norm_l2'): _RVV_AVAILABLE = True - print("✓ RVV硬件加速可用") + print("✓ RVV 硬件加速可用") else: _RVV_AVAILABLE = False rvv = None - print("⚠ RVV模块存在但缺少必要函数,将使用CPU降级计算") + print("⚠ rvv 模块存在但缺少必要函数,将使用 CPU 降级计算") except ImportError: _RVV_AVAILABLE = False rvv = None - print("⚠ RVV模块不可用,将使用CPU降级计算,并尝试自动安装RVV依赖") - try: - import os - os.system('pip install --force-reinstall ./clib/rvv-0.1.3-py3-none-any.whl') - try: - import rvv - _RVV_AVAILABLE = True - print("✓ RVV模块已安装,将使用RVV硬件加速") - except ImportError: - print("⚠ RVV模块安装后启动失败,请手动安装") - except ImportError: - print("⚠ 无法自动安装RVV依赖,请手动安装") - + print("⚠ rvv 模块不可用,将使用 CPU 降级计算") ``` -# rvv API 文档(SG2002 / C906FDV / RVV 0.7.1) +> **注意**:wheel 本身不依赖 NumPy(`install_requires=[]`)。但若要传入 `numpy.ndarray`、或运行与 NumPy 的对比测试,需要在目标环境安装 NumPy。嵌入式 Linux 上通常无法编译/安装 NumPy。 -本文档描述 `rvv` Python 扩展模块的公共 API。 +## 性能对比 -- 模块名:`rvv` -- 目标平台:RISC-V(SG2002 / C906FDV),支持 RVV 0.7.1 时会启用矢量加速 -- 数据类型:**仅支持 float32** -- 设计目标: - - **兼容 NumPy 的 N 维数组(ndarray)作为输入** - - 在内部自动转换为适合 RVV/kernel 处理的格式(float32 + C 连续) - - 在 NumPy 可用时返回 `numpy.ndarray`(pybind11 `py::array_t`) -- 编译参考:基于[https://github.com/Taoxuan-168/Auto-bind-Python-from-CC-](https://github.com/Taoxuan-168/Auto-bind-Python-from-CC-)并修改了部分代码 -> 安装提示:wheel 本身不依赖 NumPy(`install_requires=[]`)。 -> 但若要传入 `numpy.ndarray`、或运行与 NumPy 的对比测试,需要目标环境安装 NumPy。 +![RVV 与 NumPy 性能对比](../../assets/rvv_performance_comparison.jpg) ---- +在 SG2002 上,`add` / `sub` / `scale` 这类逐元素运算更容易看到 RVV 带来的性能收益;`matmul` 是否快于 NumPy 取决于 NumPy 是否链接了高性能 BLAS(嵌入式环境中的 NumPy 常常没有,或性能有限)。 -## 1. 输入数据模型(重要) +## 输入数据模型 `rvv` 的所有函数都基于 **buffer protocol**(PEP 3118)读取输入。 -### 1.1 支持的输入类型 - -以下输入通常都可以: +### 支持的输入类型 - `numpy.ndarray(dtype=np.float32)` -- 其他实现了 buffer protocol 的对象(如某些张量库/自定义 buffer) +- 其他实现了 buffer protocol 的对象(如某些张量库 / 自定义 buffer) -### 1.2 强制要求 +### 强制要求 - **dtype 必须是 float32** - - PEP3118 `format == 'f'` + - PEP 3118 `format == 'f'` - `itemsize == 4` - **必须是 C-contiguous(行主序连续)** - - 若为非连续/切片视图(stride 不满足连续布局),将抛出异常 + - 若为非连续 / 切片视图(stride 不满足连续布局),将抛出异常 -### 1.3 自动转换规则 +### 自动转换规则 内部的 `as_f32_buffer()` 会优先尝试 NumPy 路径: @@ -115,14 +77,29 @@ except ImportError: 这意味着: -- 如果 NumPy 可用,且你传入 `float64` 或非连续数组,它会复制/转换为连续的 `float32` 再计算。 -- 如果 NumPy 不可用,则只能走通用 buffer 路径,此时不满足上述要求会直接报错。 +- NumPy 可用时,传入 `float64` 或非连续数组会被复制/转换为连续的 `float32` 再计算。 +- NumPy 不可用时,只能走通用 buffer 路径,此时不满足上述要求会直接报错。 ---- +如果你希望"零拷贝"并获得最佳性能,建议在调用前确保输入满足要求: + +```python +x = np.ascontiguousarray(x, dtype=np.float32) +``` + +## API 参考 + +顶层模块名为 `rvv`,提供以下函数: -## 2. 向量运算 API(1-D) +| 函数 | 说明 | +| --- | --- | +| `rvv.add(a, b)` | 1-D 逐元素加法 | +| `rvv.sub(a, b)` | 1-D 逐元素减法 | +| `rvv.scale(a, k)` | 1-D 向量按标量缩放 | +| `rvv.dot(a, b)` | 1-D 点积(内积) | +| `rvv.norm_l2(a)` | 1-D L2 范数 | +| `rvv.matmul(A, B)` | 2-D 矩阵乘法 | -### 2.1 `rvv.add(a, b) -> ndarray[float32]` +### rvv.add(a, b) -> ndarray[float32] **功能**:逐元素加法。 @@ -131,18 +108,15 @@ except ImportError: - `a`:1-D float32 buffer(期望 `ndim=1`) - `b`:1-D float32 buffer(期望 `ndim=1`) -**返回**: - -- `out`:1-D `float32` 数组,长度与 `a` 相同 +**返回**:1-D `float32` 数组,长度与 `a` 相同 **错误**: -- `ValueError`: - - `a` 或 `b` 维度不是 1:`"a must have ndim=1, got ndim=..."` - - `a` 与 `b` 长度不同:`"add: a and b must have the same length"` - - 输入不是 C-contiguous:`"a must be C-contiguous float32 buffer"` -- `TypeError`: - - 输入不是 float32:例如 `format!='f'` 或 `itemsize!=4` +- `ValueError` + - `a` 或 `b` 维度不是 1:`a must have ndim=1, got ndim=...` + - `a` 与 `b` 长度不同:`add: a and b must have the same length` + - 输入不是 C-contiguous:`a must be C-contiguous float32 buffer` +- `TypeError`:输入不是 float32(`format != 'f'` 或 `itemsize != 4`) **示例**: @@ -155,16 +129,11 @@ b = np.ones(8, dtype=np.float32) print(rvv.add(a, b)) ``` ---- - -### 2.2 `rvv.sub(a, b) -> ndarray[float32]` - -**功能**:逐元素减法。 +### rvv.sub(a, b) -> ndarray[float32] -- 语义:`out[i] = a[i] - b[i]` -- 参数/返回/错误与 `add` 相同,长度必须一致。 +**功能**:逐元素减法,语义为 `out[i] = a[i] - b[i]`。 -**示例**: +参数、返回值与错误同 `add`,两个向量长度必须一致。 ```python import numpy as np @@ -175,9 +144,7 @@ b = np.ones(8, dtype=np.float32) print(rvv.sub(a, b)) ``` ---- - -### 2.3 `rvv.scale(a, k) -> ndarray[float32]` +### rvv.scale(a, k) -> ndarray[float32] **功能**:向量按标量缩放。 @@ -186,15 +153,9 @@ print(rvv.sub(a, b)) - `a`:1-D float32 buffer - `k`:Python `float` -**返回**: +**返回**:1-D float32 数组 -- `out`:1-D float32 数组 - -**错误**: - -- `ValueError` / `TypeError`:同 `add` 的 dtype/contiguous/ndim 校验 - -**示例**: +**错误**:`ValueError` / `TypeError`,校验规则同 `add` ```python import numpy as np @@ -204,29 +165,21 @@ a = np.arange(8, dtype=np.float32) print(rvv.scale(a, 0.5)) ``` ---- - -### 2.4 `rvv.dot(a, b) -> float` - -**功能**:点积(内积)。 +### rvv.dot(a, b) -> float -- 语义:`sum_i a[i] * b[i]` +**功能**:点积(内积),语义为 `sum_i a[i] * b[i]`。 **参数**: - `a`:1-D float32 buffer - `b`:1-D float32 buffer -**返回**: - -- Python `float` +**返回**:Python `float` **错误**: -- `ValueError`:长度不一致:`"dot: a and b must have the same length"` -- dtype/连续性/ndim 错误同上 - -**示例**: +- `ValueError`:长度不一致,`dot: a and b must have the same length` +- dtype / 连续性 / ndim 错误同上 ```python import numpy as np @@ -236,30 +189,15 @@ a = np.arange(8, dtype=np.float32) print(rvv.dot(a, a)) ``` ---- - -### 2.5 `rvv.norm_l2(a) -> float` - -**功能**:L2 范数(欧几里得范数)。 - -- 定义:`sqrt(dot(a, a))` +### rvv.norm_l2(a) -> float -**参数**: - -- `a`:1-D float32 buffer - -**返回**: - -- Python `float` +**功能**:L2 范数(欧几里得范数),定义为 `sqrt(dot(a, a))`。 -**数值误差说明(重要)**: +**参数**:`a`:1-D float32 buffer -`dot` 和 `norm` 都是“归约”运算(reduction)。 -当向量很大时(例如 1e6 长度),由于不同实现的归约顺序不同(RVV 分块、标量循环、NumPy/BLAS 向量化等),最终结果可能与 NumPy 有**很小的相对误差**。 +**返回**:Python `float` -建议比较时使用相对误差(例如 `1e-4 ~ 1e-3`)而不是严格相等。 - -**示例**: +**数值误差说明**:`dot` 和 `norm_l2` 都是归约(reduction)运算。当向量很大时(例如 1e6 长度),由于不同实现的归约顺序不同(RVV 分块、标量循环、NumPy/BLAS 向量化等),结果可能与 NumPy 有**很小的相对误差**。比较时建议使用相对误差(例如 `1e-4 ~ 1e-3`),而不是严格相等。 ```python import numpy as np @@ -269,37 +207,25 @@ a = np.random.randn(1000000).astype(np.float32) print(rvv.norm_l2(a)) ``` ---- - -## 3. 矩阵运算 API(2-D) - -### 3.1 `rvv.matmul(A, B) -> ndarray[float32]` +### rvv.matmul(A, B) -> ndarray[float32] **功能**:矩阵乘法。 -- 输入: - - `A`:形状 `(m, k)` - - `B`:形状 `(k, n)` -- 输出: - - `C`:形状 `(m, n)` +- 输入:`A` 形状 `(m, k)`,`B` 形状 `(k, n)` +- 输出:`C` 形状 `(m, n)` **参数**: - `A`:2-D float32 buffer(`ndim=2`,C-contiguous,行主序) - `B`:2-D float32 buffer(`ndim=2`,C-contiguous,行主序) -**返回**: - -- `C`:2-D float32 数组 +**返回**:2-D float32 数组 **错误**: -- `ValueError`: - - 维度不是 2:`"A must have ndim=2, got ndim=..."` - - 形状不匹配: - - `"matmul: shape mismatch: A is (m,k) but B is (k2,n)"` - -**示例**: +- `ValueError` + - 维度不是 2:`A must have ndim=2, got ndim=...` + - 形状不匹配:`matmul: shape mismatch: A is (m,k) but B is (k2,n)` ```python import numpy as np @@ -311,54 +237,7 @@ C = rvv.matmul(A, B) print(C.shape) ``` ---- - -## 4. 性能建议 - -- 确保输入是 **float32** 且 **C-contiguous**,避免不必要的复制。 -- 大数组上,`add/sub/scale` 通常更容易看到 RVV 性能收益。 -- `matmul` 是否快于 NumPy 取决于 NumPy 是否链接了高性能 BLAS(嵌入式环境中 NumPy 常常没有或性能有限)。 - ---- - -## 5. 常见错误与排查 - -### 5.1 `... must be float32-compatible buffer ...` - -说明输入不是 float32。 - -解决: - -```python -x = x.astype(np.float32, copy=False) -``` - -### 5.2 `... must be C-contiguous float32 buffer` - -说明输入是切片/转置等非连续视图。 - -解决: - -```python -x = np.ascontiguousarray(x, dtype=np.float32) -``` - -### 5.3 `add/sub/dot: a and b must have the same length` - -说明向量长度不一致。 - ---- - -## 6. 与实现对应关系(供开发者) - -- Python 绑定:`rvv_ext/main/src/bind_rvv.cpp` -- C++ 公共接口声明:`rvv_ext/main/include/rvv.hpp` -- RVV 0.7.1 实现:`rvv_ext/main/src/rvv_rvv071.cpp`(仅在 `__riscv_vector` 下编译) -- 标量实现:`rvv_ext/main/src/rvv_scalar.cpp` - ---- - -## 7. 最小示例(组合使用) +### 组合使用示例 ```python import numpy as np @@ -367,13 +246,9 @@ import rvv a = np.arange(8, dtype=np.float32) b = np.arange(8, dtype=np.float32) -c = rvv.add(a, b) -d = rvv.sub(a, b) -e = rvv.scale(a, 2.0) - -print(c) -print(d) -print(e) +print(rvv.add(a, b)) +print(rvv.sub(a, b)) +print(rvv.scale(a, 2.0)) print(rvv.dot(a, b)) print(rvv.norm_l2(a)) @@ -382,149 +257,93 @@ B = np.arange(12, dtype=np.float32).reshape(3, 4) print(rvv.matmul(A, B)) ``` +## 常见错误与排查 +### `... must be float32-compatible buffer ...` -# 以下是二次开发可以参考的 -# rvv (SG2002/C906 RVV 加速的 NumPy 运算) - -此文件夹包含一个小型的 C++/pybind11 Python 扩展,提供 **NumPy 兼容** 的向量/矩阵运算,并为 SG2002 (C906) 提供 **RVV 0.7.1** 快速路径。 - -> 目标 Python:**3.11.6**(对应 SDK 组件 `python3_lib_maixcam_musl_3.11.6`)。 - ---- - -## 你可能会遇到的几个关键点 - -- 一定要在项目根目录 `rvv_ext/` 执行构建,不要在 `rvv_ext/main/` 里执行。 - - 否则会生成 `rvv_ext/main/build/...` 的配置并导致输出看起来“无限循环”。 -- 必须设置 SDK 环境变量: - - `MY_SDK_PATH=/root/xmusic/Auto-bind-Python-from-CC--main/Auto-bind-Python-from-CC--main` - - 不设置会报找不到 `/tools/cmds`。 -- 交叉编译时 `TOOLCHAIN_PATH` **必须是绝对路径**,否则 CMake 会报: - - `TOOLCHAIN_PATH set error: ...` -- `distclean` 会删除 `build/`,之后不能直接 `cmake --build build ...`,否则会报: - - `Error: could not load cache` - - 必须先重新执行 `python3 project.py build` 生成 `build/CMakeCache.txt`。 -- 嵌入式 Linux 上通常 **无法编译/安装 NumPy**。本库 **wheel 安装不依赖 NumPy**(`install_requires=[]`)。 - - 但如果你要对比 NumPy 的结果/速度,需要目标环境能装 NumPy。 -- `norm_l2` / `dot` 在超大向量(例如 1e6)上可能与 NumPy 有轻微差异(归约顺序导致浮点误差),应使用相对误差比较,而不是严格相等。 - ---- - -## 输入约束(与 NumPy 兼容的关键点) - -本库的绑定实现位于 `main/src/bind_rvv.cpp`,核心行为如下: - -- 所有运算都是 **float32-only** -- 输入接受: - - NumPy 可用时:优先将输入转换为 **`float32 + C-contiguous`**(`py::array_t`) - - 这意味着 `float64` 或非连续数组会发生 **复制/转换**(这是为了兼容性与稳定性) - - NumPy 不可用时:走 **buffer protocol** 路径 - - 要求 buffer 的 `format == 'f'` 且 `itemsize == 4` - - 要求 **严格 C-contiguous**(否则会抛 `ValueError`) - -如果你希望“零拷贝”并获得最佳性能,建议在调用前确保: +说明输入不是 float32。解决: ```python -x = np.ascontiguousarray(x, dtype=np.float32) +x = x.astype(np.float32, copy=False) ``` ---- - -## IDE 代码提示(自动补全/类型提示) +### `... must be C-contiguous float32 buffer` -由于 `rvv` 是 **二进制扩展模块**(`rvv.so`),IDE 无法像纯 Python 一样从源码推断函数签名。 -本项目已通过 **PEP 561** 的方式提供类型提示: - -- `rvv_ext/rvv.pyi`:模块存根(stub),为 `add/sub/scale/dot/norm_l2/matmul` 提供签名与说明 -- `rvv_ext/py.typed`:标记文件,告知工具/IDE “该包携带类型信息” +说明输入是切片、转置等非连续视图。解决: -并且在打包 wheel 时会把它们一并打入 whl(见 `rvv_ext/setup.py`)。 - -### 方式 A:安装 wheel 后获得提示(推荐) - -在目标机/开发机安装生成的 wheel 后,IDE 通常会自动读取 `.pyi`,为 `import rvv` 提供补全: - -```bash -pip install --no-deps --force-reinstall dist/*.whl +```python +x = np.ascontiguousarray(x, dtype=np.float32) ``` -### 方式 B:在源码目录直接开发时获得提示 - -如果你暂时不安装 wheel,而是在源码目录直接写代码: - -- 确保 IDE 的解释器/项目索引能看到 `rvv_ext/rvv.pyi` -- 可在 PyCharm 中将 `rvv_ext/` 目录标记为 **Sources Root**(或加入 `PYTHONPATH`) - -> 注意:无论哪种方式,运行时导入仍然是 `import rvv`。 - ---- - -## 主要目标 +### `add/sub/dot: a and b must have the same length` -- 直接接受 **NumPy `ndarray` / buffer-protocol** 输入。 -- 内部将输入转换为 **float32 + C连续** 缓冲区(内核期望的格式)。 -- 当可用时使用 RVV(RISC-V 向量扩展)实现(`__riscv_vector`)。 -- 提供标量回退,以便相同的源码可以在非 RISC-V 主机上构建/测试。 +说明两个向量长度不一致。 ---- +## 性能建议 -## Python API(概览) +- 确保输入是 **float32** 且 **C-contiguous**,避免不必要的复制。 +- 大数组上,`add` / `sub` / `scale` 通常更容易看到 RVV 的性能收益。 +- `matmul` 是否快于 NumPy 取决于 NumPy 是否链接了高性能 BLAS(嵌入式环境中 NumPy 常常没有或性能有限)。 -顶层模块名为 `rvv`: +## 二次开发 -- `rvv.add(a, b) -> ndarray` -- `rvv.sub(a, b) -> ndarray` -- `rvv.scale(a, k) -> ndarray` -- `rvv.dot(a, b) -> float` -- `rvv.norm_l2(a) -> float` -- `rvv.matmul(A, B) -> ndarray` +本节面向需要在 SG2002 上自行构建、或基于本模块做二次开发的用户。 -更完整的 API 文档请见:`lib/rvvapi.md`。 +### 与实现对应关系 ---- +- Python 绑定:`rvv_ext/main/src/bind_rvv.cpp` +- C++ 公共接口声明:`rvv_ext/main/include/rvv.hpp` +- RVV 0.7.1 实现:`rvv_ext/main/src/rvv_rvv071.cpp`(仅在 `__riscv_vector` 下编译) +- 标量实现:`rvv_ext/main/src/rvv_scalar.cpp` -## 构建模式选择:交叉编译(MaixCam) vs 主机测试(Linux) +### 构建模式选择:交叉编译(MaixCAM) vs 主机测试(Linux) 项目在 `main/CMakeLists.txt` 中支持两类构建模式: - **交叉编译到 SG2002(推荐)**:启用 `MaixCam` - - 会启用 RVV ISA flags(如 `-march=rv64imafdcv0p7xthead`) - - 会链接 SDK 的 `python3_lib_maixcam_musl_3.11.6` 头文件/库,避免 `Python.h` 缺失 + - 启用 RVV ISA flags(如 `-march=rv64imafdcv0p7xthead`) + - 链接 SDK 的 `python3_lib_maixcam_musl_3.11.6` 头文件/库,避免 `Python.h` 缺失 - **主机 Linux 测试**:启用 `Linux` - - 先尝试 system `Python.h`(`python3-dev`),找不到则回退到 SDK python 组件 + - 先尝试系统 `Python.h`(`python3-dev`),找不到则回退到 SDK python 组件 -> 经验:如果你看到 `fatal error: Python.h: No such file or directory`,说明当前构建模式没有拿到 Python 开发头。 +目标 Python 为 **3.11.6**(对应 SDK 组件 `python3_lib_maixcam_musl_3.11.6`)。 ---- +> 如果你看到 `fatal error: Python.h: No such file or directory`,说明当前构建模式没有拿到 Python 开发头文件。 + +### 构建注意事项 -## 使用 Auto-bind-Python-from-CC--main 构建 (Linux) +- 一定要在项目根目录 `rvv_ext/` 执行构建,不要在 `rvv_ext/main/` 里执行,否则会生成 `rvv_ext/main/build/...` 的配置,输出看起来像"无限循环"。 +- 必须设置 SDK 环境变量 `MY_SDK_PATH`,不设置会报找不到 `/tools/cmds`。 +- 交叉编译时 `TOOLCHAIN_PATH` **必须是绝对路径**,否则 CMake 会报 `TOOLCHAIN_PATH set error: ...`。 +- `distclean` 会删除 `build/`,之后不能直接 `cmake --build build ...`,否则会报 `Error: could not load cache`,必须先重新执行 `python3 project.py build` 生成 `build/CMakeCache.txt`。 +- 嵌入式 Linux 上通常**无法编译/安装 NumPy**。本库 wheel 安装不依赖 NumPy,但若要对比 NumPy 的结果/速度,需要目标环境能装 NumPy。 +- `norm_l2` / `dot` 在超大向量(例如 1e6)上可能与 NumPy 有轻微差异(归约顺序导致的浮点误差),应使用相对误差比较,而不是严格相等。 -此项目使用与 `Auto-bind-Python-from-CC--main/examples/demo` 相同的构建系统。 +### 使用 Auto-bind-Python-from-CC--main 构建 -### 0) 设置 SDK 环境变量(必须) +本项目使用与 `Auto-bind-Python-from-CC--main/examples/demo` 相同的构建系统。 + +**0) 设置 SDK 环境变量(必须)** ```bash export MY_SDK_PATH=/root/xmusic/Auto-bind-Python-from-CC--main/Auto-bind-Python-from-CC--main ``` -### 1) 打开 menuconfig +**1) 打开 menuconfig** ```bash cd /root/xmusic/rvv_ext python3 project.py menuconfig ``` -### 2) 配置工具链(交叉编译到 SG2002) +**2) 配置工具链(交叉编译到 SG2002)** - `-mcpu=c906fdv` - `-march=rv64imafdcv0p7xthead` - `-mcmodel=medany` - `-mabi=lp64d` -#### 替代方案:不使用 menuconfig 进行配置 - -您也可以通过标志进行配置: +也可以不用 menuconfig,直接通过参数配置: ```bash python3 project.py config \ @@ -532,143 +351,81 @@ python3 project.py config \ --toolchain-prefix riscv64-unknown-linux-musl- ``` -或者通过此项目顶级 `CMakeLists.txt` 使用的环境变量: +或者使用项目顶级 `CMakeLists.txt` 读取的环境变量: ```bash export MY_TOOLCHAIN_PATH=/root/xmusic/toolchains/maixcam/host-tools/gcc/riscv64-linux-musl-x86_64/bin ``` -### 3) 构建 + wheel 包 +**3) 构建 + 生成 wheel 包** ```bash python3 project.py build ``` 产物: + - 编译的扩展:`build/main/libmain.so` - Wheel 包:`dist/*.whl` -### 4) 快速 RVV 启用检查(可选) +**4) 检查 RVV 是否启用(可选)** -在执行 `python3 project.py build` 后,检查构建日志中的编译命令行是否包含: +执行 `python3 project.py build` 后,检查构建日志中的编译命令行是否包含: - `-march=rv64imafdcv0p7xthead` -如果存在该标志,`__riscv_vector` 应该被定义,RVV 实现(`rvv_rvv071.cpp`)将会被编译。 - -## Python API +如果存在该标志,`__riscv_vector` 应该已被定义,RVV 实现(`rvv_rvv071.cpp`)会被编译进库。 -顶层模块名为 `rvv`。 - `/root/xmusic/toolchains/maixcam/host-tools/gcc/riscv64-linux-musl-x86_64/bin` - (请根据您实际的工作空间路径调整前缀 `/root/xmusic`) -- `CONFIG_TOOLCHAIN_PREFIX` = - `riscv64-unknown-linux-musl-` +### IDE 代码提示 -然后选择 RISCV64 目标(MaixCam)。 +`rvv` 是二进制扩展模块(`rvv.so`),IDE 无法像纯 Python 那样从源码推断函数签名。本项目已通过 **PEP 561** 提供类型提示: -当启用 `MaixCam` 时,此项目的 `main/CMakeLists.txt` 已经注入了 SG2002 所需的 RVV 标志: - -- `-mcpu=c906fdv` -- `-march=rv64imafdcv0p7xthead` -- `-mcmodel=medany` -- `-mabi=lp64d` - -#### 替代方案:不使用 menuconfig 进行配置 - -您也可以通过标志进行配置: - -```bash -python3 project.py config \ - --toolchain /root/xmusic/toolchains/maixcam/host-tools/gcc/riscv64-linux-musl-x86_64/bin \ - --toolchain-prefix riscv64-unknown-linux-musl- -``` +- `rvv_ext/rvv.pyi`:模块存根(stub),为 `add/sub/scale/dot/norm_l2/matmul` 提供签名与说明 +- `rvv_ext/py.typed`:标记文件,告知工具/IDE 该包携带类型信息 -或者通过此项目顶级 `CMakeLists.txt` 使用的环境变量: +打包 wheel 时这两者会一并打入(见 `rvv_ext/setup.py`)。 -```bash -export MY_TOOLCHAIN_PATH=/root/xmusic/toolchains/maixcam/host-tools/gcc/riscv64-linux-musl-x86_64/bin -``` - -### 3) 构建 + wheel 包 +**方式 A:安装 wheel 后获得提示(推荐)** ```bash -python3 project.py build +pip install --no-deps --force-reinstall dist/*.whl ``` -产物: -- 编译的扩展:`build/main/libmain.so` -- Wheel 包:`dist/*.whl` - -### 4) 快速 RVV 启用检查(可选) - -在执行 `python3 project.py build` 后,检查构建日志中的编译命令行是否包含: - -- `-march=rv64imafdcv0p7xthead` - -如果存在该标志,`__riscv_vector` 应该被定义,RVV 实现(`rvv_rvv071.cpp`)将会被编译。 - -## Python API +**方式 B:在源码目录直接开发时获得提示** -顶层模块名为 `rvv`。 - -- `rvv.add(a, b) -> ndarray` -- `rvv.sub(a, b) -> ndarray` -- `rvv.scale(a, k) -> ndarray` -- `rvv.dot(a, b) -> float` -- `rvv.norm_l2(a) -> float` -- `rvv.matmul(A, B) -> ndarray` - -所有数组输入都会在内部转换为 `float32` 和 C 连续格式。 +- 确保 IDE 的解释器/项目索引能看到 `rvv_ext/rvv.pyi` +- 可在 PyCharm 中将 `rvv_ext/` 目录标记为 **Sources Root**(或加入 `PYTHONPATH`) -## 测试 +> 无论哪种方式,运行时导入仍然是 `import rvv`。 -## 测试 +### 测试 -测试位于 `rvv_ext/tests` 目录,需要 NumPy + pytest。 +测试位于 `rvv_ext/tests` 目录,需要 NumPy + pytest: ```bash -python3 -c "import rvv; import numpy as np; a=np.arange(8,dtype=np.float32); print(rvv.add(a,a)); print(rvv.dot(a,a))" +pytest -q ``` ---- - -## 测试与性能对比(不依赖 pytest) - -运行: +不依赖 pytest 的性能对比脚本: ```bash python3 tests/test_rvv.py ``` -### 运行 `cmake --build build ...` 时出现 "Error: could not load cache" 错误 - -当 CMake 缓存(`build/CMakeCache.txt`)缺失时会发生这种情况。 -常见原因: -- 您运行了 `python3 project.py distclean` 然后**没有**重新运行 CMake 配置步骤。 -- `build/` 目录被删除或为空。 - -解决方法: +在 SG2002 上还可以运行微基准测试: ```bash -cd /path/to/rvv_ext - -# 重新运行配置(生成 build/CMakeCache.txt) -python3 project.py build - -# 然后编译 -cmake --build build --target main -- -j"$(nproc)" +python3 tests/bench_perf.py ``` -### `setup.py` 显示 `Native library not found: build/main/libmain.so` +### 故障排除 -这意味着您还没有构建扩展(或者它被构建到了不同的文件夹中)。 +**`Error: could not load cache`** -检查: +在执行 `cmake --build build ...` 时出现,说明 CMake 缓存(`build/CMakeCache.txt`)缺失。常见原因: -当 CMake 缓存(`build/CMakeCache.txt`)缺失时会发生这种情况。 -常见原因: -- 您运行了 `python3 project.py distclean` 然后**没有**重新运行 CMake 配置步骤。 -- `build/` 目录被删除或为空。 +- 执行了 `python3 project.py distclean`,之后**没有**重新运行 CMake 配置步骤 +- `build/` 目录被删除或为空 解决方法: @@ -682,28 +439,22 @@ python3 project.py build cmake --build build --target main -- -j"$(nproc)" ``` -### `setup.py` 显示 `Native library not found: build/main/libmain.so` - -这意味着您还没有构建扩展(或者它被构建到了不同的文件夹中)。 +**`setup.py` 显示 `Native library not found: build/main/libmain.so`** -检查: +说明扩展还没有构建,或者被构建到了其他目录。检查: ```bash find build -maxdepth 4 -name 'libmain.so' -o -name '*.so' | sort ``` -如果 `libmain.so` 存在但不在 `build/main/` 下,请相应地调整 `setup.py` 中的 `SO_FILE_PATH`。 - -## 复制粘贴命令(嵌入式 Linux) +如果 `libmain.so` 存在但不在 `build/main/` 下,请相应调整 `setup.py` 中的 `SO_FILE_PATH`。 -### A) 在当前机器上构建 wheel 包(安装时不需要 NumPy) - -### A) 在当前机器上构建 wheel 包(安装时不需要 NumPy) +### 复制粘贴命令(嵌入式 Linux) ```bash -cd /home/ywj/ywj2/rvv_ext # 根据您的实际路径调整 +cd /path/to/rvv_ext # 根据实际路径调整 -# (可选) 完全清理:这会移除 build/ 和 CMakeCache.txt +# (可选) 完全清理:会移除 build/ 和 CMakeCache.txt python3 project.py distclean # 1) 配置 CMake(重新创建 build/ 和 build/CMakeCache.txt) @@ -725,196 +476,10 @@ python3 setup.py bdist_wheel ls -la dist ``` -> 如果您只想清理编译的对象但保留 CMake 缓存,请优先使用: -> -> ```bash -> python3 project.py clean -> ``` -> -> 而不是 `distclean`。 -#### 替代方案:不使用 menuconfig 进行配置 -> -> ```bash -> python3 project.py clean -> ``` -> -> 而不是 `distclean`。 -#### 替代方案:不使用 menuconfig 进行配置 - -您也可以通过标志进行配置: - -```bash -python3 project.py config \ - --toolchain /root/xmusic/host-tools/gcc/riscv64-linux-musl-x86_64/bin \ - --toolchain-prefix riscv64-unknown-linux-musl- -``` - -或者通过此项目顶级 `CMakeLists.txt` 使用的环境变量: - -```bash -export MY_TOOLCHAIN_PATH=/root/xmusic/toolchains/maixcam/host-tools/gcc/riscv64-linux-musl-x86_64/bin -``` - -### 3) 构建 + wheel 包 - -```bash -export MY_TOOLCHAIN_PATH=/root/xmusic/toolchains/maixcam/host-tools/gcc/riscv64-linux-musl-x86_64/bin -``` - -### 3) 构建 + wheel 包 - -```bash -python3 project.py build -``` - -产物: -- 编译的扩展:`build/main/libmain.so` -- Wheel 包:`dist/*.whl` - -### 4) 快速 RVV 启用检查(可选) - -在执行 `python3 project.py build` 后,检查构建日志中的编译命令行是否包含: - -- `-march=rv64imafdcv0p7xthead` - -如果存在该标志,`__riscv_vector` 应该被定义,RVV 实现(`rvv_rvv071.cpp`)将会被编译。 - -## Python API - -在执行 `python3 project.py build` 后,检查构建日志中的编译命令行是否包含: - -- `-march=rv64imafdcv0p7xthead` - -如果存在该标志,`__riscv_vector` 应该被定义,RVV 实现(`rvv_rvv071.cpp`)将会被编译。 - -## Python API - -顶层模块名为 `rvv`。 - -- `rvv.add(a, b) -> ndarray` -- `rvv.sub(a, b) -> ndarray` -- `rvv.scale(a, k) -> ndarray` -- `rvv.dot(a, b) -> float` -- `rvv.norm_l2(a) -> float` -- `rvv.matmul(A, B) -> ndarray` -- `rvv.sub(a, b) -> ndarray` -- `rvv.scale(a, k) -> ndarray` -- `rvv.dot(a, b) -> float` -- `rvv.norm_l2(a) -> float` -- `rvv.matmul(A, B) -> ndarray` - -所有数组输入都会在内部转换为 `float32` 和 C 连续格式。 - -## 测试 - -测试位于 `rvv_ext/tests` 目录,需要 NumPy + pytest。 - -## 测试 - -测试位于 `rvv_ext/tests` 目录,需要 NumPy + pytest。 - -```bash -pytest -q -``` - -在 SG2002 上,您还可以运行微基准测试: - -```bash -python3 tests/bench_perf.py -``` - -## 故障排除 - -### 运行 `cmake --build build ...` 时出现 "Error: could not load cache" 错误 - -当 CMake 缓存(`build/CMakeCache.txt`)缺失时会发生这种情况。 -常见原因: -- 您运行了 `python3 project.py distclean` 然后**没有**重新运行 CMake 配置步骤。 -- `build/` 目录被删除或为空。 -常见原因: -- 您运行了 `python3 project.py distclean` 然后**没有**重新运行 CMake 配置步骤。 -- `build/` 目录被删除或为空。 - -解决方法: - -```bash -cd /path/to/rvv_ext - -# Re-run configure (generates build/CMakeCache.txt) -python3 project.py build -python3 project.py build - -# Then compile -cmake --build build --target main -- -j"$(nproc)" -cmake --build build --target main -- -j"$(nproc)" -``` +> 如果只想清理编译产物但保留 CMake 缓存,优先使用 `python3 project.py clean` 而不是 `distclean`。 -### `setup.py` 显示 `Native library not found: build/main/libmain.so` +## 许可 -这意味着您还没有构建扩展(或者它被构建到了不同的文件夹中)。 - -检查: - -```bash -find build -maxdepth 4 -name 'libmain.so' -o -name '*.so' | sort -``` - -如果 `libmain.so` 存在但不在 `build/main/` 下,请相应地调整 `setup.py` 中的 `SO_FILE_PATH`。 - -## 复制粘贴命令(嵌入式 Linux) - -### A) 在当前机器上构建 wheel 包(安装时不需要 NumPy) - -```bash -cd /home/ywj/ywj2/rvv_ext # adjust to your real path - -# (Optional) full clean: this removes build/ and CMakeCache.txt -python3 project.py distclean -python3 project.py distclean - -# 1) Configure CMake (re-creates build/ and build/CMakeCache.txt) -python3 project.py build - -# 健全性检查(配置后应该存在) -ls -la build/CMakeCache.txt - -# 2) Compile the extension shared library (creates build/main/libmain.so) -cmake --build build --target main -- -j"$(nproc)" - -# Sanity check (should exist after compile) -ls -la build/main/libmain.so - -# 3) Build wheel (creates dist/*.whl) -python3 setup.py bdist_wheel - -# 4) List wheel -ls -la build/CMakeCache.txt - -# 2) Compile the extension shared library (creates build/main/libmain.so) -cmake --build build --target main -- -j"$(nproc)" - -# Sanity check (should exist after compile) -ls -la build/main/libmain.so - -# 3) Build wheel (creates dist/*.whl) -python3 setup.py bdist_wheel - -# 4) List wheel -ls -la dist -``` +本项目采用 LGPL-3.0 许可,详见仓库中的 LICENSE 文件。 -> 如果您只想清理编译的对象但保留 CMake 缓存,请优先使用: -> -> ```bash -> python3 project.py clean -> ``` -> -> 而不是 `distclean`。 - -> 如果您只想清理编译的对象但保留 CMake 缓存,请优先使用: -> -> ```bash -> python3 project.py clean -> ``` -> -> 而不是 `distclean`。 +Copyright (C) 2026 ywj <yangwenjie1231@qq.com> diff --git a/docs/doc/zh/sidebar.yaml b/docs/doc/zh/sidebar.yaml index 745f5301..0df4d70b 100644 --- a/docs/doc/zh/sidebar.yaml +++ b/docs/doc/zh/sidebar.yaml @@ -273,3 +273,5 @@ items: label: 使用 MaixCDK 开发 - file: pro/compile_os.md label: 编译系统 + - file: pro/rvv.md + label: 使用RVV加速