diff --git a/daemon/src/gpu_controller.rs b/daemon/src/gpu_controller.rs index df353eb..66d13b9 100644 --- a/daemon/src/gpu_controller.rs +++ b/daemon/src/gpu_controller.rs @@ -41,6 +41,27 @@ impl PowerProfile { } } +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +pub struct ClocksTable { + gpu_power_levels: BTreeMap, // + mem_power_levels: BTreeMap, + 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, + pub clocks_table: Option, } 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 { + 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::().unwrap(); + let voltage = split[2].replace("mV", "").parse::().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::().unwrap(); + let voltage = split[2].replace("mV", "").parse::().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::().unwrap(); + let max_clock = split[2].replace("MHz", "").parse::().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::().unwrap(); + let max_clock = split[2].replace("MHz", "").parse::().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::().unwrap(); + let max_voltage = split[2].replace("mV", "").parse::().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(); diff --git a/gui/src/main.rs b/gui/src/main.rs index 8bc8fe6..f2684f8 100644 --- a/gui/src/main.rs +++ b/gui/src/main.rs @@ -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 { - PowerProfile::Auto => Some(0), - PowerProfile::High => Some(1), - PowerProfile::Low => Some(2), - }); + 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); diff --git a/gui/src/main_window.glade b/gui/src/main_window.glade index a5f56e1..2c5c881 100644 --- a/gui/src/main_window.glade +++ b/gui/src/main_window.glade @@ -818,8 +818,8 @@ True False - 5 - 5 + 10 + 10 Description of the selected power profile @@ -847,6 +847,32 @@ 4 + + + True + False + 0.10000000149011612 + none + + + + + + True + False + Power Levels + + + + + + + + False + True + 5 + + 1