From 239af5a2af6ce1d9e3f58742fb73e53341c7d0c4 Mon Sep 17 00:00:00 2001 From: Ilya Zlobintsev Date: Sat, 14 Nov 2020 09:09:28 +0200 Subject: [PATCH] Implemented GPU power cap modification --- daemon/src/daemon_connection.rs | 16 ++++++++ daemon/src/gpu_controller.rs | 34 +++++++++++++--- daemon/src/hw_mon.rs | 37 ++++++++++++++++- daemon/src/lib.rs | 17 ++++++-- gui/src/main.rs | 26 +++++++++++- gui/src/main_window.glade | 71 +++++++++++++++++++++++++++++++++ 6 files changed, 189 insertions(+), 12 deletions(-) diff --git a/daemon/src/daemon_connection.rs b/daemon/src/daemon_connection.rs index 8fde840..ec7689e 100644 --- a/daemon/src/daemon_connection.rs +++ b/daemon/src/daemon_connection.rs @@ -148,6 +148,22 @@ impl DaemonConnection { } } + pub fn set_power_cap(&self, gpu_id: u32, cap: i32) -> Result<(), DaemonError> { + let mut s = UnixStream::connect(SOCK_PATH).unwrap(); + s.write_all(&bincode::serialize(&Action::SetPowerCap(gpu_id, cap)).unwrap()) + .unwrap(); + s.shutdown(std::net::Shutdown::Write).expect("Could not shut down"); + let mut buffer = Vec::::new(); + s.read_to_end(&mut buffer).unwrap(); + + let result: Result = bincode::deserialize(&buffer).unwrap(); + + match result { + Ok(_) => Ok(()), + Err(e) => Err(e), + } + } + pub fn get_gpus(&self) -> Result, DaemonError> { log::trace!("sending request"); let mut s = UnixStream::connect(SOCK_PATH).unwrap(); diff --git a/daemon/src/gpu_controller.rs b/daemon/src/gpu_controller.rs index de7d576..f352018 100644 --- a/daemon/src/gpu_controller.rs +++ b/daemon/src/gpu_controller.rs @@ -1,4 +1,4 @@ -use crate::config::{Config, GpuConfig, GpuIdentifier}; +use crate::config::{GpuConfig, GpuIdentifier}; use crate::hw_mon::{HWMon, HWMonError}; use serde::{Deserialize, Serialize}; use std::path::{Path, PathBuf}; @@ -13,7 +13,8 @@ pub struct GpuStats { pub gpu_freq: i32, pub gpu_temp: i32, pub power_avg: i32, - pub power_max: i32, + pub power_cap: i32, + pub power_cap_max: i32, pub fan_speed: i32, pub max_fan_speed: i32, } @@ -54,6 +55,8 @@ pub struct GpuInfo { pub link_width: u8, pub vulkan_info: VulkanInfo, pub pci_slot: String, + pub power_cap: i32, + pub power_cap_max: i32, } impl GpuController { @@ -210,6 +213,11 @@ impl GpuController { let vulkan_info = GpuController::get_vulkan_info(&model_id); + let (power_cap, power_cap_max) = match &self.hw_mon { + Some(hw_mon) => (hw_mon.get_power_cap(), hw_mon.get_power_cap_max()), + None => (0, 0), + }; + GpuInfo { gpu_vendor: vendor, gpu_model: model, @@ -224,6 +232,8 @@ impl GpuController { link_width, vulkan_info, pci_slot, + power_cap, + power_cap_max, } } @@ -238,9 +248,9 @@ impl GpuController { Err(_) => 0, }; - let (mem_freq, gpu_freq, gpu_temp, power_avg, power_max, fan_speed, max_fan_speed) = match &self.hw_mon { - Some(hw_mon) => (hw_mon.get_mem_freq(), hw_mon.get_gpu_freq(), hw_mon.get_gpu_temp(), hw_mon.get_power_avg(), hw_mon.get_power_cap(), hw_mon.get_fan_speed(), hw_mon.fan_max_speed), - None => (0, 0, 0, 0, 0, 0, 0), + let (mem_freq, gpu_freq, gpu_temp, power_avg, power_cap, power_cap_max, fan_speed, max_fan_speed) = match &self.hw_mon { + Some(hw_mon) => (hw_mon.get_mem_freq(), hw_mon.get_gpu_freq(), hw_mon.get_gpu_temp(), hw_mon.get_power_avg(), hw_mon.get_power_cap(), hw_mon.get_power_cap_max(), hw_mon.get_fan_speed(), hw_mon.fan_max_speed), + None => (0, 0, 0, 0, 0, 0, 0, 0), }; GpuStats { @@ -250,7 +260,8 @@ impl GpuController { gpu_freq, gpu_temp, power_avg, - power_max, + power_cap, + power_cap_max, fan_speed, max_fan_speed, } @@ -312,6 +323,17 @@ impl GpuController { } } + pub fn set_power_cap(&mut self, cap: i32) -> Result<(), HWMonError> { + match &mut self.hw_mon { + Some(hw_mon) => { + hw_mon.set_power_cap(cap).unwrap(); + self.gpu_info.power_cap = cap; + Ok(()) + }, + None => Err(HWMonError::NoHWMon), + } + } + 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/daemon/src/hw_mon.rs b/daemon/src/hw_mon.rs index cd4a51d..191ef04 100644 --- a/daemon/src/hw_mon.rs +++ b/daemon/src/hw_mon.rs @@ -15,6 +15,7 @@ use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug)] pub enum HWMonError { PermissionDenied, + InvalidValue, NoHWMon, } @@ -24,6 +25,7 @@ pub struct HWMon { pub fan_max_speed: i32, fan_control: Arc, fan_curve: Arc>>, + power_cap: i32, } impl HWMon { @@ -37,16 +39,18 @@ impl HWMon { Err(_) => 0, }; - let mon = HWMon { + let mut mon = HWMon { hwmon_path: hwmon_path.clone(), fan_max_speed, fan_control: Arc::new(AtomicBool::new(false)), fan_curve: Arc::new(RwLock::new(fan_curve)), + power_cap: 0, }; if fan_control_enabled { mon.start_fan_control().unwrap(); } + mon.power_cap = mon.get_power_cap(); mon } @@ -115,6 +119,19 @@ impl HWMon { } } + pub fn get_power_cap_max(&self) -> i32 { + let filename = self.hwmon_path.join("power1_cap_max"); + + match fs::read_to_string(filename) { + Ok(a) => a + .trim() + .parse::() + .unwrap() + / 1000000, + _ => 0, + } + } + pub fn get_power_cap(&self) -> i32 { let filename = self.hwmon_path.join("power1_cap"); @@ -128,6 +145,24 @@ impl HWMon { } } + pub fn set_power_cap(&mut self, cap: i32) -> Result<(), HWMonError> { + + if cap > self.get_power_cap_max() { + return Err(HWMonError::InvalidValue); + } + + let cap = cap * 1000000; + log::trace!("setting power cap to {}", cap); + + match fs::write(self.hwmon_path.join("power1_cap"), cap.to_string()) { + Ok(_) => { + self.power_cap = cap; + Ok(()) + }, + Err(_) => Err(HWMonError::PermissionDenied), + } + } + pub fn get_power_avg(&self) -> i32 { let filename = self.hwmon_path.join("power1_average"); diff --git a/daemon/src/lib.rs b/daemon/src/lib.rs index e65c7d0..fe4a3b0 100644 --- a/daemon/src/lib.rs +++ b/daemon/src/lib.rs @@ -3,7 +3,7 @@ pub mod daemon_connection; pub mod gpu_controller; pub mod hw_mon; -use config::{Config, GpuConfig, GpuIdentifier}; +use config::{Config, GpuConfig}; use serde::{Deserialize, Serialize}; use std::{collections::{BTreeMap, HashMap}, fs}; use std::os::unix::net::{UnixListener, UnixStream}; @@ -35,6 +35,7 @@ pub enum Action { StopFanControl(u32), GetFanControl(u32), SetFanCurve(u32, BTreeMap), + SetPowerCap(u32, i32), Shutdown, } @@ -191,9 +192,6 @@ impl Daemon { } Action::SetFanCurve(i, curve) => match self.gpu_controllers.get_mut(&i) { Some(controller) => { - - let mut buffer = Vec::new(); - stream.read_to_end(&mut buffer).unwrap(); match controller.set_fan_curve(curve) { Ok(_) => { @@ -207,6 +205,17 @@ impl Daemon { }, None => Err(DaemonError::InvalidID), } + Action::SetPowerCap(i, cap) => match self.gpu_controllers.get_mut(&i) { + Some(controller) => { + match controller.set_power_cap(cap) { + Ok(_) => { + Ok(DaemonResponse::OK) + }, + Err(_) => Err(DaemonError::HWMonError), + } + }, + None => Err(DaemonError::InvalidID), + } Action::Shutdown => std::process::exit(0), }; diff --git a/gui/src/main.rs b/gui/src/main.rs index 7062044..ee0b7b2 100644 --- a/gui/src/main.rs +++ b/gui/src/main.rs @@ -40,12 +40,16 @@ fn build_ui(application: >k::Application) { let fan_speed_text_buffer: TextBuffer = builder.get_object("fan_speed_text_buffer").unwrap(); + let power_cap_label: Label = builder.get_object("power_cap_label").unwrap(); + let automatic_fan_control_switch: Switch = builder.get_object("automatic_fan_control_switch").unwrap(); let apply_button: Button = builder.get_object("apply_button").unwrap(); let fan_curve_frame: Frame = builder.get_object("fan_curve_frame").unwrap(); + + let gpu_power_adjustment: Adjustment = builder.get_object("gpu_power_adjustment").unwrap(); let mut unpriviliged: bool = false; @@ -94,8 +98,15 @@ fn build_ui(application: >k::Application) { let fan_curv_frm = fan_curve_frame.clone(); let auto_fan_ctrl_swtch = automatic_fan_control_switch.clone(); + let b = apply_button.clone(); + gpu_power_adjustment.connect_value_changed(move |adjustment| { + println!("changed adjustment value to {}/{}", adjustment.get_value(), adjustment.get_upper()); + b.set_sensitive(true); + power_cap_label.set_text(&format!("{}/{}", adjustment.get_value().floor(), adjustment.get_upper())); + }); + let b = apply_button.clone(); gpu_select_comboboxtext.connect_changed(move |combobox| { let mut current_gpu_id = cur_id.write().unwrap(); *current_gpu_id = combobox.get_active_id().unwrap().parse::().expect("invalid id"); @@ -166,7 +177,7 @@ fn build_ui(application: >k::Application) { gpu_temp_text_buffer.set_text(&format!("{}°C", gpu_stats.gpu_temp)); gpu_power_text_buffer - .set_text(&format!("{}/{}W", gpu_stats.power_avg, gpu_stats.power_max)); + .set_text(&format!("{}/{}W", gpu_stats.power_avg, gpu_stats.power_cap)); fan_speed_text_buffer.set_text(&format!( "{}RPM({}%)", @@ -174,6 +185,7 @@ fn build_ui(application: >k::Application) { (gpu_stats.fan_speed as f64 / gpu_stats.max_fan_speed as f64 * 100 as f64) as i32 )); + glib::Continue(true) }); @@ -268,6 +280,9 @@ fn build_ui(application: >k::Application) { d.start_fan_control(current_gpu_id).unwrap(); } } + + let power_cap = gpu_power_adjustment.get_value().floor() as i32; + d.set_power_cap(current_gpu_id, power_cap).unwrap(); }); }, Err(_) => (), @@ -316,6 +331,11 @@ fn set_info(builder: &Builder, gpu_info: &GpuInfo) { .get_object("vulkan_features_text_buffer") .expect("Couldn't get textbuffer"); + let power_cap_label: Label = builder.get_object("power_cap_label").unwrap(); + + let gpu_power_adjustment: Adjustment = builder.get_object("gpu_power_adjustment").unwrap(); + //let power_cap_scale: Scale = builder.get_object("power_cap_scale").unwrap(); + gpu_model_text_buffer.set_text(&gpu_info.card_model); manufacturer_text_buffer.set_text(&gpu_info.card_vendor); vbios_version_text_buffer.set_text(&gpu_info.vbios_version); @@ -330,6 +350,10 @@ fn set_info(builder: &Builder, gpu_info: &GpuInfo) { vulkan_version_text_buffer.set_text(&gpu_info.vulkan_info.api_version); vulkan_features_text_buffer.set_text(&gpu_info.vulkan_info.features); + power_cap_label.set_text(&format!("{}/{}", gpu_info.power_cap, gpu_info.power_cap_max)); + gpu_power_adjustment.set_upper(gpu_info.power_cap_max as f64); + gpu_power_adjustment.set_value(gpu_info.power_cap as f64); + } fn main() { diff --git a/gui/src/main_window.glade b/gui/src/main_window.glade index 6e02e67..579341b 100644 --- a/gui/src/main_window.glade +++ b/gui/src/main_window.glade @@ -39,6 +39,11 @@ gpu_model + + 100 + 1 + 10 + 50W/100W @@ -65,6 +70,9 @@ Manufacturer + + 50/100 + vbios_version @@ -85,6 +93,7 @@ False + LACT 350 500 @@ -672,6 +681,68 @@ 1 + + + True + False + 0.10000000149011612 + none + + + True + False + 10 + 10 + + + True + False + 50/100 + + + False + True + 0 + + + + + True + True + True + gpu_power_adjustment + False + 0 + 0 + 0 + False + left + + + False + True + 1 + + + + + + + True + False + Power Cap (Watts) + + + + + + + + False + True + 2 + + 1