From c0b97dc96420f2aa8e70add8c49a16280bfbbd7d Mon Sep 17 00:00:00 2001 From: yangwenjie1231 Date: Tue, 6 Oct 2026 10:47:34 +0800 Subject: [PATCH] docs: register RVV acceleration page in sidebar and add English version PR #176 added `docs/doc/zh/pro/rvv.md` but never registered it in `sidebar.yaml`. teedoc builds a page for every `.md` file, so the page was generated and reachable by direct URL, but it had no entry in the navigation and became an orphan page. The language switcher also pointed at an English page that did not exist, returning 404. - register `pro/rvv.md` in both `docs/doc/zh/sidebar.yaml` and `docs/doc/en/sidebar.yaml` - add the missing English version `docs/doc/en/pro/rvv.md` - tidy up the Chinese page: merge the duplicated sections, drop the stray top-level headings so the page has a single H1, fix a link broken by a full-width parenthesis, and rewrite the release-notes framing into normal document form - move the performance chart into `docs/doc/assets/` instead of hotlinking maixhub, matching how the rest of the docs reference images --- .../doc/assets/rvv_performance_comparison.jpg | Bin 0 -> 40576 bytes docs/doc/en/pro/rvv.md | 485 +++++++++++ docs/doc/en/sidebar.yaml | 2 + docs/doc/zh/pro/rvv.md | 765 ++++-------------- docs/doc/zh/sidebar.yaml | 2 + 5 files changed, 654 insertions(+), 600 deletions(-) create mode 100644 docs/doc/assets/rvv_performance_comparison.jpg create mode 100644 docs/doc/en/pro/rvv.md diff --git a/docs/doc/assets/rvv_performance_comparison.jpg b/docs/doc/assets/rvv_performance_comparison.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c7c2fd6f933cee9ffcd3f8114e0fb68e5485a4f0 GIT binary patch literal 40576 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⁢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

;!QqG~ziFY$h+W+$pwGcNOyj)TA;N4yR_5S}rxT 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 Ip6ypZ0~BpXg#Z8m literal 0 HcmV?d00001 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加速