mirror of
https://github.com/ilya-zlobintsev/LACT.git
synced 2025-02-25 18:55:26 -06:00
Initial multi-gpu support
This commit is contained in:
parent
a4a639534c
commit
c78f18eaee
@ -8,4 +8,6 @@ edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
daemon = { path = "../daemon" }
|
||||
structopt = "0.3"
|
||||
structopt = "0.3"
|
||||
log = "0.4"
|
||||
env_logger = "0.8"
|
@ -5,40 +5,58 @@ use structopt::StructOpt;
|
||||
#[structopt(rename_all = "lower")]
|
||||
enum Opt {
|
||||
///Gets realtime GPU information
|
||||
Stats,
|
||||
Info,
|
||||
StartFanControl,
|
||||
StopFanControl,
|
||||
GetFanControl,
|
||||
Stats {
|
||||
gpu_id: u32,
|
||||
},
|
||||
Gpus,
|
||||
Info {
|
||||
gpu_id: u32,
|
||||
},
|
||||
StartFanControl {
|
||||
gpu_id: u32,
|
||||
},
|
||||
StopFanControl {
|
||||
gpu_id: u32,
|
||||
},
|
||||
GetFanControl {
|
||||
gpu_id: u32,
|
||||
},
|
||||
Stop,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
env_logger::init();
|
||||
|
||||
let opt = Opt::from_args();
|
||||
|
||||
let d = DaemonConnection::new().unwrap();
|
||||
log::trace!("connection established");
|
||||
|
||||
match opt {
|
||||
Opt::Stats => {
|
||||
let gpu_stats = d.get_gpu_stats();
|
||||
Opt::Gpus => {
|
||||
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!("{:?}", gpu_stats);
|
||||
},
|
||||
Opt::Info => {
|
||||
let gpu_info = d.get_gpu_info();
|
||||
Opt::Info { gpu_id } => {
|
||||
let gpu_info = d.get_gpu_info(gpu_id);
|
||||
println!("GPU Vendor: {}", gpu_info.gpu_vendor);
|
||||
println!("GPU Model: {}", gpu_info.card_model);
|
||||
println!("Driver in use: {}", gpu_info.driver);
|
||||
print!("VBIOS Version: {}", gpu_info.vbios_version);
|
||||
},
|
||||
Opt::StartFanControl => {
|
||||
println!("{:?}", d.start_fan_control());
|
||||
Opt::StartFanControl { gpu_id } => {
|
||||
println!("{:?}", d.start_fan_control(gpu_id));
|
||||
},
|
||||
Opt::StopFanControl => {
|
||||
println!("{:?}", d.stop_fan_control());
|
||||
Opt::StopFanControl { gpu_id } => {
|
||||
println!("{:?}", d.stop_fan_control(gpu_id));
|
||||
},
|
||||
Opt::GetFanControl => {
|
||||
println!("{:?}", d.get_fan_control());
|
||||
Opt::GetFanControl { gpu_id } => {
|
||||
println!("{:?}", d.get_fan_control(gpu_id));
|
||||
},
|
||||
Opt::Stop => d.shutdown(),
|
||||
}
|
||||
|
@ -12,4 +12,5 @@ serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
vulkano = "0.19"
|
||||
log = "0.4"
|
||||
env_logger = "0.8"
|
||||
env_logger = "0.8"
|
||||
rand = "0.7"
|
@ -1,5 +1,5 @@
|
||||
use std::{collections::BTreeMap, io, fs, path::PathBuf};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{collections::BTreeMap, fs, io, path::PathBuf};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ConfigError {
|
||||
@ -42,7 +42,7 @@ impl Config {
|
||||
|
||||
pub fn read_from_file(path: &PathBuf) -> Result<Self, ConfigError> {
|
||||
let json = fs::read_to_string(path)?;
|
||||
|
||||
|
||||
Ok(serde_json::from_str::<Config>(&json)?)
|
||||
}
|
||||
|
||||
@ -62,4 +62,4 @@ mod tests {
|
||||
let c = Config::new();
|
||||
c.save(PathBuf::from("/tmp/config.json"))
|
||||
}
|
||||
}*/
|
||||
}*/
|
||||
|
@ -1,6 +1,14 @@
|
||||
use crate::{Action, SOCK_PATH, gpu_controller::GpuInfo, gpu_controller::{FanControlInfo, GpuStats}, hw_mon::HWMonError};
|
||||
use std::{collections::BTreeMap, io::{Read, Write}};
|
||||
use std::os::unix::net::UnixStream;
|
||||
use crate::{
|
||||
gpu_controller::GpuInfo,
|
||||
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)]
|
||||
pub enum DaemonConnectionError {
|
||||
@ -9,21 +17,26 @@ pub enum DaemonConnectionError {
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct DaemonConnection {
|
||||
}
|
||||
pub struct DaemonConnection {}
|
||||
|
||||
impl DaemonConnection {
|
||||
pub fn new() -> Result<Self, DaemonConnectionError> {
|
||||
match UnixStream::connect(SOCK_PATH) {
|
||||
Ok(mut stream) => {
|
||||
stream.write(&bincode::serialize(&Action::CheckAlive).unwrap()).unwrap();
|
||||
let mut buffer = Vec::<u8>::new();
|
||||
stream.read_to_end(&mut buffer).unwrap();
|
||||
|
||||
Ok(mut stream) => {
|
||||
stream
|
||||
.write(&bincode::serialize(&Action::CheckAlive).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 {
|
||||
Ok(DaemonConnection { })
|
||||
}
|
||||
else {
|
||||
Ok(DaemonConnection {})
|
||||
} else {
|
||||
Err(DaemonConnectionError::ConnectionFailed)
|
||||
}
|
||||
}
|
||||
@ -31,83 +44,110 @@ impl DaemonConnection {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_gpu_stats(&self) -> GpuStats {
|
||||
let mut stream = UnixStream::connect(SOCK_PATH).expect("Failed to connect to daemon");
|
||||
stream
|
||||
.write(&bincode::serialize(&Action::GetStats).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())
|
||||
pub fn get_gpu_stats(&self, gpu_id: u32) -> GpuStats {
|
||||
let mut s = UnixStream::connect(SOCK_PATH).expect("Failed to connect to daemon");
|
||||
s
|
||||
.write(&bincode::serialize(&Action::GetStats(gpu_id)).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 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();
|
||||
|
||||
|
||||
match result {
|
||||
Ok(_) => Ok(()),
|
||||
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();
|
||||
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();
|
||||
s.read_to_end(&mut buffer).unwrap();
|
||||
|
||||
let result: Result<(), HWMonError> = bincode::deserialize(&buffer).unwrap();
|
||||
|
||||
|
||||
match result {
|
||||
Ok(_) => Ok(()),
|
||||
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();
|
||||
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();
|
||||
s.read_to_end(&mut 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();
|
||||
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();
|
||||
}
|
||||
|
||||
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) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
use crate::config::Config;
|
||||
use crate::hw_mon::{HWMon, HWMonError};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{collections::BTreeMap, fs};
|
||||
use std::path::PathBuf;
|
||||
use std::{collections::BTreeMap, fs};
|
||||
use vulkano::instance::{Instance, InstanceExtensions, PhysicalDevice};
|
||||
use crate::config::Config;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct GpuStats {
|
||||
@ -58,9 +58,18 @@ pub struct GpuInfo {
|
||||
|
||||
impl GpuController {
|
||||
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 {
|
||||
hw_path: hw_path.clone(),
|
||||
@ -118,7 +127,12 @@ impl GpuController {
|
||||
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[0..card_vendor_id.len()] == card_vendor_id.to_lowercase() {
|
||||
card_vendor = line.splitn(2, ' ').collect::<Vec<&str>>()[1]
|
||||
@ -138,8 +152,8 @@ impl GpuController {
|
||||
Ok(v) => v,
|
||||
Err(_) => "".to_string(),
|
||||
}
|
||||
.trim()
|
||||
.to_string();
|
||||
.trim()
|
||||
.to_string();
|
||||
|
||||
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,
|
||||
@ -156,7 +170,6 @@ impl GpuController {
|
||||
Err(_) => 0,
|
||||
};
|
||||
|
||||
|
||||
let vulkan_info = GpuController::get_vulkan_info(&model_id);
|
||||
let max_fan_speed = self.hw_mon.fan_max_speed;
|
||||
|
||||
@ -214,9 +227,11 @@ impl GpuController {
|
||||
match self.hw_mon.start_fan_control() {
|
||||
Ok(_) => {
|
||||
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(())
|
||||
},
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
@ -225,9 +240,11 @@ impl GpuController {
|
||||
match self.hw_mon.stop_fan_control() {
|
||||
Ok(_) => {
|
||||
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(())
|
||||
},
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
@ -244,7 +261,9 @@ impl GpuController {
|
||||
pub fn set_fan_curve(&mut self, curve: BTreeMap<i32, f64>) {
|
||||
self.hw_mon.set_fan_curve(curve.clone());
|
||||
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 {
|
||||
|
@ -26,12 +26,15 @@ pub struct HWMon {
|
||||
}
|
||||
|
||||
impl HWMon {
|
||||
pub fn new(hwmon_path: &PathBuf, fan_control_enabled: bool, fan_curve: BTreeMap<i32, f64>) -> HWMon {
|
||||
let fan_max_speed = fs::read_to_string(hwmon_path.join("fan1_max"))
|
||||
.unwrap()
|
||||
.trim()
|
||||
.parse::<i32>()
|
||||
.unwrap();
|
||||
pub fn new(
|
||||
hwmon_path: &PathBuf,
|
||||
fan_control_enabled: bool,
|
||||
fan_curve: BTreeMap<i32, f64>,
|
||||
) -> HWMon {
|
||||
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 {
|
||||
hwmon_path: hwmon_path.clone(),
|
||||
@ -43,7 +46,7 @@ impl HWMon {
|
||||
if fan_control_enabled {
|
||||
mon.start_fan_control().unwrap();
|
||||
}
|
||||
|
||||
|
||||
mon
|
||||
}
|
||||
|
||||
|
@ -1,38 +1,44 @@
|
||||
pub mod config;
|
||||
pub mod daemon_connection;
|
||||
pub mod gpu_controller;
|
||||
pub mod hw_mon;
|
||||
pub mod daemon_connection;
|
||||
pub mod config;
|
||||
|
||||
use std::{io::{Read, Write}, path::PathBuf, thread};
|
||||
use config::Config;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fs;
|
||||
use std::{collections::HashMap, fs};
|
||||
use std::os::unix::net::{UnixListener, UnixStream};
|
||||
use std::process::Command;
|
||||
use std::{
|
||||
io::{Read, Write},
|
||||
path::PathBuf,
|
||||
thread,
|
||||
};
|
||||
use rand::prelude::*;
|
||||
|
||||
use crate::gpu_controller::GpuController;
|
||||
|
||||
pub const SOCK_PATH: &str = "/tmp/amdgpu-configurator.sock";
|
||||
|
||||
pub struct Daemon {
|
||||
gpu_controller: GpuController,
|
||||
gpu_controllers: HashMap<u32, GpuController>,
|
||||
listener: UnixListener,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub enum Action {
|
||||
CheckAlive,
|
||||
GetInfo,
|
||||
GetStats,
|
||||
StartFanControl,
|
||||
StopFanControl,
|
||||
GetFanControl,
|
||||
SetFanCurve,
|
||||
GetGpus,
|
||||
GetInfo(u32),
|
||||
GetStats(u32),
|
||||
StartFanControl(u32),
|
||||
StopFanControl(u32),
|
||||
GetFanControl(u32),
|
||||
SetFanCurve(u32),
|
||||
Shutdown,
|
||||
}
|
||||
|
||||
impl Daemon {
|
||||
pub fn new() -> Daemon {
|
||||
pub fn new(unpriveleged: bool) -> Daemon {
|
||||
if fs::metadata(SOCK_PATH).is_ok() {
|
||||
fs::remove_file(SOCK_PATH).expect("Failed to take control over socket");
|
||||
}
|
||||
@ -46,19 +52,43 @@ impl Daemon {
|
||||
.expect("Failed to chmod");
|
||||
|
||||
let config_path = PathBuf::from("/etc/lact.json");
|
||||
let config = match Config::read_from_file(&config_path) {
|
||||
Ok(c) => c,
|
||||
Err(_) => {
|
||||
let c = Config::new();
|
||||
c.save(&config_path).expect("Failed to save config");
|
||||
c
|
||||
let config = if unpriveleged {
|
||||
Config::new()
|
||||
} else {
|
||||
match Config::read_from_file(&config_path) {
|
||||
Ok(c) => c,
|
||||
Err(_) => {
|
||||
let c = Config::new();
|
||||
c.save(&config_path).expect("Failed to save config");
|
||||
c
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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) {
|
||||
@ -67,7 +97,7 @@ impl Daemon {
|
||||
Ok(stream) => {
|
||||
//let mut controller = self.gpu_controller.clone();
|
||||
//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) => {
|
||||
log::error!("Error: {}", err);
|
||||
@ -77,41 +107,68 @@ impl Daemon {
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_connection(gpu_controller: &mut GpuController, mut stream: UnixStream) {
|
||||
let mut buffer: [u8; 4] = [0; 4];
|
||||
stream.read(&mut buffer).unwrap();
|
||||
fn handle_connection(gpu_controllers: &mut HashMap<u32, GpuController>, mut stream: UnixStream) {
|
||||
log::trace!("Reading buffer");
|
||||
let mut buffer = Vec::<u8>::new();
|
||||
stream.read_to_end(&mut buffer).unwrap();
|
||||
//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");
|
||||
//log::trace!("{:?}", action);
|
||||
|
||||
log::trace!("Executing action {:?}", action);
|
||||
let response: Option<Vec<u8>> = match action {
|
||||
Action::GetStats => Some(bincode::serialize(&gpu_controller.get_stats()).unwrap()),
|
||||
Action::GetInfo => Some(bincode::serialize(&gpu_controller.gpu_info).unwrap()),
|
||||
Action::StartFanControl => Some(bincode::serialize(&gpu_controller.start_fan_control()).unwrap()),
|
||||
Action::StopFanControl => Some(bincode::serialize(&gpu_controller.stop_fan_control()).unwrap()),
|
||||
Action::GetFanControl => Some(bincode::serialize(&gpu_controller.get_fan_control()).unwrap()),
|
||||
Action::SetFanCurve => {
|
||||
Action::CheckAlive => Some(vec![1]),
|
||||
Action::GetGpus => {
|
||||
let mut gpus: HashMap<u32, String> = HashMap::new();
|
||||
for controller in gpu_controllers {
|
||||
gpus.insert(*controller.0, controller.1.gpu_info.gpu_model.clone());
|
||||
}
|
||||
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();
|
||||
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
|
||||
},
|
||||
Action::CheckAlive => Some(vec![1]),
|
||||
}
|
||||
Action::Shutdown => std::process::exit(0),
|
||||
};
|
||||
|
||||
if let Some(r) = &response {
|
||||
stream
|
||||
.write_all(&r)
|
||||
.expect("Failed writing response");
|
||||
log::trace!("Responding");
|
||||
stream.write_all(&r).expect("Failed writing response");
|
||||
//stream
|
||||
// .shutdown(std::net::Shutdown::Write)
|
||||
// .expect("Could not shut down");
|
||||
log::trace!("Finished responding");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum DaemonError {
|
||||
ConnectionFailed,
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,6 @@ use daemon::Daemon;
|
||||
|
||||
fn main() {
|
||||
env_logger::init();
|
||||
let d = Daemon::new();
|
||||
let d = Daemon::new(false);
|
||||
d.listen();
|
||||
}
|
||||
|
@ -2,13 +2,22 @@ extern crate gdk;
|
||||
extern crate gio;
|
||||
extern crate gtk;
|
||||
|
||||
use daemon::{Daemon, daemon_connection::DaemonConnection};
|
||||
use daemon::{daemon_connection::DaemonConnection, Daemon};
|
||||
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 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: >k::Application) {
|
||||
let glade_src = include_str!("main_window.glade");
|
||||
@ -62,31 +71,23 @@ fn build_ui(application: >k::Application) {
|
||||
let vram_usage_label: Label = builder
|
||||
.get_object("vram_usage_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
|
||||
.get_object("vram_clock_text_buffer").unwrap();
|
||||
let gpu_clock_text_buffer: TextBuffer = builder.get_object("gpu_clock_text_buffer").unwrap();
|
||||
|
||||
let gpu_temp_text_buffer: TextBuffer = builder
|
||||
.get_object("gpu_temp_text_buffer").unwrap();
|
||||
let vram_clock_text_buffer: TextBuffer = builder.get_object("vram_clock_text_buffer").unwrap();
|
||||
|
||||
let gpu_power_text_buffer: TextBuffer = builder
|
||||
.get_object("gpu_power_text_buffer").unwrap();
|
||||
let gpu_temp_text_buffer: TextBuffer = builder.get_object("gpu_temp_text_buffer").unwrap();
|
||||
|
||||
let fan_speed_text_buffer: TextBuffer = builder
|
||||
.get_object("fan_speed_text_buffer").unwrap();
|
||||
let gpu_power_text_buffer: TextBuffer = builder.get_object("gpu_power_text_buffer").unwrap();
|
||||
|
||||
let automatic_fan_control_switch: Switch = builder
|
||||
.get_object("automatic_fan_control_switch").unwrap();
|
||||
let fan_speed_text_buffer: TextBuffer = builder.get_object("fan_speed_text_buffer").unwrap();
|
||||
|
||||
let apply_button: Button = builder
|
||||
.get_object("apply_button").unwrap();
|
||||
let automatic_fan_control_switch: Switch =
|
||||
builder.get_object("automatic_fan_control_switch").unwrap();
|
||||
|
||||
let fan_curve_frame: Frame = builder
|
||||
.get_object("fan_curve_frame").unwrap();
|
||||
let apply_button: Button = builder.get_object("apply_button").unwrap();
|
||||
|
||||
let fan_curve_frame: Frame = builder.get_object("fan_curve_frame").unwrap();
|
||||
|
||||
let mut unpriviliged: bool = false;
|
||||
|
||||
@ -95,7 +96,7 @@ fn build_ui(application: >k::Application) {
|
||||
Err(_) => {
|
||||
unpriviliged = true;
|
||||
|
||||
let daemon = Daemon::new();
|
||||
let daemon = Daemon::new(unpriviliged);
|
||||
thread::spawn(move || {
|
||||
daemon.listen();
|
||||
});
|
||||
@ -139,20 +140,17 @@ fn build_ui(application: >k::Application) {
|
||||
|
||||
let (tx, rx) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
|
||||
|
||||
thread::spawn(move || {
|
||||
loop {
|
||||
let gpu_stats = d.get_gpu_stats();
|
||||
thread::spawn(move || loop {
|
||||
let gpu_stats = d.get_gpu_stats();
|
||||
|
||||
tx.send(gpu_stats).expect("Couldn't send text");
|
||||
thread::sleep(Duration::from_millis(500));
|
||||
}
|
||||
tx.send(gpu_stats).expect("Couldn't send text");
|
||||
thread::sleep(Duration::from_millis(500));
|
||||
});
|
||||
|
||||
|
||||
rx.attach(None, move |gpu_stats| {
|
||||
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);
|
||||
|
||||
|
||||
let text = format!("{}/{} MiB", gpu_stats.mem_used, gpu_stats.mem_total);
|
||||
vram_usage_label.set_text(&text);
|
||||
|
||||
@ -161,9 +159,14 @@ 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));
|
||||
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)
|
||||
});
|
||||
@ -174,8 +177,7 @@ fn build_ui(application: >k::Application) {
|
||||
println!("Automatic fan control disabled!");
|
||||
automatic_fan_control_switch.set_active(false);
|
||||
fan_curve_frame.set_visible(true);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
println!("Automatic fan control enabled");
|
||||
fan_curve_frame.set_visible(false);
|
||||
}
|
||||
@ -187,8 +189,8 @@ fn build_ui(application: >k::Application) {
|
||||
match switch.get_active() {
|
||||
true => {
|
||||
fan_curve_frame.set_visible(false);
|
||||
},
|
||||
false => {
|
||||
}
|
||||
false => {
|
||||
fan_curve_frame.set_visible(true);
|
||||
}
|
||||
}
|
||||
@ -200,20 +202,24 @@ fn build_ui(application: >k::Application) {
|
||||
|
||||
for i in 1..6 {
|
||||
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);
|
||||
curve_temperature_adjustment.set_value(value);
|
||||
|
||||
let c = curve.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());
|
||||
b.set_sensitive(true);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
apply_button.connect_clicked(move |b| {
|
||||
@ -225,8 +231,8 @@ fn build_ui(application: >k::Application) {
|
||||
match automatic_fan_control_switch.get_active() {
|
||||
true => {
|
||||
d.stop_fan_control().unwrap();
|
||||
},
|
||||
false => {
|
||||
}
|
||||
false => {
|
||||
d.start_fan_control().unwrap();
|
||||
}
|
||||
}
|
||||
@ -237,7 +243,6 @@ fn build_ui(application: >k::Application) {
|
||||
main_window.show();
|
||||
}
|
||||
|
||||
|
||||
fn main() {
|
||||
println!("Initializing gtk");
|
||||
let application = gtk::Application::new(Some("com.ilyaz.yagc"), Default::default())
|
||||
|
Loading…
Reference in New Issue
Block a user