From 9acaf34536840575c1a815b6729d4984801eeac7 Mon Sep 17 00:00:00 2001 From: Ashley Smith Date: Tue, 2 Mar 2021 10:53:37 +0000 Subject: [PATCH 1/6] Changed sockets to nix crate so we can use abstract sockets and not worry about file permissions or cleaning up the socket. Buffer read code may need some work --- daemon/Cargo.toml | 3 +- daemon/src/daemon_connection.rs | 89 +++++++++++++++++++++++---------- daemon/src/lib.rs | 82 +++++++++++++----------------- 3 files changed, 99 insertions(+), 75 deletions(-) diff --git a/daemon/Cargo.toml b/daemon/Cargo.toml index aae5efe..ab8dd63 100644 --- a/daemon/Cargo.toml +++ b/daemon/Cargo.toml @@ -16,4 +16,5 @@ env_logger = "0.8" rand = "0.8" signal-hook = "0.3" pciid-parser = { git = "https://github.com/ilyazzz/pci-id-parser.git" } -reqwest = { version = "0.11", features = ["blocking", "json"] } \ No newline at end of file +reqwest = { version = "0.11", features = ["blocking", "json"] } +nix = "0.20" diff --git a/daemon/src/daemon_connection.rs b/daemon/src/daemon_connection.rs index 3a4ad6c..fa0dab9 100644 --- a/daemon/src/daemon_connection.rs +++ b/daemon/src/daemon_connection.rs @@ -6,49 +6,83 @@ use crate::{ }; use crate::{Action, DaemonResponse, SOCK_PATH}; use std::collections::{BTreeMap, HashMap}; -use std::io::{Read, Write}; -use std::os::unix::net::UnixStream; #[derive(Clone, Copy)] pub struct DaemonConnection {} +pub const BUFFER_SIZE: usize = 4096; + impl DaemonConnection { pub fn new() -> Result { - match UnixStream::connect(SOCK_PATH) { - Ok(mut stream) => { - stream - .write(&bincode::serialize(&Action::CheckAlive).unwrap()) - .unwrap(); + let addr = nix::sys::socket::SockAddr::Unix(nix::sys::socket::UnixAddr::new_abstract(SOCK_PATH.as_bytes()).unwrap()); + let socket = nix::sys::socket::socket(nix::sys::socket::AddressFamily::Unix, nix::sys::socket::SockType::Stream, nix::sys::socket::SockFlag::empty(), None).expect("Creating socket failed"); + nix::sys::socket::connect(socket, &addr).expect("Socket connect failed"); - stream - .shutdown(std::net::Shutdown::Write) - .expect("Could not shut down"); + nix::unistd::write(socket, &bincode::serialize(&Action::CheckAlive).unwrap()) + .expect("Writing check alive to socket failed"); - let mut buffer = Vec::::new(); - stream.read_to_end(&mut buffer).unwrap(); + nix::sys::socket::shutdown(socket, nix::sys::socket::Shutdown::Write) + .expect("Could not shut down"); - let result: Result = - bincode::deserialize(&buffer).unwrap(); - match result { - Ok(_) => Ok(DaemonConnection {}), - Err(_) => Err(DaemonError::ConnectionFailed), + let mut buffer = Vec::::new(); + buffer.resize(BUFFER_SIZE, 0); + loop { + match nix::unistd::read(socket, &mut buffer) { + Ok(0) => { + break; + }, + Ok(n) => { + assert!(n < buffer.len()); + if n < buffer.len() { + buffer.resize(n, 0); + } + break; + }, + Err(e) => { + panic!("Error reading from socket: {}", e); } } + } + let result: Result = bincode::deserialize(&buffer).expect("failed to deserialize message"); + + match result { + Ok(_) => Ok(DaemonConnection {}), Err(_) => Err(DaemonError::ConnectionFailed), } } fn send_action(&self, action: Action) -> Result { - let mut s = UnixStream::connect(SOCK_PATH).expect("Connection to daemon dropped"); + let addr = nix::sys::socket::SockAddr::Unix(nix::sys::socket::UnixAddr::new_abstract(SOCK_PATH.as_bytes()).unwrap()); + let socket = nix::sys::socket::socket(nix::sys::socket::AddressFamily::Unix, nix::sys::socket::SockType::Stream, nix::sys::socket::SockFlag::empty(), None).expect("Socket failed"); + nix::sys::socket::connect(socket, &addr).expect("connect failed"); - s.write(&bincode::serialize(&action).unwrap()) - .expect("Failed to write"); - s.shutdown(std::net::Shutdown::Write) - .expect("Could nto shut down"); + + let b = bincode::serialize(&action).unwrap(); + nix::unistd::write(socket, &b) + .expect("Writing action to socket failed"); + + nix::sys::socket::shutdown(socket, nix::sys::socket::Shutdown::Write) + .expect("Could not shut down"); let mut buffer = Vec::::new(); - s.read_to_end(&mut buffer).unwrap(); - + buffer.resize(BUFFER_SIZE, 0); + loop { + match nix::unistd::read(socket, &mut buffer) { + Ok(0) => { + break; + }, + Ok(n) => { + assert!(n < buffer.len()); + if n < buffer.len() { + buffer.resize(n, 0); + } + break; + }, + Err(e) => { + panic!("Error reading from socket: {}", e); + } + } + } bincode::deserialize(&buffer).expect("failed to deserialize message") } @@ -163,9 +197,10 @@ impl DaemonConnection { } pub fn shutdown(&self) { - let mut s = UnixStream::connect(SOCK_PATH).unwrap(); - s.write_all(&bincode::serialize(&Action::Shutdown).unwrap()) - .unwrap(); + let addr = nix::sys::socket::SockAddr::Unix(nix::sys::socket::UnixAddr::new_abstract(SOCK_PATH.as_bytes()).unwrap()); + let socket = nix::sys::socket::socket(nix::sys::socket::AddressFamily::Unix, nix::sys::socket::SockType::Stream, nix::sys::socket::SockFlag::empty(), None).expect("Socket failed"); + nix::sys::socket::connect(socket, &addr).expect("connect failed"); + nix::unistd::write(socket, &mut &bincode::serialize(&Action::Shutdown).unwrap()).expect("Writing shutdown to socket failed"); } pub fn get_config(&self) -> Result { diff --git a/daemon/src/lib.rs b/daemon/src/lib.rs index a6bcb74..2d4a553 100644 --- a/daemon/src/lib.rs +++ b/daemon/src/lib.rs @@ -8,24 +8,23 @@ use gpu_controller::PowerProfile; use pciid_parser::PciDatabase; use rand::prelude::*; use serde::{Deserialize, Serialize}; -use std::os::unix::net::{UnixListener, UnixStream}; -use std::process::Command; use std::{ collections::{BTreeMap, HashMap}, fs, }; use std::{ - io::{Read, Write}, path::PathBuf, }; use crate::gpu_controller::GpuController; -pub const SOCK_PATH: &str = "/tmp/amdgpu-configurator.sock"; +// Abstract socket allows anyone to connect without worrying about permissions +// https://unix.stackexchange.com/questions/579612/unix-domain-sockets-for-non-root-user +pub const SOCK_PATH: &str = "amdgpu-configurator.sock"; pub struct Daemon { gpu_controllers: HashMap, - listener: UnixListener, + listener: std::os::unix::io::RawFd, config: Config, } @@ -54,9 +53,10 @@ pub enum Action { impl Daemon { pub fn new(unprivileged: bool) -> Daemon { - if fs::metadata(SOCK_PATH).is_ok() { - fs::remove_file(SOCK_PATH).expect("Failed to take control over socket"); - } + let addr = nix::sys::socket::SockAddr::Unix(nix::sys::socket::UnixAddr::new_abstract(SOCK_PATH.as_bytes()).unwrap()); + let listener = nix::sys::socket::socket(nix::sys::socket::AddressFamily::Unix, nix::sys::socket::SockType::Stream, nix::sys::socket::SockFlag::empty(), None).expect("Socket failed"); + nix::sys::socket::bind(listener, &addr).expect("Bind failed"); + nix::sys::socket::listen(listener, 128).expect("Listen failed"); let config_path = PathBuf::from("/etc/lact.json"); let mut config = if unprivileged { @@ -76,26 +76,6 @@ impl Daemon { } }; - let listener = UnixListener::bind(SOCK_PATH).unwrap(); - - Command::new("chmod") - .arg("664") - .arg(SOCK_PATH) - .output() - .expect("Failed to chmod"); - - Command::new("chown") - .arg("nobody:wheel") - .arg(SOCK_PATH) - .output() - .expect("Failed to chown"); - - Command::new("chown") - .arg(&format!("nobody:{}", config.group)) - .arg(SOCK_PATH) - .output() - .expect("Failed to chown"); - log::info!("Using config {:?}", config); let gpu_controllers = Self::load_gpu_controllers(&mut config); @@ -191,27 +171,38 @@ impl Daemon { } pub fn listen(mut self) { - let listener = self.listener.try_clone().expect("couldn't try_clone"); - for stream in listener.incoming() { - match stream { - Ok(stream) => { - //let mut controller = self.gpu_controller.clone(); - //thread::spawn(move || Daemon::handle_connection(&mut controller, stream)); - //Daemon::handle_connection(&mut self.gpu_controllers, stream); - Daemon::handle_connection(&mut self, stream); - } - Err(err) => { - log::error!("Error: {}", err); - break; - } + loop { + let stream = nix::sys::socket::accept(self.listener).expect("Accept failed"); + if stream < 0 { + log::error!("Error from accept"); + break; + } else { + Daemon::handle_connection(&mut self, stream); } } } - fn handle_connection(&mut self, mut stream: UnixStream) { + fn handle_connection(&mut self, stream: i32) { log::trace!("Reading buffer"); let mut buffer = Vec::::new(); - stream.read_to_end(&mut buffer).unwrap(); + buffer.resize(daemon_connection::BUFFER_SIZE, 0); + loop { + match nix::unistd::read(stream, &mut buffer) { + Ok(0) => { + break; + }, + Ok(n) => { + assert!(n < buffer.len()); + if n < buffer.len() { + buffer.resize(n, 0); + } + break; + }, + Err(e) => { + panic!("Error reading from socket: {}", e); + } + } + } //log::trace!("finished reading, buffer size {}", buffer.len()); log::trace!("Attempting to deserialize {:?}", &buffer); //log::trace!("{:?}", action); @@ -426,7 +417,6 @@ impl Daemon { controller.stop_fan_control(); } } - fs::remove_file(SOCK_PATH).expect("Failed to remove socket"); } std::process::exit(0); } @@ -441,9 +431,7 @@ impl Daemon { }; log::trace!("Responding"); - stream - .write_all(&bincode::serialize(&response).unwrap()) - .expect("Failed writing response"); + nix::unistd::write(stream, &mut &bincode::serialize(&response).unwrap()).expect("Writing response to socket failed"); //stream // .shutdown(std::net::Shutdown::Write) // .expect("Could not shut down"); From b5a3e554ed4e9df7174cec3a09b72939e9799420 Mon Sep 17 00:00:00 2001 From: Ilya Zlobintsev Date: Tue, 2 Mar 2021 15:11:45 +0200 Subject: [PATCH 2/6] Show GPU usage and temperature on the OC page --- daemon/src/gpu_controller.rs | 7 +++ gui/src/app/root_stack/oc_page/stats_grid.rs | 46 ++++++++++++++++++-- gui/src/main.rs | 2 + 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/daemon/src/gpu_controller.rs b/daemon/src/gpu_controller.rs index 1f72fba..de40dcb 100644 --- a/daemon/src/gpu_controller.rs +++ b/daemon/src/gpu_controller.rs @@ -104,6 +104,7 @@ pub struct GpuStats { pub fan_speed: Option, pub max_fan_speed: Option, pub voltage: Option, + pub gpu_usage: Option, } #[derive(Serialize, Deserialize, Debug)] @@ -329,6 +330,11 @@ impl GpuController { Ok(a) => Some(a.trim().parse::().unwrap() / 1024 / 1024), Err(_) => None, }; + + let gpu_usage = match fs::read_to_string(self.hw_path.join("gpu_busy_percent")) { + Ok(a) => Some(a.trim().parse::().unwrap()), + Err(_) => None, + }; let ( mem_freq, @@ -367,6 +373,7 @@ impl GpuController { fan_speed, max_fan_speed, voltage, + gpu_usage, }) } diff --git a/gui/src/app/root_stack/oc_page/stats_grid.rs b/gui/src/app/root_stack/oc_page/stats_grid.rs index 0186a8d..0f28b88 100644 --- a/gui/src/app/root_stack/oc_page/stats_grid.rs +++ b/gui/src/app/root_stack/oc_page/stats_grid.rs @@ -10,6 +10,8 @@ pub struct StatsGrid { vram_clock_label: Label, gpu_voltage_label: Label, power_usage_label: Label, + gpu_temperature_label: Label, + gpu_usage_label: Label, } impl StatsGrid { @@ -37,7 +39,7 @@ impl StatsGrid { vram_usage_overlay.add(&vram_usage_bar); vram_usage_overlay.add_overlay(&vram_usage_label); - container.attach(&vram_usage_overlay, 1, 0, 1, 1); + container.attach(&vram_usage_overlay, 1, 0, 2, 1); } let gpu_clock_label = Label::new(None); @@ -81,7 +83,7 @@ impl StatsGrid { gpu_voltage_box.set_halign(Align::Center); - container.attach(&gpu_voltage_box, 0, 2, 1, 1); + container.attach(&gpu_voltage_box, 2, 1, 1, 1); } let power_usage_label = Label::new(None); @@ -96,7 +98,35 @@ impl StatsGrid { power_usage_box.set_halign(Align::Center); - container.attach(&power_usage_box, 1, 2, 1, 1); + container.attach(&power_usage_box, 0, 2, 1, 1); + } + + let gpu_temperature_label = Label::new(None); + { + let gpu_temperature_box = Box::new(Orientation::Horizontal, 5); + + gpu_temperature_box.pack_start(&Label::new(Some("GPU Temperature:")), false, false, 2); + + // gpu_temperature_label.set_markup("0°C"); + + gpu_temperature_box.pack_start(&gpu_temperature_label, false, false, 2); + + gpu_temperature_box.set_halign(Align::Center); + + container.attach(&gpu_temperature_box, 1, 2, 1, 1); + } + + let gpu_usage_label = Label::new(None); + { + let gpu_usage_box = Box::new(Orientation::Horizontal, 5); + + gpu_usage_box.pack_start(&Label::new(Some("GPU Usage:")), false, false, 2); + + gpu_usage_box.pack_start(&gpu_usage_label, false, false, 2); + + gpu_usage_box.set_halign(Align::Center); + + container.attach(&gpu_usage_box, 2, 2, 1, 1); } Self { @@ -107,6 +137,8 @@ impl StatsGrid { vram_clock_label, gpu_voltage_label, power_usage_label, + gpu_temperature_label, + gpu_usage_label, } } @@ -141,5 +173,13 @@ impl StatsGrid { stats.power_avg.unwrap_or_else(|| 0), stats.power_cap.unwrap_or_else(|| 0) )); + self.gpu_temperature_label.set_markup(&format!( + "{}°C", + stats.gpu_temp.unwrap_or_default() + )); + self.gpu_usage_label.set_markup(&format!( + "{}%", + stats.gpu_usage.unwrap_or_default() + )); } } diff --git a/gui/src/main.rs b/gui/src/main.rs index 98c9f6b..015643d 100644 --- a/gui/src/main.rs +++ b/gui/src/main.rs @@ -25,6 +25,8 @@ fn ask_for_online_update(connection: &DaemonConnection) { let mut config = connection.get_config().unwrap(); if let None = config.allow_online_update { + log::trace!("Online access permission not configured! Showing the dialog"); + let diag = MessageDialog::new( None::<&Window>, DialogFlags::empty(), From 0c002452bf709b320360a240c9d36e46d0f715f3 Mon Sep 17 00:00:00 2001 From: Ilya Zlobintsev Date: Tue, 2 Mar 2021 15:13:40 +0200 Subject: [PATCH 3/6] Formatting --- daemon/src/gpu_controller.rs | 2 +- gui/src/app/root_stack/oc_page/stats_grid.rs | 14 +++++--------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/daemon/src/gpu_controller.rs b/daemon/src/gpu_controller.rs index de40dcb..30be57e 100644 --- a/daemon/src/gpu_controller.rs +++ b/daemon/src/gpu_controller.rs @@ -330,7 +330,7 @@ impl GpuController { Ok(a) => Some(a.trim().parse::().unwrap() / 1024 / 1024), Err(_) => None, }; - + let gpu_usage = match fs::read_to_string(self.hw_path.join("gpu_busy_percent")) { Ok(a) => Some(a.trim().parse::().unwrap()), Err(_) => None, diff --git a/gui/src/app/root_stack/oc_page/stats_grid.rs b/gui/src/app/root_stack/oc_page/stats_grid.rs index 0f28b88..7e148d9 100644 --- a/gui/src/app/root_stack/oc_page/stats_grid.rs +++ b/gui/src/app/root_stack/oc_page/stats_grid.rs @@ -100,7 +100,7 @@ impl StatsGrid { container.attach(&power_usage_box, 0, 2, 1, 1); } - + let gpu_temperature_label = Label::new(None); { let gpu_temperature_box = Box::new(Orientation::Horizontal, 5); @@ -173,13 +173,9 @@ impl StatsGrid { stats.power_avg.unwrap_or_else(|| 0), stats.power_cap.unwrap_or_else(|| 0) )); - self.gpu_temperature_label.set_markup(&format!( - "{}°C", - stats.gpu_temp.unwrap_or_default() - )); - self.gpu_usage_label.set_markup(&format!( - "{}%", - stats.gpu_usage.unwrap_or_default() - )); + self.gpu_temperature_label + .set_markup(&format!("{}°C", stats.gpu_temp.unwrap_or_default())); + self.gpu_usage_label + .set_markup(&format!("{}%", stats.gpu_usage.unwrap_or_default())); } } From 13fc0166bd417ef84a77fc05d3e42d622d723460 Mon Sep 17 00:00:00 2001 From: Ilya Zlobintsev Date: Tue, 2 Mar 2021 16:18:51 +0200 Subject: [PATCH 4/6] Add power cap adjustment --- daemon/src/gpu_controller.rs | 9 ++ gui/src/app.rs | 8 +- gui/src/app/root_stack/oc_page.rs | 30 +++++-- .../app/root_stack/oc_page/power_cap_frame.rs | 84 +++++++++++++++++++ .../root_stack/oc_page/power_profile_frame.rs | 1 - 5 files changed, 125 insertions(+), 7 deletions(-) create mode 100644 gui/src/app/root_stack/oc_page/power_cap_frame.rs diff --git a/daemon/src/gpu_controller.rs b/daemon/src/gpu_controller.rs index 30be57e..31e1951 100644 --- a/daemon/src/gpu_controller.rs +++ b/daemon/src/gpu_controller.rs @@ -133,6 +133,8 @@ pub struct GpuInfo { pub pci_slot: String, pub power_profile: Option, pub clocks_table: Option, + pub power_cap: Option, + pub power_cap_max: Option, } #[derive(Deserialize, Serialize)] @@ -213,6 +215,11 @@ impl GpuController { Err(_) => None, }; + if let Some(hw_mon) = &self.hw_mon { + info.power_cap = hw_mon.get_power_cap(); + info.power_cap_max = hw_mon.get_power_cap_max(); + } + info } @@ -317,6 +324,8 @@ impl GpuController { pci_slot, power_profile: None, clocks_table: None, + power_cap: None, + power_cap_max: None, } } diff --git a/gui/src/app.rs b/gui/src/app.rs index e92d688..aa64fef 100644 --- a/gui/src/app.rs +++ b/gui/src/app.rs @@ -179,6 +179,12 @@ impl App { .expect("Failed to set power profile"); } + if let Some(cap) = app.root_stack.oc_page.get_power_cap() { + app.daemon_connection + .set_power_cap(gpu_id, cap) + .expect("Failed to set power cap"); + } + app.set_info(gpu_id); }); } @@ -195,7 +201,7 @@ impl App { self.root_stack.info_page.set_info(&gpu_info); log::trace!("Setting clocks"); - self.root_stack.oc_page.set_clocks(&gpu_info.clocks_table); + self.root_stack.oc_page.set_info(&gpu_info); log::trace!("Setting power profile {:?}", gpu_info.power_profile); self.root_stack diff --git a/gui/src/app/root_stack/oc_page.rs b/gui/src/app/root_stack/oc_page.rs index 651d904..43938c4 100644 --- a/gui/src/app/root_stack/oc_page.rs +++ b/gui/src/app/root_stack/oc_page.rs @@ -1,23 +1,25 @@ mod clocks_frame; +mod power_cap_frame; mod power_profile_frame; mod stats_grid; mod warning_frame; use clocks_frame::ClocksSettings; -use daemon::gpu_controller::{ClocksTable, GpuStats, PowerProfile}; +use daemon::gpu_controller::{GpuInfo, GpuStats, PowerProfile}; use gtk::*; +use clocks_frame::ClocksFrame; +use power_cap_frame::PowerCapFrame; use power_profile_frame::PowerProfileFrame; use stats_grid::StatsGrid; use warning_frame::WarningFrame; -use self::clocks_frame::ClocksFrame; - #[derive(Clone)] pub struct OcPage { pub container: Box, stats_grid: StatsGrid, power_profile_frame: PowerProfileFrame, + power_cap_frame: PowerCapFrame, clocks_frame: ClocksFrame, pub warning_frame: WarningFrame, } @@ -34,6 +36,10 @@ impl OcPage { container.pack_start(&stats_grid.container, false, true, 5); + let power_cap_frame = PowerCapFrame::new(); + + container.pack_start(&power_cap_frame.container, false, true, 0); + let power_profile_frame = PowerProfileFrame::new(); container.pack_start(&power_profile_frame.container, false, true, 0); @@ -48,6 +54,7 @@ impl OcPage { power_profile_frame, clocks_frame, warning_frame, + power_cap_frame, } } @@ -70,10 +77,16 @@ impl OcPage { }); } { + let f = f.clone(); self.clocks_frame.connect_clocks_changed(move || { f(); }) } + { + self.power_cap_frame.connect_cap_changed(move || { + f(); + }) + } } pub fn set_power_profile(&self, profile: &Option) { @@ -93,14 +106,17 @@ impl OcPage { } } - pub fn set_clocks(&self, clocks_table: &Option) { - match clocks_table { + pub fn set_info(&self, info: &GpuInfo) { + match &info.clocks_table { Some(clocks_table) => { self.clocks_frame.show(); self.clocks_frame.set_clocks(clocks_table); } None => self.clocks_frame.hide(), } + + self.power_cap_frame + .set_data(info.power_cap, info.power_cap_max); } pub fn get_clocks(&self) -> Option { @@ -109,4 +125,8 @@ impl OcPage { false => None, } } + + pub fn get_power_cap(&self) -> Option { + self.power_cap_frame.get_cap() + } } diff --git a/gui/src/app/root_stack/oc_page/power_cap_frame.rs b/gui/src/app/root_stack/oc_page/power_cap_frame.rs new file mode 100644 index 0000000..f2fb78d --- /dev/null +++ b/gui/src/app/root_stack/oc_page/power_cap_frame.rs @@ -0,0 +1,84 @@ +use gtk::*; + +#[derive(Clone)] +pub struct PowerCapFrame { + pub container: Frame, + label: Label, + adjustment: Adjustment, +} + +impl PowerCapFrame { + pub fn new() -> Self { + let container = Frame::new(None); + + container.set_shadow_type(ShadowType::None); + + container.set_label_widget(Some(&{ + let label = Label::new(None); + label.set_markup("Power Usage Limit"); + label + })); + container.set_label_align(0.2, 0.0); + + let root_box = Box::new(Orientation::Horizontal, 0); + + let label = Label::new(None); + + root_box.pack_start(&label, false, true, 5); + + let adjustment = Adjustment::new(0.0, 0.0, 0.0, 1.0, 10.0, 0.0); + { + let label = label.clone(); + adjustment.connect_value_changed(move |adj| { + label.set_markup(&format!( + "{}/{} W", + adj.get_value().round(), + adj.get_upper() + )); + }); + } + + let scale = Scale::new(Orientation::Horizontal, Some(&adjustment)); + + scale.set_draw_value(false); + + root_box.pack_start(&scale, true, true, 5); + + container.add(&root_box); + + Self { + container, + label, + adjustment, + } + } + + pub fn set_data(&self, power_cap: Option, power_cap_max: Option) { + if let Some(power_cap_max) = power_cap_max { + self.adjustment.set_upper(power_cap_max as f64); + } else { + self.container.set_visible(false); + } + if let Some(power_cap) = power_cap { + self.adjustment.set_value(power_cap as f64); + } else { + self.container.set_visible(false); + } + } + + pub fn get_cap(&self) -> Option { + // Using match gives a warning that floats shouldn't be used in patterns + let cap = self.adjustment.get_value(); + if cap == 0.0 { + None + } else { + Some(cap as i64) + } + } + + pub fn connect_cap_changed(&self, f: F) { + self.adjustment.connect_value_changed(move |_| { + f(); + }); + } +} diff --git a/gui/src/app/root_stack/oc_page/power_profile_frame.rs b/gui/src/app/root_stack/oc_page/power_profile_frame.rs index 65db873..810d4b8 100644 --- a/gui/src/app/root_stack/oc_page/power_profile_frame.rs +++ b/gui/src/app/root_stack/oc_page/power_profile_frame.rs @@ -50,7 +50,6 @@ impl PowerProfileFrame { } container.add(&root_box); - Self { container, combo_box, From 358b35b49a8759305631dad2baea75dc4babc3db Mon Sep 17 00:00:00 2001 From: Ilya Zlobintsev Date: Tue, 2 Mar 2021 16:20:48 +0200 Subject: [PATCH 5/6] Remove unused GetPowerCap method --- daemon/src/daemon_connection.rs | 7 ------- daemon/src/lib.rs | 8 -------- 2 files changed, 15 deletions(-) diff --git a/daemon/src/daemon_connection.rs b/daemon/src/daemon_connection.rs index fa0dab9..7ab6b50 100644 --- a/daemon/src/daemon_connection.rs +++ b/daemon/src/daemon_connection.rs @@ -128,13 +128,6 @@ impl DaemonConnection { } } - pub fn get_power_cap(&self, gpu_id: u32) -> Result<(i64, i64), DaemonError> { - match self.send_action(Action::GetPowerCap(gpu_id))? { - DaemonResponse::PowerCap(cap) => Ok(cap), - _ => unreachable!(), - } - } - pub fn set_power_cap(&self, gpu_id: u32, cap: i64) -> Result<(), DaemonError> { match self.send_action(Action::SetPowerCap(gpu_id, cap))? { DaemonResponse::OK => Ok(()), diff --git a/daemon/src/lib.rs b/daemon/src/lib.rs index 2d4a553..d4afcc8 100644 --- a/daemon/src/lib.rs +++ b/daemon/src/lib.rs @@ -41,7 +41,6 @@ pub enum Action { GetFanControl(u32), SetFanCurve(u32, BTreeMap), SetPowerCap(u32, i64), - GetPowerCap(u32), SetPowerProfile(u32, PowerProfile), // SetGPUPowerState(u32, u32, i64, Option), SetGPUMaxPowerState(u32, i64, Option), @@ -295,13 +294,6 @@ impl Daemon { }, None => Err(DaemonError::InvalidID), }, - Action::GetPowerCap(i) => match self.gpu_controllers.get(&i) { - Some(controller) => match controller.get_power_cap() { - Ok(cap) => Ok(DaemonResponse::PowerCap(cap)), - Err(_) => Err(DaemonError::HWMonError), - }, - None => Err(DaemonError::InvalidID), - }, Action::SetPowerProfile(i, profile) => match self.gpu_controllers.get_mut(&i) { Some(controller) => match controller.set_power_profile(profile) { Ok(_) => { From 0bfc6c5acdd800d33ce92527328a9477c215b180 Mon Sep 17 00:00:00 2001 From: Ilya Zlobintsev Date: Tue, 2 Mar 2021 18:12:24 +0200 Subject: [PATCH 6/6] Small buffer reading refactor and formatting --- README.md | 2 - daemon/src/daemon_connection.rs | 78 ++++++++++++++++++--------------- daemon/src/lib.rs | 38 +++++++++++----- 3 files changed, 69 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index d6f9000..cfa1387 100644 --- a/README.md +++ b/README.md @@ -44,8 +44,6 @@ sudo systemctl enable --now lactd ``` You can now use the application. -Note: By default, only members of the group `wheel` can change settings. This can be changed by editing `/etc/lact.json` and changing the `group` value. - # CLI There is also a cli available. diff --git a/daemon/src/daemon_connection.rs b/daemon/src/daemon_connection.rs index 7ab6b50..0d96cda 100644 --- a/daemon/src/daemon_connection.rs +++ b/daemon/src/daemon_connection.rs @@ -1,9 +1,8 @@ +use crate::config::Config; +use crate::gpu_controller::{FanControlInfo, GpuStats}; use crate::gpu_controller::{GpuInfo, PowerProfile}; +use crate::Daemon; use crate::DaemonError; -use crate::{ - config::Config, - gpu_controller::{FanControlInfo, GpuStats}, -}; use crate::{Action, DaemonResponse, SOCK_PATH}; use std::collections::{BTreeMap, HashMap}; @@ -14,8 +13,16 @@ pub const BUFFER_SIZE: usize = 4096; impl DaemonConnection { pub fn new() -> Result { - let addr = nix::sys::socket::SockAddr::Unix(nix::sys::socket::UnixAddr::new_abstract(SOCK_PATH.as_bytes()).unwrap()); - let socket = nix::sys::socket::socket(nix::sys::socket::AddressFamily::Unix, nix::sys::socket::SockType::Stream, nix::sys::socket::SockFlag::empty(), None).expect("Creating socket failed"); + let addr = nix::sys::socket::SockAddr::Unix( + nix::sys::socket::UnixAddr::new_abstract(SOCK_PATH.as_bytes()).unwrap(), + ); + let socket = nix::sys::socket::socket( + nix::sys::socket::AddressFamily::Unix, + nix::sys::socket::SockType::Stream, + nix::sys::socket::SockFlag::empty(), + None, + ) + .expect("Creating socket failed"); nix::sys::socket::connect(socket, &addr).expect("Socket connect failed"); nix::unistd::write(socket, &bincode::serialize(&Action::CheckAlive).unwrap()) @@ -30,20 +37,21 @@ impl DaemonConnection { match nix::unistd::read(socket, &mut buffer) { Ok(0) => { break; - }, + } Ok(n) => { assert!(n < buffer.len()); if n < buffer.len() { buffer.resize(n, 0); } break; - }, + } Err(e) => { panic!("Error reading from socket: {}", e); } } } - let result: Result = bincode::deserialize(&buffer).expect("failed to deserialize message"); + let result: Result = + bincode::deserialize(&buffer).expect("failed to deserialize message"); match result { Ok(_) => Ok(DaemonConnection {}), @@ -52,37 +60,26 @@ impl DaemonConnection { } fn send_action(&self, action: Action) -> Result { - let addr = nix::sys::socket::SockAddr::Unix(nix::sys::socket::UnixAddr::new_abstract(SOCK_PATH.as_bytes()).unwrap()); - let socket = nix::sys::socket::socket(nix::sys::socket::AddressFamily::Unix, nix::sys::socket::SockType::Stream, nix::sys::socket::SockFlag::empty(), None).expect("Socket failed"); + let addr = nix::sys::socket::SockAddr::Unix( + nix::sys::socket::UnixAddr::new_abstract(SOCK_PATH.as_bytes()).unwrap(), + ); + let socket = nix::sys::socket::socket( + nix::sys::socket::AddressFamily::Unix, + nix::sys::socket::SockType::Stream, + nix::sys::socket::SockFlag::empty(), + None, + ) + .expect("Socket failed"); nix::sys::socket::connect(socket, &addr).expect("connect failed"); - let b = bincode::serialize(&action).unwrap(); - nix::unistd::write(socket, &b) - .expect("Writing action to socket failed"); + nix::unistd::write(socket, &b).expect("Writing action to socket failed"); nix::sys::socket::shutdown(socket, nix::sys::socket::Shutdown::Write) .expect("Could not shut down"); - let mut buffer = Vec::::new(); - buffer.resize(BUFFER_SIZE, 0); - loop { - match nix::unistd::read(socket, &mut buffer) { - Ok(0) => { - break; - }, - Ok(n) => { - assert!(n < buffer.len()); - if n < buffer.len() { - buffer.resize(n, 0); - } - break; - }, - Err(e) => { - panic!("Error reading from socket: {}", e); - } - } - } + let buffer = Daemon::read_buffer(socket); + bincode::deserialize(&buffer).expect("failed to deserialize message") } @@ -190,10 +187,19 @@ impl DaemonConnection { } pub fn shutdown(&self) { - let addr = nix::sys::socket::SockAddr::Unix(nix::sys::socket::UnixAddr::new_abstract(SOCK_PATH.as_bytes()).unwrap()); - let socket = nix::sys::socket::socket(nix::sys::socket::AddressFamily::Unix, nix::sys::socket::SockType::Stream, nix::sys::socket::SockFlag::empty(), None).expect("Socket failed"); + let addr = nix::sys::socket::SockAddr::Unix( + nix::sys::socket::UnixAddr::new_abstract(SOCK_PATH.as_bytes()).unwrap(), + ); + let socket = nix::sys::socket::socket( + nix::sys::socket::AddressFamily::Unix, + nix::sys::socket::SockType::Stream, + nix::sys::socket::SockFlag::empty(), + None, + ) + .expect("Socket failed"); nix::sys::socket::connect(socket, &addr).expect("connect failed"); - nix::unistd::write(socket, &mut &bincode::serialize(&Action::Shutdown).unwrap()).expect("Writing shutdown to socket failed"); + nix::unistd::write(socket, &mut &bincode::serialize(&Action::Shutdown).unwrap()) + .expect("Writing shutdown to socket failed"); } pub fn get_config(&self) -> Result { diff --git a/daemon/src/lib.rs b/daemon/src/lib.rs index d4afcc8..e2f3e3e 100644 --- a/daemon/src/lib.rs +++ b/daemon/src/lib.rs @@ -8,19 +8,18 @@ use gpu_controller::PowerProfile; use pciid_parser::PciDatabase; use rand::prelude::*; use serde::{Deserialize, Serialize}; +use std::path::PathBuf; use std::{ collections::{BTreeMap, HashMap}, fs, }; -use std::{ - path::PathBuf, -}; use crate::gpu_controller::GpuController; // Abstract socket allows anyone to connect without worrying about permissions // https://unix.stackexchange.com/questions/579612/unix-domain-sockets-for-non-root-user pub const SOCK_PATH: &str = "amdgpu-configurator.sock"; +pub const BUFFER_SIZE: usize = 4096; pub struct Daemon { gpu_controllers: HashMap, @@ -52,8 +51,16 @@ pub enum Action { impl Daemon { pub fn new(unprivileged: bool) -> Daemon { - let addr = nix::sys::socket::SockAddr::Unix(nix::sys::socket::UnixAddr::new_abstract(SOCK_PATH.as_bytes()).unwrap()); - let listener = nix::sys::socket::socket(nix::sys::socket::AddressFamily::Unix, nix::sys::socket::SockType::Stream, nix::sys::socket::SockFlag::empty(), None).expect("Socket failed"); + let addr = nix::sys::socket::SockAddr::Unix( + nix::sys::socket::UnixAddr::new_abstract(SOCK_PATH.as_bytes()).unwrap(), + ); + let listener = nix::sys::socket::socket( + nix::sys::socket::AddressFamily::Unix, + nix::sys::socket::SockType::Stream, + nix::sys::socket::SockFlag::empty(), + None, + ) + .expect("Socket failed"); nix::sys::socket::bind(listener, &addr).expect("Bind failed"); nix::sys::socket::listen(listener, 128).expect("Listen failed"); @@ -181,27 +188,34 @@ impl Daemon { } } - fn handle_connection(&mut self, stream: i32) { + pub fn read_buffer(stream: i32) -> Vec { log::trace!("Reading buffer"); let mut buffer = Vec::::new(); - buffer.resize(daemon_connection::BUFFER_SIZE, 0); + buffer.resize(BUFFER_SIZE, 0); loop { match nix::unistd::read(stream, &mut buffer) { Ok(0) => { break; - }, + } Ok(n) => { assert!(n < buffer.len()); if n < buffer.len() { buffer.resize(n, 0); } break; - }, + } Err(e) => { panic!("Error reading from socket: {}", e); } } } + + buffer + } + + fn handle_connection(&mut self, stream: i32) { + let buffer = Self::read_buffer(stream); + //log::trace!("finished reading, buffer size {}", buffer.len()); log::trace!("Attempting to deserialize {:?}", &buffer); //log::trace!("{:?}", action); @@ -422,8 +436,10 @@ impl Daemon { Action::GetConfig => Ok(DaemonResponse::Config(self.config.clone())), }; - log::trace!("Responding"); - nix::unistd::write(stream, &mut &bincode::serialize(&response).unwrap()).expect("Writing response to socket failed"); + let buffer = bincode::serialize(&response).unwrap(); + + log::trace!("Responding, buffer length {}", buffer.len()); + nix::unistd::write(stream, &buffer).expect("Writing response to socket failed"); //stream // .shutdown(std::net::Shutdown::Write) // .expect("Could not shut down");