Skip to main content

baracuda_types/
version.rs

1//! CUDA version identifier + feature-gating enum.
2//!
3//! `CudaVersion` uses the same packed encoding NVIDIA uses in
4//! `cuDriverGetVersion` / `cudaRuntimeGetVersion`: `major * 1000 + minor * 10`
5//! — i.e. CUDA 12.6.0 is encoded as `12060`.
6
7use core::fmt;
8
9/// A CUDA major.minor version.
10#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
11#[repr(transparent)]
12pub struct CudaVersion(u32);
13
14impl CudaVersion {
15    /// CUDA 11.4 — the baracuda floor.
16    pub const CUDA_11_4: Self = Self::from_major_minor(11, 4);
17    /// CUDA 11.8 — last 11.x release.
18    pub const CUDA_11_8: Self = Self::from_major_minor(11, 8);
19    /// CUDA 12.0 — introduced library management, green contexts, multicast, nvJitLink.
20    pub const CUDA_12_0: Self = Self::from_major_minor(12, 0);
21    /// CUDA 12.3 — introduced graph conditional nodes.
22    pub const CUDA_12_3: Self = Self::from_major_minor(12, 3);
23    /// CUDA 12.6.
24    pub const CUDA_12_6: Self = Self::from_major_minor(12, 6);
25    /// CUDA 12.8 — introduced graph SWITCH nodes.
26    pub const CUDA_12_8: Self = Self::from_major_minor(12, 8);
27    /// CUDA 13.0.
28    pub const CUDA_13_0: Self = Self::from_major_minor(13, 0);
29
30    /// The baracuda floor: the oldest CUDA driver/toolkit we officially support.
31    pub const FLOOR: Self = Self::CUDA_11_4;
32
33    /// Construct a version from major.minor parts (e.g. `12, 6`).
34    #[inline]
35    pub const fn from_major_minor(major: u32, minor: u32) -> Self {
36        Self(major * 1000 + minor * 10)
37    }
38
39    /// Decode the raw integer returned by `cuDriverGetVersion` /
40    /// `cudaRuntimeGetVersion`.
41    #[inline]
42    pub const fn from_raw(raw: u32) -> Self {
43        Self(raw)
44    }
45
46    /// The packed integer form (major\*1000 + minor\*10).
47    #[inline]
48    pub const fn raw(self) -> u32 {
49        self.0
50    }
51
52    /// Major version number (e.g. 12 for CUDA 12.6).
53    #[inline]
54    pub const fn major(self) -> u32 {
55        self.0 / 1000
56    }
57
58    /// Minor version number (e.g. 6 for CUDA 12.6).
59    #[inline]
60    pub const fn minor(self) -> u32 {
61        (self.0 % 1000) / 10
62    }
63
64    /// `true` iff this version is ≥ `major.minor`.
65    #[inline]
66    pub const fn at_least(self, major: u32, minor: u32) -> bool {
67        self.0 >= major * 1000 + minor * 10
68    }
69}
70
71impl fmt::Display for CudaVersion {
72    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73        write!(f, "CUDA {}.{}", self.major(), self.minor())
74    }
75}
76
77/// Named CUDA capabilities, each gated by the minimum toolkit/driver version
78/// in which they became available. Safe-API crates call [`supports`] before
79/// invoking the underlying symbol and surface `Error::FeatureNotSupported`
80/// when the installed driver is too old.
81#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
82#[non_exhaustive]
83pub enum Feature {
84    /// Stream-ordered memory allocator (`cuMemAllocAsync`, pools). CUDA 11.2+.
85    StreamOrderedAllocator,
86    /// Virtual memory management (`cuMemCreate`, `cuMemMap`, ...). CUDA 10.2+.
87    VirtualMemoryManagement,
88    /// Context-independent library loading (`cuLibraryLoadData`). CUDA 12.0+.
89    LibraryManagement,
90    /// Lightweight SM-partitioned contexts. CUDA 12.0+.
91    GreenContexts,
92    /// Multicast objects across multiple GPUs. CUDA 12.0+.
93    MulticastObjects,
94    /// Graph conditional (IF/WHILE) nodes. CUDA 12.3+.
95    GraphConditionalNodes,
96    /// Graph SWITCH nodes. CUDA 12.8+.
97    GraphSwitchNodes,
98    /// Extensible kernel launch (`cuLaunchKernelEx`, cluster dims). CUDA 12.0+.
99    CudaLaunchKernelEx,
100    /// nvJitLink modern JIT linker. CUDA 12.0+.
101    NvJitLink,
102    /// Hopper-only TMA tensor map descriptors. CUDA 11.8+ (HW 9.0+).
103    TensorMapObjects,
104    /// Runtime-API log buffer (`cudaLogs*`). CUDA 12.0+.
105    RuntimeLogBuffer,
106    /// `cudaInitDevice` (initialize primary context without making it current). CUDA 12.0+.
107    CudaInitDevice,
108    /// Green-context-aware execution context APIs on the runtime. CUDA 13.1+.
109    RuntimeGreenContexts,
110}
111
112impl Feature {
113    /// The minimum CUDA version at which the feature is available.
114    pub const fn required_version(self) -> CudaVersion {
115        match self {
116            Feature::StreamOrderedAllocator => CudaVersion::from_major_minor(11, 2),
117            Feature::VirtualMemoryManagement => CudaVersion::from_major_minor(10, 2),
118            Feature::LibraryManagement => CudaVersion::CUDA_12_0,
119            Feature::GreenContexts => CudaVersion::CUDA_12_0,
120            Feature::MulticastObjects => CudaVersion::CUDA_12_0,
121            Feature::GraphConditionalNodes => CudaVersion::CUDA_12_3,
122            Feature::GraphSwitchNodes => CudaVersion::CUDA_12_8,
123            Feature::CudaLaunchKernelEx => CudaVersion::CUDA_12_0,
124            Feature::NvJitLink => CudaVersion::CUDA_12_0,
125            Feature::TensorMapObjects => CudaVersion::from_major_minor(11, 8),
126            Feature::RuntimeLogBuffer => CudaVersion::CUDA_12_0,
127            Feature::CudaInitDevice => CudaVersion::CUDA_12_0,
128            Feature::RuntimeGreenContexts => CudaVersion::from_major_minor(13, 1),
129        }
130    }
131}
132
133/// `true` if `feature` is callable on a CUDA installation of version `version`
134/// or newer.
135#[inline]
136pub const fn supports(version: CudaVersion, feature: Feature) -> bool {
137    version.raw() >= feature.required_version().raw()
138}
139
140#[cfg(test)]
141mod tests {
142    use super::*;
143
144    #[test]
145    fn encode_decode() {
146        let v = CudaVersion::from_major_minor(12, 6);
147        assert_eq!(v.major(), 12);
148        assert_eq!(v.minor(), 6);
149        assert_eq!(v.raw(), 12060);
150    }
151
152    #[test]
153    fn ordering_is_by_version() {
154        assert!(CudaVersion::CUDA_11_4 < CudaVersion::CUDA_12_0);
155        assert!(CudaVersion::CUDA_12_0 < CudaVersion::CUDA_13_0);
156    }
157
158    #[test]
159    fn at_least() {
160        assert!(CudaVersion::CUDA_12_6.at_least(12, 0));
161        assert!(!CudaVersion::CUDA_11_4.at_least(12, 0));
162    }
163
164    #[test]
165    fn feature_gating() {
166        assert!(supports(CudaVersion::CUDA_12_0, Feature::GreenContexts));
167        assert!(!supports(CudaVersion::CUDA_11_8, Feature::GreenContexts));
168        assert!(supports(CudaVersion::CUDA_12_8, Feature::GraphSwitchNodes));
169        assert!(!supports(CudaVersion::CUDA_12_6, Feature::GraphSwitchNodes));
170    }
171
172    #[test]
173    fn floor_is_consistent() {
174        assert_eq!(CudaVersion::FLOOR, CudaVersion::CUDA_11_4);
175    }
176}