1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
use std::collections::BTreeMap; use void::{Void, ResultVoidExt}; use sys::gpu::pstate; use sys; use types::{Microvolts, MicrovoltsDelta, Kilohertz, KilohertzDelta, Percentage, Range, Delta, RawConversion}; use clock::ClockDomain; pub use sys::gpu::pstate::{PstateId as PState, VoltageInfoDomain as VoltageDomain, UtilizationDomain}; #[derive(Debug, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)] pub struct PStateSettings { pub id: PState, pub editable: bool, pub clocks: Vec<ClockEntry>, pub base_voltages: Vec<BaseVoltage>, } #[derive(Debug, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)] pub struct PStates { pub editable: bool, pub pstates: Vec<PStateSettings>, pub overvolt: Vec<BaseVoltage>, } #[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)] pub enum ClockEntry { Single { domain: ClockDomain, editable: bool, frequency_delta: Delta<KilohertzDelta>, frequency: Kilohertz, }, Range { domain: ClockDomain, editable: bool, frequency_delta: Delta<KilohertzDelta>, frequency_range: Range<Kilohertz>, voltage_domain: VoltageDomain, voltage_range: Range<Microvolts>, }, } impl ClockEntry { pub fn domain(&self) -> ClockDomain { match *self { ClockEntry::Single { domain, .. } => domain, ClockEntry::Range { domain, .. } => domain, } } pub fn editable(&self) -> bool { match *self { ClockEntry::Single { editable, .. } => editable, ClockEntry::Range { editable, .. } => editable, } } pub fn frequency_delta(&self) -> Delta<KilohertzDelta> { match *self { ClockEntry::Single { frequency_delta, .. } => frequency_delta, ClockEntry::Range { frequency_delta, .. } => frequency_delta, } } } #[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)] pub struct BaseVoltage { pub voltage_domain: VoltageDomain, pub editable: bool, pub voltage: Microvolts, pub voltage_delta: Delta<MicrovoltsDelta>, } impl PStateSettings { pub fn from_raw(settings: &pstate::NV_GPU_PERF_PSTATES20_PSTATE, num_clocks: usize, num_base_voltages: usize) -> Result<Self, sys::ArgumentRangeError> { trace!("convert_raw({:#?}, {:?}, {:?})", settings, num_clocks, num_base_voltages); Ok(PStateSettings { id: PState::from_raw(settings.pstateId)?, editable: settings.bIsEditable.get(), clocks: settings.clocks[..num_clocks].iter().map(RawConversion::convert_raw).collect::<Result<_, _>>()?, base_voltages: settings.baseVoltages[..num_base_voltages].iter().map(RawConversion::convert_raw).collect::<Result<_, _>>()?, }) } } impl RawConversion for pstate::NV_GPU_PERF_PSTATES20_INFO_V2 { type Target = PStates; type Error = sys::ArgumentRangeError; fn convert_raw(&self) -> Result<Self::Target, Self::Error> { trace!("convert_raw({:#?})", self); Ok(PStates { editable: self.bIsEditable.get(), pstates: self.pstates[..self.numPstates as usize].iter().map(|ps| PStateSettings::from_raw(ps, self.numClocks as _, self.numBaseVoltages as _)).collect::<Result<_, _>>()?, overvolt: self.voltages[..self.numVoltages as usize].iter().map(RawConversion::convert_raw).collect::<Result<_, _>>()?, }) } } impl RawConversion for pstate::NV_GPU_PERF_PSTATE20_BASE_VOLTAGE_ENTRY_V1 { type Target = BaseVoltage; type Error = sys::ArgumentRangeError; fn convert_raw(&self) -> Result<Self::Target, Self::Error> { trace!("convert_raw({:#?})", self); Ok(BaseVoltage { voltage_domain: VoltageDomain::from_raw(self.domainId)?, editable: self.bIsEditable.get(), voltage: Microvolts(self.volt_uV), voltage_delta: match self.voltDelta_uV.convert_raw().void_unwrap() { Delta { value, range } => Delta { value: MicrovoltsDelta(value.0), range: Range { min: MicrovoltsDelta(range.min.0), max: MicrovoltsDelta(range.max.0), }, }, }, }) } } impl RawConversion for pstate::NV_GPU_PSTATE20_CLOCK_ENTRY_V1 { type Target = ClockEntry; type Error = sys::ArgumentRangeError; fn convert_raw(&self) -> Result<Self::Target, Self::Error> { trace!("convert_raw({:#?})", self); Ok(match self.data.get(pstate::PstateClockType::from_raw(self.typeId)?) { pstate::NV_GPU_PSTATE20_CLOCK_ENTRY_DATA_VALUE::Single(single) => ClockEntry::Single { domain: ClockDomain::from_raw(self.domainId)?, editable: self.bIsEditable.get(), frequency_delta: self.freqDelta_kHz.convert_raw().void_unwrap(), frequency: Kilohertz(single.freq_kHz), }, pstate::NV_GPU_PSTATE20_CLOCK_ENTRY_DATA_VALUE::Range(range) => ClockEntry::Range { domain: ClockDomain::from_raw(self.domainId)?, editable: self.bIsEditable.get(), frequency_delta: self.freqDelta_kHz.convert_raw().void_unwrap(), frequency_range: Range { min: Kilohertz(range.minFreq_kHz), max: Kilohertz(range.maxFreq_kHz), }, voltage_domain: VoltageDomain::from_raw(range.domainId)?, voltage_range: Range { min: Microvolts(range.minVoltage_uV), max: Microvolts(range.maxVoltage_uV), }, }, }) } } impl RawConversion for pstate::NV_GPU_PERF_PSTATES20_PARAM_DELTA { type Target = Delta<KilohertzDelta>; type Error = Void; fn convert_raw(&self) -> Result<Self::Target, Self::Error> { trace!("convert_raw({:#?})", self); Ok(Delta { value: KilohertzDelta(self.value), range: Range { min: KilohertzDelta(self.min), max: KilohertzDelta(self.max), }, }) } } impl RawConversion for pstate::NV_GPU_DYNAMIC_PSTATES_INFO_EX { type Target = BTreeMap<pstate::UtilizationDomain, Percentage>; type Error = sys::ArgumentRangeError; fn convert_raw(&self) -> Result<Self::Target, Self::Error> { trace!("convert_raw({:#?})", self); if self.flag_enabled() { Ok(BTreeMap::new()) } else { pstate::UtilizationDomain::values() .map(|domain| (domain, &self.utilization[domain.raw() as usize])) .filter(|&(_, util)| util.bIsPresent.get()) .map(|(id, util)| Percentage::from_raw(util.percentage).map(|p| (id, p))) .collect() } } }