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