Initial multi-gpu support

This commit is contained in:
Ilya Zlobintsev 2020-11-08 09:07:45 +02:00
parent a4a639534c
commit c78f18eaee
10 changed files with 324 additions and 179 deletions

View File

@ -8,4 +8,6 @@ edition = "2018"
[dependencies] [dependencies]
daemon = { path = "../daemon" } daemon = { path = "../daemon" }
structopt = "0.3" structopt = "0.3"
log = "0.4"
env_logger = "0.8"

View File

@ -5,40 +5,58 @@ use structopt::StructOpt;
#[structopt(rename_all = "lower")] #[structopt(rename_all = "lower")]
enum Opt { enum Opt {
///Gets realtime GPU information ///Gets realtime GPU information
Stats, Stats {
Info, gpu_id: u32,
StartFanControl, },
StopFanControl, Gpus,
GetFanControl, Info {
gpu_id: u32,
},
StartFanControl {
gpu_id: u32,
},
StopFanControl {
gpu_id: u32,
},
GetFanControl {
gpu_id: u32,
},
Stop, Stop,
} }
fn main() { fn main() {
env_logger::init();
let opt = Opt::from_args(); let opt = Opt::from_args();
let d = DaemonConnection::new().unwrap(); let d = DaemonConnection::new().unwrap();
log::trace!("connection established");
match opt { match opt {
Opt::Stats => { Opt::Gpus => {
let gpu_stats = d.get_gpu_stats(); let gpus = d.get_gpus();
println!("{:?}", gpus);
},
Opt::Stats { gpu_id } => {
let gpu_stats = d.get_gpu_stats(gpu_id);
println!("VRAM: {}/{}", gpu_stats.mem_used, gpu_stats.mem_total); println!("VRAM: {}/{}", gpu_stats.mem_used, gpu_stats.mem_total);
println!("{:?}", gpu_stats); println!("{:?}", gpu_stats);
}, },
Opt::Info => { Opt::Info { gpu_id } => {
let gpu_info = d.get_gpu_info(); let gpu_info = d.get_gpu_info(gpu_id);
println!("GPU Vendor: {}", gpu_info.gpu_vendor); println!("GPU Vendor: {}", gpu_info.gpu_vendor);
println!("GPU Model: {}", gpu_info.card_model); println!("GPU Model: {}", gpu_info.card_model);
println!("Driver in use: {}", gpu_info.driver); println!("Driver in use: {}", gpu_info.driver);
print!("VBIOS Version: {}", gpu_info.vbios_version); print!("VBIOS Version: {}", gpu_info.vbios_version);
}, },
Opt::StartFanControl => { Opt::StartFanControl { gpu_id } => {
println!("{:?}", d.start_fan_control()); println!("{:?}", d.start_fan_control(gpu_id));
}, },
Opt::StopFanControl => { Opt::StopFanControl { gpu_id } => {
println!("{:?}", d.stop_fan_control()); println!("{:?}", d.stop_fan_control(gpu_id));
}, },
Opt::GetFanControl => { Opt::GetFanControl { gpu_id } => {
println!("{:?}", d.get_fan_control()); println!("{:?}", d.get_fan_control(gpu_id));
}, },
Opt::Stop => d.shutdown(), Opt::Stop => d.shutdown(),
} }

View File

@ -12,4 +12,5 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
vulkano = "0.19" vulkano = "0.19"
log = "0.4" log = "0.4"
env_logger = "0.8" env_logger = "0.8"
rand = "0.7"

View File

@ -1,5 +1,5 @@
use std::{collections::BTreeMap, io, fs, path::PathBuf};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{collections::BTreeMap, fs, io, path::PathBuf};
#[derive(Debug)] #[derive(Debug)]
pub enum ConfigError { pub enum ConfigError {
@ -42,7 +42,7 @@ impl Config {
pub fn read_from_file(path: &PathBuf) -> Result<Self, ConfigError> { pub fn read_from_file(path: &PathBuf) -> Result<Self, ConfigError> {
let json = fs::read_to_string(path)?; let json = fs::read_to_string(path)?;
Ok(serde_json::from_str::<Config>(&json)?) Ok(serde_json::from_str::<Config>(&json)?)
} }
@ -62,4 +62,4 @@ mod tests {
let c = Config::new(); let c = Config::new();
c.save(PathBuf::from("/tmp/config.json")) c.save(PathBuf::from("/tmp/config.json"))
} }
}*/ }*/

View File

@ -1,6 +1,14 @@
use crate::{Action, SOCK_PATH, gpu_controller::GpuInfo, gpu_controller::{FanControlInfo, GpuStats}, hw_mon::HWMonError}; use crate::{
use std::{collections::BTreeMap, io::{Read, Write}}; gpu_controller::GpuInfo,
use std::os::unix::net::UnixStream; gpu_controller::{FanControlInfo, GpuStats},
hw_mon::HWMonError,
Action, SOCK_PATH,
};
use std::{collections::HashMap, os::unix::net::UnixStream};
use std::{
collections::BTreeMap,
io::{Read, Write},
};
#[derive(Debug)] #[derive(Debug)]
pub enum DaemonConnectionError { pub enum DaemonConnectionError {
@ -9,21 +17,26 @@ pub enum DaemonConnectionError {
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct DaemonConnection { pub struct DaemonConnection {}
}
impl DaemonConnection { impl DaemonConnection {
pub fn new() -> Result<Self, DaemonConnectionError> { pub fn new() -> Result<Self, DaemonConnectionError> {
match UnixStream::connect(SOCK_PATH) { match UnixStream::connect(SOCK_PATH) {
Ok(mut stream) => { Ok(mut stream) => {
stream.write(&bincode::serialize(&Action::CheckAlive).unwrap()).unwrap(); stream
let mut buffer = Vec::<u8>::new(); .write(&bincode::serialize(&Action::CheckAlive).unwrap())
stream.read_to_end(&mut buffer).unwrap(); .unwrap();
stream
.shutdown(std::net::Shutdown::Write)
.expect("Could not shut down");
let mut buffer: [u8; 1] = [0; 1];
stream.read(&mut buffer).unwrap();
if buffer[0] == 1 { if buffer[0] == 1 {
Ok(DaemonConnection { }) Ok(DaemonConnection {})
} } else {
else {
Err(DaemonConnectionError::ConnectionFailed) Err(DaemonConnectionError::ConnectionFailed)
} }
} }
@ -31,83 +44,110 @@ impl DaemonConnection {
} }
} }
pub fn get_gpu_stats(&self) -> GpuStats { pub fn get_gpu_stats(&self, gpu_id: u32) -> GpuStats {
let mut stream = UnixStream::connect(SOCK_PATH).expect("Failed to connect to daemon"); let mut s = UnixStream::connect(SOCK_PATH).expect("Failed to connect to daemon");
stream s
.write(&bincode::serialize(&Action::GetStats).unwrap()) .write(&bincode::serialize(&Action::GetStats(gpu_id)).unwrap())
.unwrap();
/*stream
.shutdown(std::net::Shutdown::Write)
.expect("Could not shut down");*/
let mut buffer = Vec::<u8>::new();
stream.read_to_end(&mut buffer).unwrap();
bincode::deserialize(&buffer).unwrap()
}
pub fn get_gpu_info(&self) -> GpuInfo {
let mut s = UnixStream::connect(SOCK_PATH).unwrap();
s.write_all(&bincode::serialize(&Action::GetInfo).unwrap())
.unwrap();
/*s.shutdown(std::net::Shutdown::Write)
.expect("Could not shut down");*/
let mut buffer = Vec::<u8>::new();
s.read_to_end(&mut buffer).unwrap();
bincode::deserialize(&buffer).unwrap()
}
pub fn start_fan_control(&self) -> Result<(), DaemonConnectionError> {
let mut s = UnixStream::connect(SOCK_PATH).unwrap();
s.write_all(&bincode::serialize(&Action::StartFanControl).unwrap())
.unwrap(); .unwrap();
s.shutdown(std::net::Shutdown::Write).expect("Could not shut down");
let mut buffer = Vec::<u8>::new(); let mut buffer = Vec::<u8>::new();
s.read_to_end(&mut buffer).unwrap(); s.read_to_end(&mut buffer).unwrap();
bincode::deserialize(&buffer).unwrap()
}
pub fn get_gpu_info(&self, gpu_id: u32) -> GpuInfo {
let mut s = UnixStream::connect(SOCK_PATH).unwrap();
s.write_all(&bincode::serialize(&Action::GetInfo(gpu_id)).unwrap())
.unwrap();
s.shutdown(std::net::Shutdown::Write)
.expect("Could not shut down");
log::trace!("Sent action, receiving response");
let mut buffer = Vec::<u8>::new();
s.read_to_end(&mut buffer).unwrap();
log::trace!("Response recieved");
bincode::deserialize(&buffer).unwrap()
}
pub fn start_fan_control(&self, gpu_id: u32) -> Result<(), DaemonConnectionError> {
let mut s = UnixStream::connect(SOCK_PATH).unwrap();
s.write_all(&bincode::serialize(&Action::StartFanControl(gpu_id)).unwrap())
.unwrap();
s.shutdown(std::net::Shutdown::Write).expect("Could not shut down");
log::trace!("Sent action, receiving response");
let mut buffer = Vec::<u8>::new();
s.read_to_end(&mut buffer).unwrap();
log::trace!("Response recieved");
let result: Result<(), HWMonError> = bincode::deserialize(&buffer).unwrap(); let result: Result<(), HWMonError> = bincode::deserialize(&buffer).unwrap();
match result { match result {
Ok(_) => Ok(()), Ok(_) => Ok(()),
Err(_) => Err(DaemonConnectionError::PermissionDenied), Err(_) => Err(DaemonConnectionError::PermissionDenied),
} }
} }
pub fn stop_fan_control(&self) -> Result<(), DaemonConnectionError> { pub fn stop_fan_control(&self, gpu_id: u32) -> Result<(), DaemonConnectionError> {
let mut s = UnixStream::connect(SOCK_PATH).unwrap(); let mut s = UnixStream::connect(SOCK_PATH).unwrap();
s.write_all(&bincode::serialize(&Action::StopFanControl).unwrap()).unwrap(); s.write_all(&bincode::serialize(&Action::StopFanControl(gpu_id)).unwrap())
.unwrap();
s.shutdown(std::net::Shutdown::Write).expect("Could not shut down");
let mut buffer = Vec::<u8>::new(); let mut buffer = Vec::<u8>::new();
s.read_to_end(&mut buffer).unwrap(); s.read_to_end(&mut buffer).unwrap();
let result: Result<(), HWMonError> = bincode::deserialize(&buffer).unwrap(); let result: Result<(), HWMonError> = bincode::deserialize(&buffer).unwrap();
match result { match result {
Ok(_) => Ok(()), Ok(_) => Ok(()),
Err(_) => Err(DaemonConnectionError::PermissionDenied), Err(_) => Err(DaemonConnectionError::PermissionDenied),
} }
} }
pub fn get_fan_control(&self)-> FanControlInfo { pub fn get_fan_control(&self, gpu_id: u32) -> FanControlInfo {
let mut s = UnixStream::connect(SOCK_PATH).unwrap(); let mut s = UnixStream::connect(SOCK_PATH).unwrap();
s.write_all(&bincode::serialize(&Action::GetFanControl).unwrap()).unwrap(); s.write_all(&bincode::serialize(&Action::GetFanControl(gpu_id)).unwrap())
.unwrap();
s.shutdown(std::net::Shutdown::Write).expect("Could not shut down");
let mut buffer = Vec::<u8>::new(); let mut buffer = Vec::<u8>::new();
s.read_to_end(&mut buffer).unwrap(); s.read_to_end(&mut buffer).unwrap();
bincode::deserialize(&buffer).unwrap() bincode::deserialize(&buffer).unwrap()
} }
pub fn set_fan_curve(&self, curve: BTreeMap<i32, f64>) { pub fn set_fan_curve(&self, gpu_id: u32, curve: BTreeMap<i32, f64>) {
let mut s = UnixStream::connect(SOCK_PATH).unwrap(); let mut s = UnixStream::connect(SOCK_PATH).unwrap();
s.write_all(&bincode::serialize(&Action::SetFanCurve).unwrap()).unwrap(); s.write_all(&bincode::serialize(&Action::SetFanCurve(gpu_id)).unwrap())
.unwrap();
s.shutdown(std::net::Shutdown::Write).expect("Could not shut down");
s.write_all(&bincode::serialize(&curve).unwrap()).unwrap(); s.write_all(&bincode::serialize(&curve).unwrap()).unwrap();
} }
pub fn get_gpus(&self) -> HashMap<u32, String> {
log::trace!("sending request");
let mut s = UnixStream::connect(SOCK_PATH).unwrap();
s.write_all(&bincode::serialize(&Action::GetGpus).unwrap())
.unwrap();
s.shutdown(std::net::Shutdown::Write).expect("Could not shut down");
log::trace!("sent request");
let mut buffer = Vec::<u8>::new();
s.read_to_end(&mut buffer).unwrap();
log::trace!("read response");
bincode::deserialize(&buffer).unwrap()
}
pub fn shutdown(&self) { pub fn shutdown(&self) {
let mut s = UnixStream::connect(SOCK_PATH).unwrap(); let mut s = UnixStream::connect(SOCK_PATH).unwrap();
s.write_all(&bincode::serialize(&Action::Shutdown).unwrap()).unwrap(); s.write_all(&bincode::serialize(&Action::Shutdown).unwrap())
.unwrap();
} }
} }

View File

@ -1,9 +1,9 @@
use crate::config::Config;
use crate::hw_mon::{HWMon, HWMonError}; use crate::hw_mon::{HWMon, HWMonError};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{collections::BTreeMap, fs};
use std::path::PathBuf; use std::path::PathBuf;
use std::{collections::BTreeMap, fs};
use vulkano::instance::{Instance, InstanceExtensions, PhysicalDevice}; use vulkano::instance::{Instance, InstanceExtensions, PhysicalDevice};
use crate::config::Config;
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct GpuStats { pub struct GpuStats {
@ -58,9 +58,18 @@ pub struct GpuInfo {
impl GpuController { impl GpuController {
pub fn new(hw_path: PathBuf, config: Config, config_path: PathBuf) -> Self { pub fn new(hw_path: PathBuf, config: Config, config_path: PathBuf) -> Self {
let hwmon_path = fs::read_dir(&hw_path.join("hwmon")).unwrap().next().unwrap().unwrap().path(); let hwmon_path = fs::read_dir(&hw_path.join("hwmon"))
.unwrap()
.next()
.unwrap()
.unwrap()
.path();
let hw_mon = HWMon::new(&hwmon_path, config.fan_control_enabled, config.fan_curve.clone()); let hw_mon = HWMon::new(
&hwmon_path,
config.fan_control_enabled,
config.fan_curve.clone(),
);
let mut controller = GpuController { let mut controller = GpuController {
hw_path: hw_path.clone(), hw_path: hw_path.clone(),
@ -118,7 +127,12 @@ impl GpuController {
card_model_id.to_lowercase() card_model_id.to_lowercase()
); );
for line in full_hwid_list.split('\n') { let lines: Vec<&str> = full_hwid_list.split('\n').collect();
//for line in full_hwid_list.split('\n') {
for i in 0..lines.len() {
let line = lines[i];
if line.len() > card_vendor_id.len() { if line.len() > card_vendor_id.len() {
if line[0..card_vendor_id.len()] == card_vendor_id.to_lowercase() { if line[0..card_vendor_id.len()] == card_vendor_id.to_lowercase() {
card_vendor = line.splitn(2, ' ').collect::<Vec<&str>>()[1] card_vendor = line.splitn(2, ' ').collect::<Vec<&str>>()[1]
@ -138,8 +152,8 @@ impl GpuController {
Ok(v) => v, Ok(v) => v,
Err(_) => "".to_string(), Err(_) => "".to_string(),
} }
.trim() .trim()
.to_string(); .to_string();
let vram_size = match fs::read_to_string(self.hw_path.join("mem_info_vram_total")) { let vram_size = match fs::read_to_string(self.hw_path.join("mem_info_vram_total")) {
Ok(a) => a.trim().parse::<u64>().unwrap() / 1024 / 1024, Ok(a) => a.trim().parse::<u64>().unwrap() / 1024 / 1024,
@ -156,7 +170,6 @@ impl GpuController {
Err(_) => 0, Err(_) => 0,
}; };
let vulkan_info = GpuController::get_vulkan_info(&model_id); let vulkan_info = GpuController::get_vulkan_info(&model_id);
let max_fan_speed = self.hw_mon.fan_max_speed; let max_fan_speed = self.hw_mon.fan_max_speed;
@ -214,9 +227,11 @@ impl GpuController {
match self.hw_mon.start_fan_control() { match self.hw_mon.start_fan_control() {
Ok(_) => { Ok(_) => {
self.config.fan_control_enabled = true; self.config.fan_control_enabled = true;
self.config.save(&self.config_path).expect("Failed to save config"); self.config
.save(&self.config_path)
.expect("Failed to save config");
Ok(()) Ok(())
}, }
Err(e) => Err(e), Err(e) => Err(e),
} }
} }
@ -225,9 +240,11 @@ impl GpuController {
match self.hw_mon.stop_fan_control() { match self.hw_mon.stop_fan_control() {
Ok(_) => { Ok(_) => {
self.config.fan_control_enabled = false; self.config.fan_control_enabled = false;
self.config.save(&self.config_path).expect("Failed to save config"); self.config
.save(&self.config_path)
.expect("Failed to save config");
Ok(()) Ok(())
}, }
Err(e) => Err(e), Err(e) => Err(e),
} }
} }
@ -244,7 +261,9 @@ impl GpuController {
pub fn set_fan_curve(&mut self, curve: BTreeMap<i32, f64>) { pub fn set_fan_curve(&mut self, curve: BTreeMap<i32, f64>) {
self.hw_mon.set_fan_curve(curve.clone()); self.hw_mon.set_fan_curve(curve.clone());
self.config.fan_curve = curve; self.config.fan_curve = curve;
self.config.save(&self.config_path).expect("Failed to save config"); self.config
.save(&self.config_path)
.expect("Failed to save config");
} }
fn get_vulkan_info(pci_id: &str) -> VulkanInfo { fn get_vulkan_info(pci_id: &str) -> VulkanInfo {

View File

@ -26,12 +26,15 @@ pub struct HWMon {
} }
impl HWMon { impl HWMon {
pub fn new(hwmon_path: &PathBuf, fan_control_enabled: bool, fan_curve: BTreeMap<i32, f64>) -> HWMon { pub fn new(
let fan_max_speed = fs::read_to_string(hwmon_path.join("fan1_max")) hwmon_path: &PathBuf,
.unwrap() fan_control_enabled: bool,
.trim() fan_curve: BTreeMap<i32, f64>,
.parse::<i32>() ) -> HWMon {
.unwrap(); let fan_max_speed = match fs::read_to_string(hwmon_path.join("fan1_max")) {
Ok(s) => s.trim().parse::<i32>().unwrap(),
Err(_) => 0,
};
let mon = HWMon { let mon = HWMon {
hwmon_path: hwmon_path.clone(), hwmon_path: hwmon_path.clone(),
@ -43,7 +46,7 @@ impl HWMon {
if fan_control_enabled { if fan_control_enabled {
mon.start_fan_control().unwrap(); mon.start_fan_control().unwrap();
} }
mon mon
} }

View File

@ -1,38 +1,44 @@
pub mod config;
pub mod daemon_connection;
pub mod gpu_controller; pub mod gpu_controller;
pub mod hw_mon; pub mod hw_mon;
pub mod daemon_connection;
pub mod config;
use std::{io::{Read, Write}, path::PathBuf, thread};
use config::Config; use config::Config;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::fs; use std::{collections::HashMap, fs};
use std::os::unix::net::{UnixListener, UnixStream}; use std::os::unix::net::{UnixListener, UnixStream};
use std::process::Command; use std::process::Command;
use std::{
io::{Read, Write},
path::PathBuf,
thread,
};
use rand::prelude::*;
use crate::gpu_controller::GpuController; use crate::gpu_controller::GpuController;
pub const SOCK_PATH: &str = "/tmp/amdgpu-configurator.sock"; pub const SOCK_PATH: &str = "/tmp/amdgpu-configurator.sock";
pub struct Daemon { pub struct Daemon {
gpu_controller: GpuController, gpu_controllers: HashMap<u32, GpuController>,
listener: UnixListener, listener: UnixListener,
} }
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub enum Action { pub enum Action {
CheckAlive, CheckAlive,
GetInfo, GetGpus,
GetStats, GetInfo(u32),
StartFanControl, GetStats(u32),
StopFanControl, StartFanControl(u32),
GetFanControl, StopFanControl(u32),
SetFanCurve, GetFanControl(u32),
SetFanCurve(u32),
Shutdown, Shutdown,
} }
impl Daemon { impl Daemon {
pub fn new() -> Daemon { pub fn new(unpriveleged: bool) -> Daemon {
if fs::metadata(SOCK_PATH).is_ok() { if fs::metadata(SOCK_PATH).is_ok() {
fs::remove_file(SOCK_PATH).expect("Failed to take control over socket"); fs::remove_file(SOCK_PATH).expect("Failed to take control over socket");
} }
@ -46,19 +52,43 @@ impl Daemon {
.expect("Failed to chmod"); .expect("Failed to chmod");
let config_path = PathBuf::from("/etc/lact.json"); let config_path = PathBuf::from("/etc/lact.json");
let config = match Config::read_from_file(&config_path) { let config = if unpriveleged {
Ok(c) => c, Config::new()
Err(_) => { } else {
let c = Config::new(); match Config::read_from_file(&config_path) {
c.save(&config_path).expect("Failed to save config"); Ok(c) => c,
c Err(_) => {
let c = Config::new();
c.save(&config_path).expect("Failed to save config");
c
}
} }
}; };
log::trace!("Using config {:?}", config); log::trace!("Using config {:?}", config);
let gpu_controller = GpuController::new(PathBuf::from("/sys/class/drm/card0/device"), config, config_path); let mut gpu_controllers: HashMap<u32, GpuController> = HashMap::new();
Daemon { listener, gpu_controller } for entry in fs::read_dir("/sys/class/drm").expect("Could not open /sys/class/drm") {
let entry = entry.unwrap();
if entry.file_name().len() == 5 {
if entry.file_name().to_str().unwrap().split_at(4).0 == "card" {
log::info!("Initializing {:?}", entry.path());
loop {
let id: u32 = random();
if !gpu_controllers.contains_key(&id) {
gpu_controllers.insert(id, GpuController::new(entry.path().join("device"), config.clone(), config_path.clone()));
break;
}
}
}
}
}
Daemon {
listener,
gpu_controllers,
}
} }
pub fn listen(mut self) { pub fn listen(mut self) {
@ -67,7 +97,7 @@ impl Daemon {
Ok(stream) => { Ok(stream) => {
//let mut controller = self.gpu_controller.clone(); //let mut controller = self.gpu_controller.clone();
//thread::spawn(move || Daemon::handle_connection(&mut controller, stream)); //thread::spawn(move || Daemon::handle_connection(&mut controller, stream));
Daemon::handle_connection(&mut self.gpu_controller, stream); Daemon::handle_connection(&mut self.gpu_controllers, stream);
} }
Err(err) => { Err(err) => {
log::error!("Error: {}", err); log::error!("Error: {}", err);
@ -77,41 +107,68 @@ impl Daemon {
} }
} }
fn handle_connection(gpu_controller: &mut GpuController, mut stream: UnixStream) { fn handle_connection(gpu_controllers: &mut HashMap<u32, GpuController>, mut stream: UnixStream) {
let mut buffer: [u8; 4] = [0; 4]; log::trace!("Reading buffer");
stream.read(&mut buffer).unwrap(); let mut buffer = Vec::<u8>::new();
stream.read_to_end(&mut buffer).unwrap();
//log::trace!("finished reading, buffer size {}", buffer.len()); //log::trace!("finished reading, buffer size {}", buffer.len());
log::trace!("Attempting to deserialize {:?}", &buffer);
let action: Action = bincode::deserialize(&buffer).expect("Failed to deserialize buffer"); let action: Action = bincode::deserialize(&buffer).expect("Failed to deserialize buffer");
//log::trace!("{:?}", action); //log::trace!("{:?}", action);
log::trace!("Executing action {:?}", action);
let response: Option<Vec<u8>> = match action { let response: Option<Vec<u8>> = match action {
Action::GetStats => Some(bincode::serialize(&gpu_controller.get_stats()).unwrap()), Action::CheckAlive => Some(vec![1]),
Action::GetInfo => Some(bincode::serialize(&gpu_controller.gpu_info).unwrap()), Action::GetGpus => {
Action::StartFanControl => Some(bincode::serialize(&gpu_controller.start_fan_control()).unwrap()), let mut gpus: HashMap<u32, String> = HashMap::new();
Action::StopFanControl => Some(bincode::serialize(&gpu_controller.stop_fan_control()).unwrap()), for controller in gpu_controllers {
Action::GetFanControl => Some(bincode::serialize(&gpu_controller.get_fan_control()).unwrap()), gpus.insert(*controller.0, controller.1.gpu_info.gpu_model.clone());
Action::SetFanCurve => { }
Some(bincode::serialize(&gpus).unwrap())
},
Action::GetStats(i) => match gpu_controllers.get(&i) {
Some(controller) => Some(bincode::serialize(&controller.get_stats()).unwrap()),
_ => None,
},
Action::GetInfo(i) => match gpu_controllers.get(&i) {
Some(controller) => Some(bincode::serialize(&controller.gpu_info).unwrap()),
_ => None,
},
Action::StartFanControl(i) => match gpu_controllers.get_mut(&i) {
Some(controller) => Some(bincode::serialize(&controller.start_fan_control()).unwrap()),
_ => None,
},
Action::StopFanControl(i) => match gpu_controllers.get_mut(&i) {
Some(controller) => Some(bincode::serialize(&controller.stop_fan_control()).unwrap()),
_ => None,
},
Action::GetFanControl(i) => match gpu_controllers.get(&i) {
Some(controller) => Some(bincode::serialize(&controller.get_fan_control()).unwrap()),
_ => None,
}
Action::SetFanCurve(i) => {
let mut buffer = Vec::new(); let mut buffer = Vec::new();
stream.read_to_end(&mut buffer).unwrap(); stream.read_to_end(&mut buffer).unwrap();
gpu_controller.set_fan_curve(bincode::deserialize(&buffer).expect("Failed to deserialize curve")); gpu_controllers.get_mut(&i).unwrap().set_fan_curve(
bincode::deserialize(&buffer).expect("Failed to deserialize curve"),
);
None None
}, }
Action::CheckAlive => Some(vec![1]),
Action::Shutdown => std::process::exit(0), Action::Shutdown => std::process::exit(0),
}; };
if let Some(r) = &response { if let Some(r) = &response {
stream log::trace!("Responding");
.write_all(&r) stream.write_all(&r).expect("Failed writing response");
.expect("Failed writing response"); //stream
// .shutdown(std::net::Shutdown::Write)
// .expect("Could not shut down");
log::trace!("Finished responding");
} }
} }
} }
#[derive(Debug)] #[derive(Debug)]
pub enum DaemonError { pub enum DaemonError {
ConnectionFailed, ConnectionFailed,
} }

View File

@ -2,6 +2,6 @@ use daemon::Daemon;
fn main() { fn main() {
env_logger::init(); env_logger::init();
let d = Daemon::new(); let d = Daemon::new(false);
d.listen(); d.listen();
} }

View File

@ -2,13 +2,22 @@ extern crate gdk;
extern crate gio; extern crate gio;
extern crate gtk; extern crate gtk;
use daemon::{Daemon, daemon_connection::DaemonConnection}; use daemon::{daemon_connection::DaemonConnection, Daemon};
use gio::prelude::*; use gio::prelude::*;
use gtk::{Adjustment, Button, ButtonsType, DialogFlags, Frame, Label, LevelBar, MessageType, Switch, prelude::*}; use gtk::{
prelude::*, Adjustment, Button, ButtonsType, DialogFlags, Frame, Label, LevelBar, MessageType,
Switch,
};
use gtk::{Builder, MessageDialog, TextBuffer, Window}; use gtk::{Builder, MessageDialog, TextBuffer, Window};
use std::{collections::BTreeMap, env::args, sync::{Arc, RwLock}, thread, time::Duration}; use std::{
collections::BTreeMap,
env::args,
sync::{Arc, RwLock},
thread,
time::Duration,
};
fn build_ui(application: &gtk::Application) { fn build_ui(application: &gtk::Application) {
let glade_src = include_str!("main_window.glade"); let glade_src = include_str!("main_window.glade");
@ -62,31 +71,23 @@ fn build_ui(application: &gtk::Application) {
let vram_usage_label: Label = builder let vram_usage_label: Label = builder
.get_object("vram_usage_label") .get_object("vram_usage_label")
.expect("Couldn't get label"); .expect("Couldn't get label");
let gpu_clock_text_buffer: TextBuffer = builder
.get_object("gpu_clock_text_buffer").unwrap();
let vram_clock_text_buffer: TextBuffer = builder let gpu_clock_text_buffer: TextBuffer = builder.get_object("gpu_clock_text_buffer").unwrap();
.get_object("vram_clock_text_buffer").unwrap();
let gpu_temp_text_buffer: TextBuffer = builder let vram_clock_text_buffer: TextBuffer = builder.get_object("vram_clock_text_buffer").unwrap();
.get_object("gpu_temp_text_buffer").unwrap();
let gpu_power_text_buffer: TextBuffer = builder let gpu_temp_text_buffer: TextBuffer = builder.get_object("gpu_temp_text_buffer").unwrap();
.get_object("gpu_power_text_buffer").unwrap();
let fan_speed_text_buffer: TextBuffer = builder let gpu_power_text_buffer: TextBuffer = builder.get_object("gpu_power_text_buffer").unwrap();
.get_object("fan_speed_text_buffer").unwrap();
let automatic_fan_control_switch: Switch = builder let fan_speed_text_buffer: TextBuffer = builder.get_object("fan_speed_text_buffer").unwrap();
.get_object("automatic_fan_control_switch").unwrap();
let apply_button: Button = builder let automatic_fan_control_switch: Switch =
.get_object("apply_button").unwrap(); builder.get_object("automatic_fan_control_switch").unwrap();
let fan_curve_frame: Frame = builder let apply_button: Button = builder.get_object("apply_button").unwrap();
.get_object("fan_curve_frame").unwrap();
let fan_curve_frame: Frame = builder.get_object("fan_curve_frame").unwrap();
let mut unpriviliged: bool = false; let mut unpriviliged: bool = false;
@ -95,7 +96,7 @@ fn build_ui(application: &gtk::Application) {
Err(_) => { Err(_) => {
unpriviliged = true; unpriviliged = true;
let daemon = Daemon::new(); let daemon = Daemon::new(unpriviliged);
thread::spawn(move || { thread::spawn(move || {
daemon.listen(); daemon.listen();
}); });
@ -139,20 +140,17 @@ fn build_ui(application: &gtk::Application) {
let (tx, rx) = glib::MainContext::channel(glib::PRIORITY_DEFAULT); let (tx, rx) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
thread::spawn(move || { thread::spawn(move || loop {
loop { let gpu_stats = d.get_gpu_stats();
let gpu_stats = d.get_gpu_stats();
tx.send(gpu_stats).expect("Couldn't send text"); tx.send(gpu_stats).expect("Couldn't send text");
thread::sleep(Duration::from_millis(500)); thread::sleep(Duration::from_millis(500));
}
}); });
rx.attach(None, move |gpu_stats| { rx.attach(None, move |gpu_stats| {
vram_usage_level_bar.set_max_value(gpu_stats.mem_total as f64); vram_usage_level_bar.set_max_value(gpu_stats.mem_total as f64);
vram_usage_level_bar.set_value(gpu_stats.mem_used as f64); vram_usage_level_bar.set_value(gpu_stats.mem_used as f64);
let text = format!("{}/{} MiB", gpu_stats.mem_used, gpu_stats.mem_total); let text = format!("{}/{} MiB", gpu_stats.mem_used, gpu_stats.mem_total);
vram_usage_label.set_text(&text); vram_usage_label.set_text(&text);
@ -161,9 +159,14 @@ fn build_ui(application: &gtk::Application) {
gpu_temp_text_buffer.set_text(&format!("{}°C", gpu_stats.gpu_temp)); 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)); gpu_power_text_buffer
.set_text(&format!("{}/{}W", gpu_stats.power_avg, gpu_stats.power_max));
fan_speed_text_buffer.set_text(&format!("{}RPM({}%)", gpu_stats.fan_speed, (gpu_stats.fan_speed as f64 / gpu_info.max_fan_speed as f64 * 100 as f64) as i32)); fan_speed_text_buffer.set_text(&format!(
"{}RPM({}%)",
gpu_stats.fan_speed,
(gpu_stats.fan_speed as f64 / gpu_info.max_fan_speed as f64 * 100 as f64) as i32
));
glib::Continue(true) glib::Continue(true)
}); });
@ -174,8 +177,7 @@ fn build_ui(application: &gtk::Application) {
println!("Automatic fan control disabled!"); println!("Automatic fan control disabled!");
automatic_fan_control_switch.set_active(false); automatic_fan_control_switch.set_active(false);
fan_curve_frame.set_visible(true); fan_curve_frame.set_visible(true);
} } else {
else {
println!("Automatic fan control enabled"); println!("Automatic fan control enabled");
fan_curve_frame.set_visible(false); fan_curve_frame.set_visible(false);
} }
@ -187,8 +189,8 @@ fn build_ui(application: &gtk::Application) {
match switch.get_active() { match switch.get_active() {
true => { true => {
fan_curve_frame.set_visible(false); fan_curve_frame.set_visible(false);
}, }
false => { false => {
fan_curve_frame.set_visible(true); fan_curve_frame.set_visible(true);
} }
} }
@ -200,20 +202,24 @@ fn build_ui(application: &gtk::Application) {
for i in 1..6 { for i in 1..6 {
let curve_temperature_adjustment: Adjustment = builder let curve_temperature_adjustment: Adjustment = builder
.get_object(&format!("curve_temperature_adjustment_{}", i)).unwrap(); .get_object(&format!("curve_temperature_adjustment_{}", i))
.unwrap();
let value = *curve.read().unwrap().get(&(i * 20)).expect("Could not get by index"); let value = *curve
.read()
.unwrap()
.get(&(i * 20))
.expect("Could not get by index");
println!("Setting value {} on adjustment {}", value, i); println!("Setting value {} on adjustment {}", value, i);
curve_temperature_adjustment.set_value(value); curve_temperature_adjustment.set_value(value);
let c = curve.clone(); let c = curve.clone();
let b = apply_button.clone(); let b = apply_button.clone();
curve_temperature_adjustment.connect_value_changed(move |adj | { curve_temperature_adjustment.connect_value_changed(move |adj| {
c.write().unwrap().insert(20 * i, adj.get_value()); c.write().unwrap().insert(20 * i, adj.get_value());
b.set_sensitive(true); b.set_sensitive(true);
}); });
} }
apply_button.connect_clicked(move |b| { apply_button.connect_clicked(move |b| {
@ -225,8 +231,8 @@ fn build_ui(application: &gtk::Application) {
match automatic_fan_control_switch.get_active() { match automatic_fan_control_switch.get_active() {
true => { true => {
d.stop_fan_control().unwrap(); d.stop_fan_control().unwrap();
}, }
false => { false => {
d.start_fan_control().unwrap(); d.start_fan_control().unwrap();
} }
} }
@ -237,7 +243,6 @@ fn build_ui(application: &gtk::Application) {
main_window.show(); main_window.show();
} }
fn main() { fn main() {
println!("Initializing gtk"); println!("Initializing gtk");
let application = gtk::Application::new(Some("com.ilyaz.yagc"), Default::default()) let application = gtk::Application::new(Some("com.ilyaz.yagc"), Default::default())