Skip to main content

nvml_wrapper/
vgpu.rs

1use std::{ffi::CStr, os::raw::c_uint};
2
3use ffi::bindings::{
4    nvmlVgpuCapability_t, nvmlVgpuTypeId_t, NVML_DEVICE_NAME_BUFFER_SIZE,
5    NVML_GRID_LICENSE_BUFFER_SIZE,
6};
7use static_assertions::assert_impl_all;
8
9use crate::{
10    error::{nvml_sym, nvml_try, NvmlError},
11    Device,
12};
13
14pub struct VgpuType<'dev> {
15    id: nvmlVgpuTypeId_t,
16    device: &'dev Device<'dev>,
17}
18
19assert_impl_all!(VgpuType: Send, Sync);
20
21impl<'dev> VgpuType<'dev> {
22    /// Create a new vGPU type wrapper.
23    ///
24    /// You probably don't need to use this yourself, but rather through
25    /// [`Device::vgpu_supported_types`] and [`Device::vgpu_creatable_types`].
26    pub fn new(device: &'dev Device, id: nvmlVgpuTypeId_t) -> Self {
27        Self { id, device }
28    }
29
30    /// Access the `Device` this struct belongs to.
31    ///
32    pub fn device(&self) -> &'dev Device<'_> {
33        self.device
34    }
35
36    /// Retrieve the class of the vGPU type.
37    ///
38    /// # Errors
39    ///
40    /// * `Uninitialized`, if the library has not been successfully initialized
41    /// * `InvalidArg`, if this `Device` is invalid
42    /// * `Unknown`, on any unexpected error
43    ///
44    /// # Device support
45    ///
46    /// Kepler or newer fully supported devices.
47    #[doc(alias = "nvmlVgpuTypeGetClass")]
48    pub fn class_name(&self) -> Result<String, NvmlError> {
49        let sym = nvml_sym(self.device.nvml().lib.nvmlVgpuTypeGetClass.as_ref())?;
50
51        unsafe {
52            let mut size = NVML_DEVICE_NAME_BUFFER_SIZE;
53            let mut buffer = vec![0; size as usize];
54
55            nvml_try(sym(self.id, buffer.as_mut_ptr(), &mut size))?;
56
57            let version_raw = CStr::from_ptr(buffer.as_ptr());
58            Ok(version_raw.to_str()?.into())
59        }
60    }
61
62    /// Retrieve license requirements for a vGPU type.
63    ///
64    /// The license type and version required to run the specified vGPU type is returned as an
65    /// alphanumeric string, in the form "\<license name\>,\<version\>", for example
66    /// "GRID-Virtual-PC,2.0". If a vGPU is runnable with* more than one type of license, the
67    /// licenses are delimited by a semicolon, for example
68    /// "GRID-Virtual-PC,2.0;GRID-Virtual-WS,2.0;GRID-Virtual-WS-Ext,2.0".
69    ///
70    /// # Errors
71    ///
72    /// * `Uninitialized`, if the library has not been successfully initialized
73    /// * `InsufficientSize`, if the passed-in `size` is 0 (must be > 0)
74    /// * `InvalidArg`, if this `Device` is invalid
75    /// * `Unknown`, on any unexpected error
76    ///
77    /// # Device support
78    ///
79    /// Kepler or newer fully supported devices.
80    #[doc(alias = "nvmlVgpuTypeGetLicense")]
81    pub fn license(&self) -> Result<String, NvmlError> {
82        let sym = nvml_sym(self.device.nvml().lib.nvmlVgpuTypeGetLicense.as_ref())?;
83
84        unsafe {
85            let mut buffer = vec![0; NVML_GRID_LICENSE_BUFFER_SIZE as usize];
86
87            nvml_try(sym(self.id, buffer.as_mut_ptr(), buffer.len() as u32))?;
88
89            let version_raw = CStr::from_ptr(buffer.as_ptr());
90            Ok(version_raw.to_str()?.into())
91        }
92    }
93
94    /// Retrieve the name of the vGPU type.
95    ///
96    /// The name is an alphanumeric string that denotes a particular vGPU, e.g. GRID M60-2Q.
97    ///
98    /// # Errors
99    ///
100    /// * `Uninitialized`, if the library has not been successfully initialized
101    /// * `InvalidArg`, if this `Device` is invalid
102    /// * `Unknown`, on any unexpected error
103    ///
104    /// # Device support
105    ///
106    /// Kepler or newer fully supported devices.
107    #[doc(alias = "nvmlVgpuTypeGetName")]
108    pub fn name(&self) -> Result<String, NvmlError> {
109        let sym = nvml_sym(self.device.nvml().lib.nvmlVgpuTypeGetName.as_ref())?;
110
111        unsafe {
112            let mut size = NVML_DEVICE_NAME_BUFFER_SIZE;
113            let mut buffer = vec![0; size as usize];
114
115            nvml_try(sym(self.id, buffer.as_mut_ptr(), &mut size))?;
116
117            let version_raw = CStr::from_ptr(buffer.as_ptr());
118            Ok(version_raw.to_str()?.into())
119        }
120    }
121
122    /// Retrieve the requested capability for a given vGPU type. Refer to the
123    /// `nvmlVgpuCapability_t` structure for the specific capabilities that can be
124    /// queried.
125    ///
126    /// # Errors
127    ///
128    /// * `Uninitialized`, if the library has not been successfully initialized
129    /// * `InvalidArg`, if this `Device` is invalid
130    /// * `Unknown`, on any unexpected error
131    ///
132    /// # Device Support
133    ///
134    /// Maxwell or newer fully supported devices.
135    #[doc(alias = "nvmlVgpuTypeGetCapabilities")]
136    pub fn capabilities(&self, capability: nvmlVgpuCapability_t) -> Result<bool, NvmlError> {
137        let sym = nvml_sym(self.device.nvml().lib.nvmlVgpuTypeGetCapabilities.as_ref())?;
138
139        let mut result: c_uint = 0;
140        unsafe {
141            nvml_try(sym(self.id, capability, &mut result))?;
142        }
143        Ok(result != 0)
144    }
145
146    /// Retrieve the device ID of the vGPU type.
147    ///
148    /// # Errors
149    ///
150    /// * `Uninitialized`, if the library has not been successfully initialized
151    /// * `InvalidArg`, if this `Device` is invalid
152    /// * `Unknown`, on any unexpected error
153    ///
154    /// # Device Support
155    ///
156    /// Kepler or newer fully supported devices.
157    #[doc(alias = "nvmlVgpuTypeGetDeviceID")]
158    pub fn device_id(&self) -> Result<(u64, u64), NvmlError> {
159        let sym = nvml_sym(self.device.nvml().lib.nvmlVgpuTypeGetDeviceID.as_ref())?;
160
161        let (mut device_id, mut subsystem_id) = (0, 0);
162        unsafe {
163            nvml_try(sym(self.id, &mut device_id, &mut subsystem_id))?;
164        }
165        Ok((device_id, subsystem_id))
166    }
167
168    /// Retrieve the static frame rate limit value of the vGPU type.
169    ///
170    /// # Errors
171    ///
172    /// * `Uninitialized`, if the library has not been successfully initialized
173    /// * `NotSupported`, if frame rate limiter is turned off for the vGPU type
174    /// * `InvalidArg`, if this `Device` is invalid
175    /// * `Unknown`, on any unexpected error
176    ///
177    /// # Device Support
178    ///
179    /// Kepler or newer fully supported devices.
180    #[doc(alias = "nvmlVgpuTypeGetFrameRateLimit")]
181    pub fn frame_rate_limit(&self) -> Result<u32, NvmlError> {
182        let sym = nvml_sym(
183            self.device
184                .nvml()
185                .lib
186                .nvmlVgpuTypeGetFrameRateLimit
187                .as_ref(),
188        )?;
189
190        let mut limit = 0;
191        unsafe {
192            nvml_try(sym(self.id, &mut limit))?;
193        }
194        Ok(limit)
195    }
196
197    /// Retrieve the vGPU framebuffer size in bytes.
198    ///
199    /// # Errors
200    ///
201    /// * `Uninitialized`, if the library has not been successfully initialized
202    /// * `InvalidArg`, if this `Device` is invalid
203    /// * `Unknown`, on any unexpected error
204    ///
205    /// # Device Support
206    ///
207    /// Kepler or newer fully supported devices.
208    #[doc(alias = "nvmlVgpuTypeGetFramebufferSize")]
209    pub fn framebuffer_size(&self) -> Result<u64, NvmlError> {
210        let sym = nvml_sym(
211            self.device
212                .nvml()
213                .lib
214                .nvmlVgpuTypeGetFramebufferSize
215                .as_ref(),
216        )?;
217
218        let mut size = 0;
219        unsafe {
220            nvml_try(sym(self.id, &mut size))?;
221        }
222        Ok(size)
223    }
224
225    /// Retrieve the GPU Instance Profile ID for the vGPU type. The API will return a valid GPU
226    /// Instance Profile ID for the MIG capable vGPU types, else
227    /// [`crate::ffi::bindings::INVALID_GPU_INSTANCE_PROFILE_ID`] is returned.
228    ///
229    /// # Errors
230    ///
231    /// * `Uninitialized`, if the library has not been successfully initialized
232    /// * `InvalidArg`, if this `Device` is invalid
233    /// * `Unknown`, on any unexpected error
234    ///
235    /// # Device Support
236    ///
237    /// Kepler or newer fully supported devices.
238    #[doc(alias = "nvmlVgpuTypeGetGpuInstanceProfileId")]
239    pub fn instance_profile_id(&self) -> Result<u32, NvmlError> {
240        let sym = nvml_sym(
241            self.device
242                .nvml()
243                .lib
244                .nvmlVgpuTypeGetGpuInstanceProfileId
245                .as_ref(),
246        )?;
247
248        let mut profile_id = 0;
249        unsafe {
250            nvml_try(sym(self.id, &mut profile_id))?;
251        }
252        Ok(profile_id)
253    }
254
255    /// Retrieve the maximum number of vGPU instances creatable on a device for the vGPU type.
256    ///
257    /// # Errors
258    ///
259    /// * `Uninitialized`, if the library has not been successfully initialized
260    /// * `InvalidArg`, if this `Device` is invalid
261    /// * `Unknown`, on any unexpected error
262    ///
263    /// # Device Support
264    ///
265    /// Kepler or newer fully supported devices.
266    #[doc(alias = "nvmlVgpuTypeGetMaxInstances")]
267    pub fn max_instances(&self) -> Result<u32, NvmlError> {
268        let sym = nvml_sym(self.device.nvml().lib.nvmlVgpuTypeGetMaxInstances.as_ref())?;
269
270        let mut max = 0;
271        unsafe {
272            nvml_try(sym(self.device.handle(), self.id, &mut max))?;
273        }
274        Ok(max)
275    }
276
277    /// Retrieve the maximum number of vGPU instances supported per VM for the vGPU type.
278    ///
279    /// # Errors
280    ///
281    /// * `Uninitialized`, if the library has not been successfully initialized
282    /// * `InvalidArg`, if this `Device` is invalid
283    /// * `Unknown`, on any unexpected error
284    ///
285    /// # Device Support
286    ///
287    /// Kepler or newer fully supported devices.
288    #[doc(alias = "nvmlVgpuTypeGetMaxInstancesPerVm")]
289    pub fn max_instances_per_vm(&self) -> Result<u32, NvmlError> {
290        let sym = nvml_sym(
291            self.device
292                .nvml()
293                .lib
294                .nvmlVgpuTypeGetMaxInstancesPerVm
295                .as_ref(),
296        )?;
297
298        let mut max = 0;
299        unsafe {
300            nvml_try(sym(self.id, &mut max))?;
301        }
302        Ok(max)
303    }
304
305    /// Retrieve count of vGPU's supported display heads.
306    ///
307    /// # Errors
308    ///
309    /// * `Uninitialized`, if the library has not been successfully initialized
310    /// * `InvalidArg`, if this `Device` is invalid
311    /// * `Unknown`, on any unexpected error
312    ///
313    /// # Device Support
314    ///
315    /// Kepler or newer fully supported devices.
316    #[doc(alias = "nvmlVgpuTypeGetNumDisplayHeads")]
317    pub fn num_display_heads(&self) -> Result<u32, NvmlError> {
318        let sym = nvml_sym(
319            self.device
320                .nvml()
321                .lib
322                .nvmlVgpuTypeGetNumDisplayHeads
323                .as_ref(),
324        )?;
325
326        let mut heads = 0;
327        unsafe {
328            nvml_try(sym(self.id, &mut heads))?;
329        }
330        Ok(heads)
331    }
332
333    /// Retrieve vGPU display head's maximum supported resolution.
334    ///
335    /// The `display_head` argument specifies the 0-based display index, the
336    /// maximum being what [`VgpuType::num_display_heads`] returns.
337    ///
338    /// # Errors
339    ///
340    /// * `Uninitialized`, if the library has not been successfully initialized
341    /// * `InvalidArg`, if this `Device` is invalid
342    /// * `Unknown`, on any unexpected error
343    ///
344    /// # Device Support
345    ///
346    /// Kepler or newer fully supported devices.
347    #[doc(alias = "nvmlVgpuTypeGetResolution")]
348    pub fn resolution(&self, display_head: u32) -> Result<(u32, u32), NvmlError> {
349        let sym = nvml_sym(self.device.nvml().lib.nvmlVgpuTypeGetResolution.as_ref())?;
350
351        let (mut x, mut y) = (0, 0);
352        unsafe {
353            nvml_try(sym(self.id, display_head, &mut x, &mut y))?;
354        }
355        Ok((x, y))
356    }
357}