Skip to main content

tenferro_gpu/cuda/
mod.rs

1//! The CUDA backend: one engine over `t4a-cuda-runtime` and the `t4a-cuda-kernels`
2//! catalogue (issue #2208).
3//!
4//! One [`CudaRuntime`] per engine owns the stream, the allocation domain, transfers and
5//! pending handles; every operation reaches the kernel catalogue through the engine's typed
6//! dispatchers, and the vendor libraries through [`raw::Session`].
7//!
8//! # Examples
9//!
10//! ```no_run
11//! # fn main() -> Result<(), tenferro_gpu::cuda::CudaEngineError> {
12//! use tenferro_gpu::cuda::{gpu_available, CudaDeviceId, CudaEngine};
13//!
14//! # #[cfg(feature = "cuda")]
15//! if gpu_available() {
16//!     let engine = CudaEngine::open(CudaDeviceId::from_ordinal(0))?;
17//!     let _ = engine.runtime();
18//! }
19//! # Ok(())
20//! # }
21//! ```
22
23pub(crate) mod device;
24pub(crate) mod identity;
25
26/// The `cudarc` crate tenferro-gpu is built against (issue #1940).
27///
28/// Downstream code that calls a CUDA vendor library (cuBLAS, cuSOLVER, ...) on tenferro buffers
29/// through [`raw::Session`] should take its bindings from here, so they always match tenferro's
30/// `cudarc` version and CUDA version selection. The re-export is not a stable API of its own: it
31/// moves with tenferro's `cudarc` requirement.
32///
33/// # Examples
34///
35/// ```
36/// use tenferro_gpu::cuda::cudarc::cublas::sys::cublasOperation_t;
37///
38/// let no_transpose = cublasOperation_t::CUBLAS_OP_N;
39/// assert_ne!(no_transpose, cublasOperation_t::CUBLAS_OP_T);
40/// ```
41pub use ::cudarc;
42pub use device::{cuda_devices, CudaDeviceError, CudaDeviceId, CudaDeviceInfo};
43
44pub use identity::{CudaComputeCapability, CudaDeviceUuid, GpuExtensionCapability};
45
46/// The CUDA backend's seam identity.
47///
48/// Its allocation is the `t4a-cuda-runtime` buffer the runtime hands out; a
49/// [`gpu::Buffer<CudaBackend>`] owns it, so no consumer reaches into tensor storage for a
50/// device address.
51#[doc(hidden)]
52pub struct CudaBackend;
53
54impl crate::gpu::Backend for CudaBackend {
55    type Allocation = t4a_cuda_runtime::Buffer;
56}
57
58/// Whether any CUDA device is usable, probed through the new runtime rather than the
59/// CubeCL path, so a new-path test cannot be skipped because the old backend failed.
60#[doc(hidden)]
61pub fn gpu_available() -> bool {
62    let available = t4a_cuda_runtime::device_count()
63        .map(|count| count > 0)
64        .unwrap_or(false);
65    // The GPU lane sets `TENFERRO_REQUIRE_GPU=1`: there a missing device must fail the test
66    // rather than skip it, so a hardware lane cannot report success without hardware.
67    assert!(
68        available || std::env::var_os("TENFERRO_REQUIRE_GPU").is_none(),
69        "TENFERRO_REQUIRE_GPU is set but no CUDA device is usable"
70    );
71    available
72}
73/// The seam this adapter implements.
74pub use crate::gpu;
75
76mod cutensor;
77mod dispatch;
78mod engine;
79mod event_domain;
80mod fusion;
81mod launch;
82mod pending;
83mod pinned;
84mod publication;
85pub mod raw;
86mod runtime;
87pub mod runtime_adapter;
88
89pub use runtime_adapter::cuda_runtime_engine_registration;
90mod storage;
91mod structural;
92mod transfer;
93pub(crate) mod vendor;
94
95mod capability;
96pub use capability::cuda_capabilities;
97pub use cutensor::{Contraction, Cutensor, Operand};
98pub use dispatch::Dispatcher;
99pub use engine::{CudaEngine, CudaEngineError};
100pub use fusion::{PrepareCounters, PreparedFusion};
101pub use launch::{device_buffer, layout_arg, KernelModules};
102pub use pending::{PendingDownload, PendingUpload, RejectedTransfer, TransferSubmitError};
103pub use pinned::PinnedHostBuffer;
104pub use publication::{
105    PublicationAdmissionError, PublicationDownload, PublicationError, RejectedPublication,
106    SourcePublication,
107};
108pub use runtime::{CudaRuntime, CudaRuntimeIdentity};
109pub use storage::CudaStorage;
110pub use transfer::{download_pending, download_tensor, upload_pending, upload_tensor};
111pub use vendor::{Cublas, GemmRequest};