EagerExtensionBackendKind::Cuda not covered
主线位置:eager 主线开始之前,
Cargo.toml这一步。eager 运行时按 engine 的种类给扩展族(einsum、linalg、fft)装模块,种类是tenferro-ad里的一个枚举。CUDA engine 本身见 CUDA。
flowchart TB fft["fft 开 cuda"] --> adc["tenferro-ad 开 cuda"] adc --> var["枚举多出 Cuda"] ein["einsum 只开 autodiff"] --> m1["match 无 Cuda 分支"] lin["linalg 只开 autodiff"] --> m2["match 无 Cuda 分支"] var --> m1 var --> m2 m1 --> e["E0004"] m2 --> e all["每个都开 cuda"] --> ok["cargo check 通过"]
实验 crate exp-tenferro8/pit1-cuda、pit1-cudafix、pit1-webgpu,cargo check --offline(debug);M2 Max、macOS 27、rustc 1.99.0。本机没有 CUDA,这一页只编译、不运行。报错里 cargo 缓存的路径前缀写成 ...。
现象
只想让 FFT 上 GPU,于是只在 tenferro-fft 上开 cuda;einsum 和 linalg 照常开 autodiff:
[dependencies]
tenferro-runtime = "=0.8.0"
tenferro-einsum = { version = "=0.8.0", features = ["autodiff"] }
tenferro-linalg = { version = "=0.8.0", features = ["autodiff"] }
tenferro-fft = { version = "=0.8.0", features = ["autodiff", "cuda"] }
main.rs 只有 fn main() {},cargo check 以 101 退出:
error[E0004]: non-exhaustive patterns: `tenferro_ad::extension::EagerExtensionBackendKind::Cuda` not covered
--> .../tenferro-einsum-0.8.0/src/eager_ad.rs:214:11
|
214 | match backend_kind {
| ^^^^^^^^^^^^ pattern `tenferro_ad::extension::EagerExtensionBackendKind::Cuda` not covered
|
note: `tenferro_ad::extension::EagerExtensionBackendKind` defined here
--> .../tenferro-ad-0.8.0/src/extension.rs:45:1
|
45 | pub enum EagerExtensionBackendKind {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
50 | Cuda,
| ---- not covered
...
error: could not compile `tenferro-einsum` (lib) due to 1 previous error
warning: build failed, waiting for other jobs to finish...
error[E0004]: non-exhaustive patterns: `tenferro_ad::extension::EagerExtensionBackendKind::Cuda` not covered
--> .../tenferro-linalg-0.8.0/src/eager_ext.rs:982:11
...
error: could not compile `tenferro-linalg` (lib) due to 1 previous error
(pit1-cuda。)出错的是没开 cuda 的两个 crate,rustc 的 help 还建议在上游代码里加一个 => todo!() 分支,这改不了。
用户指南 devices-and-gpu.md 在 v0.8.0 还留着「WebGPU Quickstart」一节,教人写 tenferro-gpu = { version = "...", default-features = false, features = ["webgpu"] }。照抄(pit1-webgpu),cargo 在解析依赖时就停下:
package `pit1-webgpu` depends on `tenferro-gpu` with feature `webgpu` but `tenferro-gpu` does not have that feature.
help: available features: blas, blas-accelerate, blas-mkl, blas-openblas, cuda, default, native, rocm
出处
枚举在 tenferro-ad 的 extension.rs,Cuda 变体跟着 tenferro-ad 自己的 cuda feature:
pub enum EagerExtensionBackendKind {
/// The eager runtime owns a CPU backend.
Cpu,
/// The eager runtime owns a CUDA backend.
#[cfg(feature = "cuda")]
Cuda,
}
tenferro-einsum 的 eager_extension_module 对它 match,Cuda 分支挂在 einsum 自己的 cuda 上:
match backend_kind {
EagerExtensionBackendKind::Cpu => {
crate::extension::extension_module::<CpuEngine>(engine_id)
.map_err(eager_runtime_config_error)
}
#[cfg(feature = "cuda")]
EagerExtensionBackendKind::Cuda => {
// ...
tenferro-linalg 的 eager_ext.rs 第 982 行是同样的写法。tenferro-fft 的 cuda 转发 "tenferro-ad?/cuda",开了 autodiff 时就打开了 tenferro-ad/cuda。依赖图里只有一份 tenferro-ad,cargo 把各处请求的 feature 取并集,于是枚举对所有人都多了 Cuda;einsum 和 linalg 没开 cuda,match 少一个分支,编译失败。没开 autodiff 的运算族 crate 不编译 eager_ad.rs 这类文件,不受影响。
这是上游的 feature 设计问题,0.8.0 上复现:一个 crate 的可选 feature 改变了另一个 crate 看到的枚举,而 #[doc(hidden)] 的这个枚举没有 #[non_exhaustive] 也没有通配分支。0.7.1 的同一个枚举有 #[cfg(feature = "webgpu")] WebGpu,坑的形状一样,换的只是变体名;WebGPU 后端和 webgpu feature 在 0.8.0 删掉了,来历见 GPU 与 XLA。
修法
依赖图里每个开了 autodiff 的运算族 crate 都一起开 cuda:
[dependencies]
tenferro-runtime = "=0.8.0"
tenferro-einsum = { version = "=0.8.0", features = ["autodiff", "cuda"] }
tenferro-linalg = { version = "=0.8.0", features = ["autodiff", "cuda"] }
tenferro-fft = { version = "=0.8.0", features = ["autodiff", "cuda"] }
Checking pit1-cudafix v0.1.0 (...)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.63s
(pit1-cudafix,cargo check。)这只说明能编译。运行期要有 CUDA 驱动,没有驱动时 cuda_devices() 和 CudaEngine::open 会 panic,见 CUDA 的「没有驱动时」。WebGPU 没有替代,0.8.0 的 GPU 后端只有 cuda。
怎么确认没中招
- E0004 的模式是
EagerExtensionBackendKind::Cuda、出错位置在tenferro-einsum/tenferro-linalg的源码里:找依赖图里谁开了cuda。cargo tree -e features -i tenferro-ad里出现tenferro-ad feature "cuda"时,它下面列出的就是来源。 - 加 GPU feature 时把所有 tenferro 运算族 crate 的 feature 列表放在一起改,不要只改一行。
- 上游指南、README 里的
webgpu是 0.7.1 留下的文字,tenferro-gpu0.8.0 的 feature 只有cuda、rocm(空占位)和 CPU provider 的那几个。
小结
tenferro-ad的EagerExtensionBackendKind::Cuda跟着tenferro-ad/cuda出现,任何一个运算族 crate 开cuda都会打开它。- 只开
autodiff的 einsum、linalg 对它match时没有Cuda分支,报 E0004;上游设计问题,0.8.0 复现。 - 每个开
autodiff的运算族 crate 都一起开cuda;指南里的features = ["webgpu"]在 0.8.0 解析不了。