Added Power Levels reading support (pp_od_clk_voltage)

This commit is contained in:
Ilya Zlobintsev 2020-11-20 17:29:38 +02:00
parent e58663f7a9
commit d66c7dca69
3 changed files with 150 additions and 10 deletions

View File

@ -41,6 +41,27 @@ impl PowerProfile {
}
}
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct ClocksTable {
gpu_power_levels: BTreeMap<u32, (i32, i32)>, //<power level, (clockspeed, voltage)>
mem_power_levels: BTreeMap<u32, (i32, i32)>,
gpu_clocks_range: (i32, i32),
mem_clocks_range: (i32, i32),
voltage_range: (i32, i32),
}
impl ClocksTable {
fn new() -> Self {
ClocksTable {
gpu_power_levels: BTreeMap::new(),
mem_power_levels: BTreeMap::new(),
gpu_clocks_range: (0, 0),
mem_clocks_range: (0, 0),
voltage_range: (0, 0),
}
}
}
#[derive(Serialize, Deserialize, Debug)]
pub struct GpuStats {
pub mem_used: u64,
@ -91,7 +112,8 @@ pub struct GpuInfo {
pub link_width: u8,
pub vulkan_info: VulkanInfo,
pub pci_slot: String,
pub power_profile: PowerProfile,
pub power_profile: Option<PowerProfile>,
pub clocks_table: Option<ClocksTable>,
}
impl GpuController {
@ -239,8 +261,13 @@ impl GpuController {
let vulkan_info = GpuController::get_vulkan_info(&model_id);
let power_profile = match self.get_power_profile() {
Ok(p) => p,
Err(_) => PowerProfile::Auto,
Ok(p) => Some(p),
Err(_) => None,
};
let clocks_table = match self.get_clocks_table() {
Ok(t) => Some(t),
Err(_) => None,
};
GpuInfo {
@ -258,6 +285,7 @@ impl GpuController {
vulkan_info,
pci_slot,
power_profile,
clocks_table,
}
}
@ -386,6 +414,85 @@ impl GpuController {
}
}
fn get_clocks_table(&self) -> Result<ClocksTable, GpuControllerError> {
match fs::read_to_string(self.hw_path.join("pp_od_clk_voltage")) {
Ok(s) => {
let mut clocks_table = ClocksTable::new();
let lines: Vec<&str> = s.trim().split("\n").collect();
log::trace!("Reading clocks table");
let mut i = 0;
while i < lines.len() {
log::trace!("matching {}", lines[i]);
match lines[i] {
"OD_SCLK:" => {
i += 1;
while (lines[i].split_at(2).0 != "OD") && i < lines.len() {
let split: Vec<&str> = lines[i].split_whitespace().collect();
let num = split[0].chars().nth(0).unwrap().to_digit(10).unwrap();
let clock = split[1].replace("MHz", "").parse::<i32>().unwrap();
let voltage = split[2].replace("mV", "").parse::<i32>().unwrap();
clocks_table.gpu_power_levels.insert(num, (clock, voltage));
log::trace!("Adding gpu power level {}MHz {}mv", clock, voltage);
i += 1;
}
},
"OD_MCLK:" => {
i += 1;
while (lines[i].split_at(2).0 != "OD") && i < lines.len() {
let split: Vec<&str> = lines[i].split_whitespace().collect();
let num = split[0].chars().nth(0).unwrap().to_digit(10).unwrap();
let clock = split[1].replace("MHz", "").parse::<i32>().unwrap();
let voltage = split[2].replace("mV", "").parse::<i32>().unwrap();
clocks_table.mem_power_levels.insert(num, (clock, voltage));
log::trace!("Adding vram power level {}MHz {}mv", clock, voltage);
i += 1;
}
},
"OD_RANGE:" => {
i += 1;
while lines[i].split_at(2).0 != "OD" {
let split: Vec<&str> = lines[i].split_whitespace().collect();
let name = split[0].replace(":", "");
match name.as_ref() {
"SCLK" => {
let min_clock = split[1].replace("MHz", "").parse::<i32>().unwrap();
let max_clock = split[2].replace("MHz", "").parse::<i32>().unwrap();
clocks_table.gpu_clocks_range = (min_clock, max_clock);
log::trace!("Maximum gpu clock: {}", max_clock);
},
"MCLK" => {
let min_clock = split[1].replace("MHz", "").parse::<i32>().unwrap();
let max_clock = split[2].replace("MHz", "").parse::<i32>().unwrap();
clocks_table.mem_clocks_range = (min_clock, max_clock);
log::trace!("Maximum vram clock: {}", max_clock);
},
"VDDC" => {
let min_voltage = split[1].replace("mV", "").parse::<i32>().unwrap();
let max_voltage = split[2].replace("mV", "").parse::<i32>().unwrap();
clocks_table.voltage_range = (min_voltage, max_voltage);
log::trace!("Maximum voltage: {}", max_voltage);
},
_ => (),
}
i += 1;
if i >= lines.len() {
break
}
}
},
_ => i += 1,
}
}
Ok(clocks_table)
},
Err(_) => Err(GpuControllerError::NotSupported),
}
}
fn get_vulkan_info(pci_id: &str) -> VulkanInfo {
let mut device_name = String::from("Not supported");
let mut api_version = String::new();

View File

@ -362,11 +362,18 @@ fn set_info(builder: &Builder, d: DaemonConnection, gpu_id: u32) {
gpu_power_adjustment.set_upper(power_cap_max as f64);
gpu_power_adjustment.set_value(power_cap as f64);
power_profile_select_comboboxtext.set_active(match &gpu_info.power_profile {
match &gpu_info.power_profile {
Some(power_profile) => {
power_profile_select_comboboxtext.set_active(match power_profile {
PowerProfile::Auto => Some(0),
PowerProfile::High => Some(1),
PowerProfile::Low => Some(2),
});
},
None => {
power_profile_select_comboboxtext.set_sensitive(false);
}
}
let fan_control = d.get_fan_control(gpu_id);

View File

@ -818,8 +818,8 @@
<object class="GtkLabel" id="power_profile_description_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-start">5</property>
<property name="margin-end">5</property>
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="label" translatable="yes">Description of the selected power profile</property>
</object>
<packing>
@ -847,6 +847,32 @@
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkFrame">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label-xalign">0.10000000149011612</property>
<property name="shadow-type">none</property>
<child>
<placeholder/>
</child>
<child type="label">
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Power Levels</property>
<attributes>
<attribute name="weight" value="semibold"/>
</attributes>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">5</property>
</packing>
</child>
</object>
<packing>
<property name="position">1</property>