From 8760dfaba22a0fd2b78ab746a5212f11191e9c25 Mon Sep 17 00:00:00 2001 From: Benedikt Steinbusch Date: Fri, 5 Jan 2024 15:03:05 +0100 Subject: [PATCH 1/4] add ScopeId and FieldValueRequest --- CHANGELOG.md | 5 ++++ nvml-wrapper/src/structs/device.rs | 37 ++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3361cc8..b606858 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ This file describes the changes / additions / fixes between wrapper releases, tr ## [Unreleased] +### Added + +* `ScopeId` +* `FieldValueRequest` + ## [0.10.0] (released 2024-02-10) Updates for NVML 12.2. diff --git a/nvml-wrapper/src/structs/device.rs b/nvml-wrapper/src/structs/device.rs index 2176607..0f8113b 100644 --- a/nvml-wrapper/src/structs/device.rs +++ b/nvml-wrapper/src/structs/device.rs @@ -101,3 +101,40 @@ pub struct RetiredPage { #[derive(Debug, Clone, Eq, PartialEq, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct FieldId(pub u32); + +/// Can be used to specify an optional scope to a given `FieldId` +/// +/// Used in `FieldValue` and `Device.field_values_for()`. +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct ScopeId(pub u32); + +/// Specify a field ID and an optional scope ID for requesting data samples +/// from a device. +/// +/// Used in [`crate::struct_wrappers::device::FieldValueSample`] and +/// [`crate::device::Device::field_values_for()`]. +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct FieldValueRequest { + /// Populate this newtype with the constants `nvml_wrapper::sys_exports::field_id::*`. + pub id: FieldId, + /// Optionally populate this with a `scopeId` appropriate for the associated [`FieldId`]. + /// + /// See NVIDIA's field ID constant docs (`NVML_FI_*`) to understand what scope + /// IDs may be valid for which field IDs. + pub scope_id: Option, +} + +impl FieldValueRequest { + pub fn id(id: FieldId) -> Self { + Self { id, scope_id: None } + } + + pub fn id_with_scope(id: FieldId, scope_id: ScopeId) -> Self { + Self { + id, + scope_id: Some(scope_id), + } + } +} From 89a184754957d11e3a48d7ce8b86798659fbd76b Mon Sep 17 00:00:00 2001 From: Benedikt Steinbusch Date: Fri, 5 Jan 2024 15:03:05 +0100 Subject: [PATCH 2/4] change field_values_for to allow requesting scoped fields --- CHANGELOG.md | 7 ++ nvml-wrapper/src/device.rs | 114 +++++++++++---------- nvml-wrapper/src/struct_wrappers/device.rs | 9 +- 3 files changed, 71 insertions(+), 59 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b606858..ed283ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,13 @@ This file describes the changes / additions / fixes between wrapper releases, tr * `ScopeId` * `FieldValueRequest` +### Changed + +* `Device` + * Methods + * `field_values_for()` +* `FieldValueSample` + ## [0.10.0] (released 2024-02-10) Updates for NVML 12.2. diff --git a/nvml-wrapper/src/device.rs b/nvml-wrapper/src/device.rs index 2e46a24..eadec46 100644 --- a/nvml-wrapper/src/device.rs +++ b/nvml-wrapper/src/device.rs @@ -35,6 +35,7 @@ use std::{ mem, os::raw::{c_int, c_uint, c_ulonglong}, ptr, + ops::Deref, }; use static_assertions::assert_impl_all; @@ -2652,9 +2653,9 @@ impl<'nvml> Device<'nvml> { } /** - Get values for the given slice of `FieldId`s. + Get values for the given `FieldValueRequest`s. - NVIDIA's docs say that if any of the `FieldId`s are populated by the same driver + NVIDIA's docs say that if any of the `FieldValueRequest`s are populated by the same driver call, the samples for those IDs will be populated by a single call instead of a call per ID. It would appear, then, that this is essentially a "batch-request" API path for better performance. @@ -2662,7 +2663,7 @@ impl<'nvml> Device<'nvml> { There are too many field ID constants defined in the header to reasonably wrap them with an enum in this crate. Instead, I've re-exported the defined ID constants at `nvml_wrapper::sys_exports::field_id::*`; stick those - constants in `FieldId`s for use with this function. + constants in `FieldValueRequest`s for use with this function. # Errors @@ -2676,30 +2677,31 @@ impl<'nvml> Device<'nvml> { # Device Support - Device support varies per `FieldId` that you pass in. + Device support varies per `FieldValueRequest` that you pass in. */ // TODO: Example #[doc(alias = "nvmlDeviceGetFieldValues")] - pub fn field_values_for( + pub fn field_values_for( &self, - id_slice: &[FieldId], - ) -> Result>, NvmlError> { + ids: I, + ) -> Result>, NvmlError> + where + I: IntoIterator, + I::Item: Deref, + { let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetFieldValues.as_ref())?; unsafe { - let values_count = id_slice.len(); - let mut field_values: Vec = Vec::with_capacity(values_count); - - for id in id_slice.iter() { - let mut raw: nvmlFieldValue_t = mem::zeroed(); - raw.fieldId = id.0; - - field_values.push(raw); - } + let mut field_values: Vec = ids.into_iter().map( + |id| nvmlFieldValue_t { + fieldId: id.id.0, + scopeId: id.scope_id.clone().unwrap_or(ScopeId(0)).0, + ..mem::zeroed() + }).collect(); nvml_try(sym( self.device, - values_count as i32, + field_values.len() as i32, field_values.as_mut_ptr(), ))?; @@ -5070,7 +5072,7 @@ mod test { use crate::enum_wrappers::device::*; use crate::enums::device::GpuLockedClocksSetting; use crate::error::*; - use crate::structs::device::FieldId; + use crate::structs::device::{FieldId, FieldValueRequest}; use crate::sys_exports::field_id::*; use crate::test_utils::*; @@ -5558,44 +5560,44 @@ mod test { let nvml = nvml(); test_with_device(3, &nvml, |device| { device.field_values_for(&[ - FieldId(NVML_FI_DEV_ECC_CURRENT), - FieldId(NVML_FI_DEV_ECC_PENDING), - FieldId(NVML_FI_DEV_ECC_SBE_VOL_TOTAL), - FieldId(NVML_FI_DEV_ECC_DBE_VOL_TOTAL), - FieldId(NVML_FI_DEV_ECC_SBE_AGG_TOTAL), - FieldId(NVML_FI_DEV_ECC_DBE_AGG_TOTAL), - FieldId(NVML_FI_DEV_ECC_SBE_VOL_L1), - FieldId(NVML_FI_DEV_ECC_DBE_VOL_L1), - FieldId(NVML_FI_DEV_ECC_SBE_VOL_L2), - FieldId(NVML_FI_DEV_ECC_DBE_VOL_L2), - FieldId(NVML_FI_DEV_ECC_SBE_VOL_DEV), - FieldId(NVML_FI_DEV_ECC_DBE_VOL_DEV), - FieldId(NVML_FI_DEV_ECC_SBE_VOL_REG), - FieldId(NVML_FI_DEV_ECC_DBE_VOL_REG), - FieldId(NVML_FI_DEV_ECC_SBE_VOL_TEX), - FieldId(NVML_FI_DEV_ECC_DBE_VOL_TEX), - FieldId(NVML_FI_DEV_ECC_DBE_VOL_CBU), - FieldId(NVML_FI_DEV_ECC_SBE_AGG_L1), - FieldId(NVML_FI_DEV_ECC_DBE_AGG_L1), - FieldId(NVML_FI_DEV_ECC_SBE_AGG_L2), - FieldId(NVML_FI_DEV_ECC_DBE_AGG_L2), - FieldId(NVML_FI_DEV_ECC_SBE_AGG_DEV), - FieldId(NVML_FI_DEV_ECC_DBE_AGG_DEV), - FieldId(NVML_FI_DEV_ECC_SBE_AGG_REG), - FieldId(NVML_FI_DEV_ECC_DBE_AGG_REG), - FieldId(NVML_FI_DEV_ECC_SBE_AGG_TEX), - FieldId(NVML_FI_DEV_ECC_DBE_AGG_TEX), - FieldId(NVML_FI_DEV_ECC_DBE_AGG_CBU), - FieldId(NVML_FI_DEV_PERF_POLICY_POWER), - FieldId(NVML_FI_DEV_PERF_POLICY_THERMAL), - FieldId(NVML_FI_DEV_PERF_POLICY_SYNC_BOOST), - FieldId(NVML_FI_DEV_PERF_POLICY_BOARD_LIMIT), - FieldId(NVML_FI_DEV_PERF_POLICY_LOW_UTILIZATION), - FieldId(NVML_FI_DEV_PERF_POLICY_RELIABILITY), - FieldId(NVML_FI_DEV_PERF_POLICY_TOTAL_APP_CLOCKS), - FieldId(NVML_FI_DEV_PERF_POLICY_TOTAL_BASE_CLOCKS), - FieldId(NVML_FI_DEV_MEMORY_TEMP), - FieldId(NVML_FI_DEV_TOTAL_ENERGY_CONSUMPTION), + FieldValueRequest::id(FieldId(NVML_FI_DEV_ECC_CURRENT)), + FieldValueRequest::id(FieldId(NVML_FI_DEV_ECC_PENDING)), + FieldValueRequest::id(FieldId(NVML_FI_DEV_ECC_SBE_VOL_TOTAL)), + FieldValueRequest::id(FieldId(NVML_FI_DEV_ECC_DBE_VOL_TOTAL)), + FieldValueRequest::id(FieldId(NVML_FI_DEV_ECC_SBE_AGG_TOTAL)), + FieldValueRequest::id(FieldId(NVML_FI_DEV_ECC_DBE_AGG_TOTAL)), + FieldValueRequest::id(FieldId(NVML_FI_DEV_ECC_SBE_VOL_L1)), + FieldValueRequest::id(FieldId(NVML_FI_DEV_ECC_DBE_VOL_L1)), + FieldValueRequest::id(FieldId(NVML_FI_DEV_ECC_SBE_VOL_L2)), + FieldValueRequest::id(FieldId(NVML_FI_DEV_ECC_DBE_VOL_L2)), + FieldValueRequest::id(FieldId(NVML_FI_DEV_ECC_SBE_VOL_DEV)), + FieldValueRequest::id(FieldId(NVML_FI_DEV_ECC_DBE_VOL_DEV)), + FieldValueRequest::id(FieldId(NVML_FI_DEV_ECC_SBE_VOL_REG)), + FieldValueRequest::id(FieldId(NVML_FI_DEV_ECC_DBE_VOL_REG)), + FieldValueRequest::id(FieldId(NVML_FI_DEV_ECC_SBE_VOL_TEX)), + FieldValueRequest::id(FieldId(NVML_FI_DEV_ECC_DBE_VOL_TEX)), + FieldValueRequest::id(FieldId(NVML_FI_DEV_ECC_DBE_VOL_CBU)), + FieldValueRequest::id(FieldId(NVML_FI_DEV_ECC_SBE_AGG_L1)), + FieldValueRequest::id(FieldId(NVML_FI_DEV_ECC_DBE_AGG_L1)), + FieldValueRequest::id(FieldId(NVML_FI_DEV_ECC_SBE_AGG_L2)), + FieldValueRequest::id(FieldId(NVML_FI_DEV_ECC_DBE_AGG_L2)), + FieldValueRequest::id(FieldId(NVML_FI_DEV_ECC_SBE_AGG_DEV)), + FieldValueRequest::id(FieldId(NVML_FI_DEV_ECC_DBE_AGG_DEV)), + FieldValueRequest::id(FieldId(NVML_FI_DEV_ECC_SBE_AGG_REG)), + FieldValueRequest::id(FieldId(NVML_FI_DEV_ECC_DBE_AGG_REG)), + FieldValueRequest::id(FieldId(NVML_FI_DEV_ECC_SBE_AGG_TEX)), + FieldValueRequest::id(FieldId(NVML_FI_DEV_ECC_DBE_AGG_TEX)), + FieldValueRequest::id(FieldId(NVML_FI_DEV_ECC_DBE_AGG_CBU)), + FieldValueRequest::id(FieldId(NVML_FI_DEV_PERF_POLICY_POWER)), + FieldValueRequest::id(FieldId(NVML_FI_DEV_PERF_POLICY_THERMAL)), + FieldValueRequest::id(FieldId(NVML_FI_DEV_PERF_POLICY_SYNC_BOOST)), + FieldValueRequest::id(FieldId(NVML_FI_DEV_PERF_POLICY_BOARD_LIMIT)), + FieldValueRequest::id(FieldId(NVML_FI_DEV_PERF_POLICY_LOW_UTILIZATION)), + FieldValueRequest::id(FieldId(NVML_FI_DEV_PERF_POLICY_RELIABILITY)), + FieldValueRequest::id(FieldId(NVML_FI_DEV_PERF_POLICY_TOTAL_APP_CLOCKS)), + FieldValueRequest::id(FieldId(NVML_FI_DEV_PERF_POLICY_TOTAL_BASE_CLOCKS)), + FieldValueRequest::id(FieldId(NVML_FI_DEV_MEMORY_TEMP)), + FieldValueRequest::id(FieldId(NVML_FI_DEV_TOTAL_ENERGY_CONSUMPTION)), ]) }) } diff --git a/nvml-wrapper/src/struct_wrappers/device.rs b/nvml-wrapper/src/struct_wrappers/device.rs index 213d16b..816210c 100644 --- a/nvml-wrapper/src/struct_wrappers/device.rs +++ b/nvml-wrapper/src/struct_wrappers/device.rs @@ -3,7 +3,7 @@ use crate::enum_wrappers::device::{BridgeChip, EncoderType, FbcSessionType, Samp use crate::enums::device::{FirmwareVersion, SampleValue, UsedGpuMemory}; use crate::error::{nvml_try, Bits, NvmlError}; use crate::ffi::bindings::*; -use crate::structs::device::FieldId; +use crate::structs::device::{FieldId, ScopeId, FieldValueRequest}; #[cfg(feature = "serde")] use serde_derive::{Deserialize, Serialize}; use std::{ @@ -527,7 +527,7 @@ impl From for ProcessUtilizationSample { #[derive(Debug)] pub struct FieldValueSample { /// The field that this sample is for. - pub field: FieldId, + pub field: FieldValueRequest, /// This sample's CPU timestamp in μs (Unix time). pub timestamp: i64, /** @@ -555,7 +555,10 @@ impl TryFrom for FieldValueSample { */ fn try_from(value: nvmlFieldValue_t) -> Result { Ok(Self { - field: FieldId(value.fieldId), + field: FieldValueRequest::id_with_scope( + FieldId(value.fieldId), + ScopeId(value.scopeId), + ), timestamp: value.timestamp, latency: value.latencyUsec, value: match nvml_try(value.nvmlReturn) { From 759eb1be5381121ca00bbfedca7dc9c5139e5960 Mon Sep 17 00:00:00 2001 From: Benedikt Steinbusch Date: Fri, 16 Feb 2024 07:57:45 +0100 Subject: [PATCH 3/4] improve formatting --- nvml-wrapper/src/device.rs | 12 +++++++----- nvml-wrapper/src/struct_wrappers/device.rs | 7 ++----- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/nvml-wrapper/src/device.rs b/nvml-wrapper/src/device.rs index eadec46..5175c4f 100644 --- a/nvml-wrapper/src/device.rs +++ b/nvml-wrapper/src/device.rs @@ -33,9 +33,9 @@ use std::{ convert::TryFrom, ffi::CStr, mem, + ops::Deref, os::raw::{c_int, c_uint, c_ulonglong}, ptr, - ops::Deref, }; use static_assertions::assert_impl_all; @@ -2687,17 +2687,19 @@ impl<'nvml> Device<'nvml> { ) -> Result>, NvmlError> where I: IntoIterator, - I::Item: Deref, + I::Item: Deref, { let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetFieldValues.as_ref())?; unsafe { - let mut field_values: Vec = ids.into_iter().map( - |id| nvmlFieldValue_t { + let mut field_values: Vec = ids + .into_iter() + .map(|id| nvmlFieldValue_t { fieldId: id.id.0, scopeId: id.scope_id.clone().unwrap_or(ScopeId(0)).0, ..mem::zeroed() - }).collect(); + }) + .collect(); nvml_try(sym( self.device, diff --git a/nvml-wrapper/src/struct_wrappers/device.rs b/nvml-wrapper/src/struct_wrappers/device.rs index 816210c..e836d78 100644 --- a/nvml-wrapper/src/struct_wrappers/device.rs +++ b/nvml-wrapper/src/struct_wrappers/device.rs @@ -3,7 +3,7 @@ use crate::enum_wrappers::device::{BridgeChip, EncoderType, FbcSessionType, Samp use crate::enums::device::{FirmwareVersion, SampleValue, UsedGpuMemory}; use crate::error::{nvml_try, Bits, NvmlError}; use crate::ffi::bindings::*; -use crate::structs::device::{FieldId, ScopeId, FieldValueRequest}; +use crate::structs::device::{FieldId, FieldValueRequest, ScopeId}; #[cfg(feature = "serde")] use serde_derive::{Deserialize, Serialize}; use std::{ @@ -555,10 +555,7 @@ impl TryFrom for FieldValueSample { */ fn try_from(value: nvmlFieldValue_t) -> Result { Ok(Self { - field: FieldValueRequest::id_with_scope( - FieldId(value.fieldId), - ScopeId(value.scopeId), - ), + field: FieldValueRequest::id_with_scope(FieldId(value.fieldId), ScopeId(value.scopeId)), timestamp: value.timestamp, latency: value.latencyUsec, value: match nvml_try(value.nvmlReturn) { From 1a5dcedc6b09f7a38aefa75091412b3a104d39d6 Mon Sep 17 00:00:00 2001 From: Benedikt Steinbusch Date: Sat, 17 Feb 2024 10:18:47 +0100 Subject: [PATCH 4/4] remove FieldValueRequest from FieldValueSample --- nvml-wrapper/src/struct_wrappers/device.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/nvml-wrapper/src/struct_wrappers/device.rs b/nvml-wrapper/src/struct_wrappers/device.rs index e836d78..b4e8cc4 100644 --- a/nvml-wrapper/src/struct_wrappers/device.rs +++ b/nvml-wrapper/src/struct_wrappers/device.rs @@ -3,7 +3,7 @@ use crate::enum_wrappers::device::{BridgeChip, EncoderType, FbcSessionType, Samp use crate::enums::device::{FirmwareVersion, SampleValue, UsedGpuMemory}; use crate::error::{nvml_try, Bits, NvmlError}; use crate::ffi::bindings::*; -use crate::structs::device::{FieldId, FieldValueRequest, ScopeId}; +use crate::structs::device::{FieldId, ScopeId}; #[cfg(feature = "serde")] use serde_derive::{Deserialize, Serialize}; use std::{ @@ -527,7 +527,9 @@ impl From for ProcessUtilizationSample { #[derive(Debug)] pub struct FieldValueSample { /// The field that this sample is for. - pub field: FieldValueRequest, + pub field: FieldId, + /// The field scope that this sample is for. + pub scope: ScopeId, /// This sample's CPU timestamp in μs (Unix time). pub timestamp: i64, /** @@ -555,7 +557,8 @@ impl TryFrom for FieldValueSample { */ fn try_from(value: nvmlFieldValue_t) -> Result { Ok(Self { - field: FieldValueRequest::id_with_scope(FieldId(value.fieldId), ScopeId(value.scopeId)), + field: FieldId(value.fieldId), + scope: ScopeId(value.scopeId), timestamp: value.timestamp, latency: value.latencyUsec, value: match nvml_try(value.nvmlReturn) {