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
use std::fmt;
use sys::gpu::{pstate, clock};
use sys;

#[derive(Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
pub struct Microvolts(pub u32);

impl fmt::Debug for Microvolts {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} mV", self.0 as f32 / 1000.0)
    }
}

#[derive(Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
pub struct Kilohertz(pub u32);

impl fmt::Debug for Kilohertz {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.0 < 1000 {
            write!(f, "{} kHz", self.0)
        } else {
            write!(f, "{} MHz", self.0 as f32 / 1000.0)
        }
    }
}

#[derive(Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
pub struct Percentage(pub u32);

impl fmt::Debug for Percentage {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} %", self.0)
    }
}

pub type PState = pstate::PstateId;

pub type VoltageDomain = pstate::VoltageInfoDomain;

#[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 struct Delta {
    pub value: i32,
    pub min: i32,
    pub max: i32,
}

pub type ClockDomain = clock::PublicClockId;

#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
pub enum ClockEntry {
    Single {
        domain: ClockDomain,
        editable: bool,
        frequency_delta: Delta,
        frequency: Kilohertz,
    },
    Range {
        domain: ClockDomain,
        editable: bool,
        frequency_delta: Delta,
        min_frequency: Kilohertz,
        max_frequency: Kilohertz,
        voltage_domain: VoltageDomain,
        min_voltage: Microvolts,
        max_voltage: Microvolts,
    },
}

#[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,
}

impl PStates {
    pub fn from_raw(info: &pstate::NV_GPU_PERF_PSTATES20_INFO_V2) -> sys::Result<Self> {
        Ok(PStates {
            editable: info.bIsEditable.get(),
            pstates: info.pstates[..info.numPstates as usize].iter().map(|ps| PStateSettings::from_raw(ps, info.numClocks as _, info.numBaseVoltages as _)).collect::<sys::Result<_>>()?,
            overvolt: info.voltages[..info.numVoltages as usize].iter().map(BaseVoltage::from_raw).collect::<sys::Result<_>>()?,
        })
    }
}

impl PStateSettings {
    pub fn from_raw(settings: &pstate::NV_GPU_PERF_PSTATES20_PSTATE, num_clocks: usize, num_base_voltages: usize) -> sys::Result<Self> {
        Ok(PStateSettings {
            id: PState::from_raw(settings.pstateId)?,
            editable: settings.bIsEditable.get(),
            clocks: settings.clocks[..num_clocks].iter().map(ClockEntry::from_raw).collect::<sys::Result<_>>()?,
            base_voltages: settings.baseVoltages[..num_base_voltages].iter().map(BaseVoltage::from_raw).collect::<sys::Result<_>>()?,
        })
    }
}

impl BaseVoltage {
    pub fn from_raw(s: &pstate::NV_GPU_PERF_PSTATE20_BASE_VOLTAGE_ENTRY_V1) -> sys::Result<Self> {
        Ok(BaseVoltage {
            voltage_domain: VoltageDomain::from_raw(s.domainId)?,
            editable: s.bIsEditable.get(),
            voltage: Microvolts(s.volt_uV),
            voltage_delta: Delta::from_raw(&s.voltDelta_uV),
        })
    }
}

impl ClockEntry {
    pub fn from_raw(clock: &pstate::NV_GPU_PSTATE20_CLOCK_ENTRY_V1) -> sys::Result<Self> {
        Ok(match clock.data.get(pstate::PstateClockType::from_raw(clock.typeId)?) {
            pstate::NV_GPU_PSTATE20_CLOCK_ENTRY_DATA_VALUE::Single(single) => ClockEntry::Single {
                domain: ClockDomain::from_raw(clock.domainId)?,
                editable: clock.bIsEditable.get(),
                frequency_delta: Delta::from_raw(&clock.freqDelta_kHz),
                frequency: Kilohertz(single.freq_kHz),
            },
            pstate::NV_GPU_PSTATE20_CLOCK_ENTRY_DATA_VALUE::Range(range) => ClockEntry::Range {
                domain: ClockDomain::from_raw(clock.domainId)?,
                editable: clock.bIsEditable.get(),
                frequency_delta: Delta::from_raw(&clock.freqDelta_kHz),
                min_frequency: Kilohertz(range.minFreq_kHz),
                max_frequency: Kilohertz(range.maxFreq_kHz),
                voltage_domain: VoltageDomain::from_raw(range.domainId)?,
                min_voltage: Microvolts(range.minVoltage_uV),
                max_voltage: Microvolts(range.maxVoltage_uV),
            },
        })
    }
}

impl Delta {
    pub fn from_raw(delta: &pstate::NV_GPU_PERF_PSTATES20_PARAM_DELTA) -> Self {
        Delta {
            value: delta.value,
            min: delta.min,
            max: delta.max,
        }
    }
}