mirror of
https://github.com/ilya-zlobintsev/LACT.git
synced 2025-02-25 18:55:26 -06:00
Added pci.ids path for ubuntu and fixed crash for GPUs without hwmon interface
This commit is contained in:
parent
55bc2ee468
commit
d5d0829e4e
@ -1,7 +1,7 @@
|
|||||||
use crate::config::Config;
|
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::path::PathBuf;
|
use std::path::{Path, PathBuf};
|
||||||
use std::{collections::BTreeMap, fs};
|
use std::{collections::BTreeMap, fs};
|
||||||
use vulkano::instance::{Instance, InstanceExtensions, PhysicalDevice};
|
use vulkano::instance::{Instance, InstanceExtensions, PhysicalDevice};
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ pub struct FanControlInfo {
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct GpuController {
|
pub struct GpuController {
|
||||||
hw_path: PathBuf,
|
hw_path: PathBuf,
|
||||||
hw_mon: HWMon,
|
hw_mon: Option<HWMon>,
|
||||||
pub gpu_info: GpuInfo,
|
pub gpu_info: GpuInfo,
|
||||||
config: Config,
|
config: Config,
|
||||||
config_path: PathBuf,
|
config_path: PathBuf,
|
||||||
@ -58,18 +58,19 @@ 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"))
|
let hw_mon = match fs::read_dir(&hw_path.join("hwmon")) {
|
||||||
.unwrap()
|
Ok(mut path) => {
|
||||||
.next()
|
let path = path.next().unwrap().unwrap().path();
|
||||||
.unwrap()
|
let hw_mon = HWMon::new(
|
||||||
.unwrap()
|
&path,
|
||||||
.path();
|
config.fan_control_enabled,
|
||||||
|
config.fan_curve.clone(),
|
||||||
|
);
|
||||||
|
Some(hw_mon)
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
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(),
|
||||||
@ -95,17 +96,17 @@ impl GpuController {
|
|||||||
|
|
||||||
for line in uevent.split('\n') {
|
for line in uevent.split('\n') {
|
||||||
let split = line.split('=').collect::<Vec<&str>>();
|
let split = line.split('=').collect::<Vec<&str>>();
|
||||||
match split[0] {
|
match split.get(0).unwrap() {
|
||||||
"DRIVER" => driver = split[1].to_string(),
|
&"DRIVER" => driver = split.get(1).unwrap().to_string(),
|
||||||
"PCI_ID" => {
|
&"PCI_ID" => {
|
||||||
let ids = split[1].split(':').collect::<Vec<&str>>();
|
let ids = split.last().expect("failed to get split").split(':').collect::<Vec<&str>>();
|
||||||
vendor_id = ids[0].to_string();
|
vendor_id = ids.get(0).unwrap().to_string();
|
||||||
model_id = ids[1].to_string();
|
model_id = ids.get(0).unwrap().to_string();
|
||||||
}
|
}
|
||||||
"PCI_SUBSYS_ID" => {
|
&"PCI_SUBSYS_ID" => {
|
||||||
let ids = split[1].split(':').collect::<Vec<&str>>();
|
let ids = split.last().expect("failed to get split").split(':').collect::<Vec<&str>>();
|
||||||
card_vendor_id = ids[0].to_string();
|
card_vendor_id = ids.get(0).unwrap().to_string();
|
||||||
card_model_id = ids[1].to_string();
|
card_model_id = ids.get(1).unwrap().to_string();
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
@ -116,38 +117,46 @@ impl GpuController {
|
|||||||
let mut card_vendor = String::new();
|
let mut card_vendor = String::new();
|
||||||
let mut card_model = String::new();
|
let mut card_model = String::new();
|
||||||
|
|
||||||
let full_hwid_list = fs::read_to_string("/usr/share/hwdata/pci.ids")
|
let mut full_hwid_list = String::new();
|
||||||
.expect("Could not read pci.ids. Perhaps the \"hwids\" package is not installed?");
|
if Path::exists(&PathBuf::from("/usr/share/hwdata/pci.ids")) {
|
||||||
|
full_hwid_list = fs::read_to_string("/usr/share/hwdata/pci.ids").unwrap();
|
||||||
|
} else if Path::exists(&PathBuf::from("/usr/share/misc/pci.ids")) {
|
||||||
|
full_hwid_list = fs::read_to_string("/usr/share/misc/pci.ids").unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
//some weird space character, don't touch
|
if !full_hwid_list.is_empty() {
|
||||||
let pci_id_line = format!(" {}", model_id.to_lowercase());
|
//some weird space character, don't touch
|
||||||
let card_ids_line = format!(
|
let pci_id_line = format!(" {}", model_id.to_lowercase());
|
||||||
" {} {}",
|
let card_ids_line = format!(
|
||||||
card_vendor_id.to_lowercase(),
|
" {} {}",
|
||||||
card_model_id.to_lowercase()
|
card_vendor_id.to_lowercase(),
|
||||||
);
|
card_model_id.to_lowercase()
|
||||||
|
);
|
||||||
|
|
||||||
let lines: Vec<&str> = full_hwid_list.split('\n').collect();
|
let lines: Vec<&str> = full_hwid_list.split('\n').collect();
|
||||||
|
|
||||||
//for line in full_hwid_list.split('\n') {
|
//for line in full_hwid_list.split('\n') {
|
||||||
for i in 0..lines.len() {
|
for i in 0..lines.len() {
|
||||||
let line = lines[i];
|
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>>().last().unwrap()
|
||||||
.trim_start()
|
.trim_start()
|
||||||
.to_string();
|
.to_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if line.contains(&pci_id_line) {
|
||||||
|
model = line[pci_id_line.len()..].trim_start().to_string();
|
||||||
|
}
|
||||||
|
if line.contains(&card_ids_line) {
|
||||||
|
card_model = line[card_ids_line.len()..].trim_start().to_string();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if line.contains(&pci_id_line) {
|
|
||||||
model = line[pci_id_line.len()..].trim_start().to_string();
|
|
||||||
}
|
|
||||||
if line.contains(&card_ids_line) {
|
|
||||||
card_model = line[card_ids_line.len()..].trim_start().to_string();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let vbios_version = match fs::read_to_string(self.hw_path.join("vbios_version")) {
|
let vbios_version = match fs::read_to_string(self.hw_path.join("vbios_version")) {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(_) => "".to_string(),
|
Err(_) => "".to_string(),
|
||||||
@ -199,11 +208,10 @@ impl GpuController {
|
|||||||
Err(_) => 0,
|
Err(_) => 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
let (mem_freq, gpu_freq) = (self.hw_mon.get_mem_freq(), self.hw_mon.get_gpu_freq());
|
let (mem_freq, gpu_freq, gpu_temp, power_avg, power_max, fan_speed, max_fan_speed) = match &self.hw_mon {
|
||||||
let gpu_temp = self.hw_mon.get_gpu_temp();
|
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),
|
||||||
let (power_avg, power_max) = (self.hw_mon.get_power_avg(), self.hw_mon.get_power_cap());
|
None => (0, 0, 0, 0, 0, 0, 0),
|
||||||
let fan_speed = self.hw_mon.get_fan_speed();
|
};
|
||||||
let max_fan_speed = self.hw_mon.fan_max_speed;
|
|
||||||
|
|
||||||
GpuStats {
|
GpuStats {
|
||||||
mem_total,
|
mem_total,
|
||||||
@ -219,48 +227,70 @@ impl GpuController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn start_fan_control(&mut self) -> Result<(), HWMonError> {
|
pub fn start_fan_control(&mut self) -> Result<(), HWMonError> {
|
||||||
match self.hw_mon.start_fan_control() {
|
match &self.hw_mon {
|
||||||
Ok(_) => {
|
Some(hw_mon) => {
|
||||||
self.config.fan_control_enabled = true;
|
|
||||||
self.config
|
match hw_mon.start_fan_control() {
|
||||||
.save(&self.config_path)
|
Ok(_) => {
|
||||||
.expect("Failed to save config");
|
self.config.fan_control_enabled = true;
|
||||||
Ok(())
|
self.config
|
||||||
}
|
.save(&self.config_path)
|
||||||
Err(e) => Err(e),
|
.expect("Failed to save config");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(e) => Err(e),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => Err(HWMonError::NoHWMon),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stop_fan_control(&mut self) -> Result<(), HWMonError> {
|
pub fn stop_fan_control(&mut self) -> Result<(), HWMonError> {
|
||||||
match self.hw_mon.stop_fan_control() {
|
match &self.hw_mon {
|
||||||
Ok(_) => {
|
Some(hw_mon) => {
|
||||||
self.config.fan_control_enabled = false;
|
match hw_mon.stop_fan_control() {
|
||||||
|
Ok(_) => {
|
||||||
|
self.config.fan_control_enabled = false;
|
||||||
|
self.config
|
||||||
|
.save(&self.config_path)
|
||||||
|
.expect("Failed to save config");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(e) => Err(e),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => Err(HWMonError::NoHWMon),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_fan_control(&self) -> Result<FanControlInfo, HWMonError> {
|
||||||
|
match &self.hw_mon {
|
||||||
|
Some(hw_mon) => {
|
||||||
|
let control = hw_mon.get_fan_control();
|
||||||
|
Ok(FanControlInfo {
|
||||||
|
enabled: control.0,
|
||||||
|
curve: control.1,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
None => Err(HWMonError::NoHWMon),
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_fan_curve(&mut self, curve: BTreeMap<i32, f64>) -> Result<(), HWMonError> {
|
||||||
|
match &self.hw_mon {
|
||||||
|
Some(hw_mon) => {
|
||||||
|
hw_mon.set_fan_curve(curve.clone());
|
||||||
|
self.config.fan_curve = curve;
|
||||||
self.config
|
self.config
|
||||||
.save(&self.config_path)
|
.save(&self.config_path)
|
||||||
.expect("Failed to save config");
|
.expect("Failed to save config");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
},
|
||||||
Err(e) => Err(e),
|
None => Err(HWMonError::NoHWMon),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_fan_control(&self) -> FanControlInfo {
|
|
||||||
let control = self.hw_mon.get_fan_control();
|
|
||||||
|
|
||||||
FanControlInfo {
|
|
||||||
enabled: control.0,
|
|
||||||
curve: control.1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_vulkan_info(pci_id: &str) -> VulkanInfo {
|
fn get_vulkan_info(pci_id: &str) -> VulkanInfo {
|
||||||
let mut device_name = String::from("Not supported");
|
let mut device_name = String::from("Not supported");
|
||||||
let mut api_version = String::new();
|
let mut api_version = String::new();
|
||||||
|
@ -15,6 +15,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub enum HWMonError {
|
pub enum HWMonError {
|
||||||
PermissionDenied,
|
PermissionDenied,
|
||||||
|
NoHWMon,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -150,7 +150,10 @@ impl Daemon {
|
|||||||
None => Err(DaemonError::InvalidID),
|
None => Err(DaemonError::InvalidID),
|
||||||
},
|
},
|
||||||
Action::GetFanControl(i) => match gpu_controllers.get(&i) {
|
Action::GetFanControl(i) => match gpu_controllers.get(&i) {
|
||||||
Some(controller) => Ok(DaemonResponse::FanControlInfo(controller.get_fan_control())),
|
Some(controller) => match controller.get_fan_control() {
|
||||||
|
Ok(info) => Ok(DaemonResponse::FanControlInfo(info)),
|
||||||
|
Err(_) => Err(DaemonError::HWMonError),
|
||||||
|
}
|
||||||
None => Err(DaemonError::InvalidID),
|
None => Err(DaemonError::InvalidID),
|
||||||
}
|
}
|
||||||
Action::SetFanCurve(i, curve) => match gpu_controllers.get_mut(&i) {
|
Action::SetFanCurve(i, curve) => match gpu_controllers.get_mut(&i) {
|
||||||
@ -159,9 +162,11 @@ impl Daemon {
|
|||||||
let mut buffer = Vec::new();
|
let mut buffer = Vec::new();
|
||||||
stream.read_to_end(&mut buffer).unwrap();
|
stream.read_to_end(&mut buffer).unwrap();
|
||||||
|
|
||||||
controller.set_fan_curve(curve);
|
match controller.set_fan_curve(curve) {
|
||||||
|
Ok(_) => Ok(DaemonResponse::OK),
|
||||||
|
Err(_) => Err(DaemonError::HWMonError),
|
||||||
|
}
|
||||||
|
|
||||||
Ok(DaemonResponse::OK)
|
|
||||||
},
|
},
|
||||||
None => Err(DaemonError::InvalidID),
|
None => Err(DaemonError::InvalidID),
|
||||||
}
|
}
|
||||||
|
120
gui/src/main.rs
120
gui/src/main.rs
@ -146,17 +146,28 @@ fn build_ui(application: >k::Application) {
|
|||||||
glib::Continue(true)
|
glib::Continue(true)
|
||||||
});
|
});
|
||||||
|
|
||||||
let fan_control = d.get_fan_control(current_gpu_id).unwrap();
|
let fan_control = d.get_fan_control(current_gpu_id);
|
||||||
|
|
||||||
if fan_control.enabled {
|
match fan_control {
|
||||||
println!("Automatic fan control disabled!");
|
Ok(ref fan_control) => {
|
||||||
automatic_fan_control_switch.set_active(false);
|
if fan_control.enabled {
|
||||||
fan_curve_frame.set_visible(true);
|
println!("Automatic fan control disabled!");
|
||||||
} else {
|
automatic_fan_control_switch.set_active(false);
|
||||||
println!("Automatic fan control enabled");
|
fan_curve_frame.set_visible(true);
|
||||||
fan_curve_frame.set_visible(false);
|
} else {
|
||||||
|
println!("Automatic fan control enabled");
|
||||||
|
fan_curve_frame.set_visible(false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(_) => {
|
||||||
|
automatic_fan_control_switch.set_sensitive(false);
|
||||||
|
automatic_fan_control_switch.set_tooltip_text(Some("Unavailable"));
|
||||||
|
|
||||||
|
fan_curve_frame.set_visible(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let b = apply_button.clone();
|
let b = apply_button.clone();
|
||||||
|
|
||||||
let switch = automatic_fan_control_switch.clone();
|
let switch = automatic_fan_control_switch.clone();
|
||||||
@ -173,55 +184,62 @@ fn build_ui(application: >k::Application) {
|
|||||||
b.set_sensitive(true);
|
b.set_sensitive(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
let curve: Arc<RwLock<BTreeMap<i32, f64>>> = Arc::new(RwLock::new(fan_control.curve));
|
match fan_control {
|
||||||
|
Ok(fan_control) => {
|
||||||
|
|
||||||
for i in 1..6 {
|
let curve: Arc<RwLock<BTreeMap<i32, f64>>> = Arc::new(RwLock::new(fan_control.curve));
|
||||||
let curve_temperature_adjustment: Adjustment = builder
|
|
||||||
.get_object(&format!("curve_temperature_adjustment_{}", i))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let value = *curve
|
for i in 1..6 {
|
||||||
.read()
|
let curve_temperature_adjustment: Adjustment = builder
|
||||||
.unwrap()
|
.get_object(&format!("curve_temperature_adjustment_{}", i))
|
||||||
.get(&(i * 20))
|
.unwrap();
|
||||||
.expect("Could not get by index");
|
|
||||||
println!("Setting value {} on adjustment {}", value, i);
|
|
||||||
curve_temperature_adjustment.set_value(value);
|
|
||||||
|
|
||||||
let c = curve.clone();
|
let value = *curve
|
||||||
let b = apply_button.clone();
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
.get(&(i * 20))
|
||||||
|
.expect("Could not get by index");
|
||||||
|
println!("Setting value {} on adjustment {}", value, i);
|
||||||
|
curve_temperature_adjustment.set_value(value);
|
||||||
|
|
||||||
curve_temperature_adjustment.connect_value_changed(move |adj| {
|
let c = curve.clone();
|
||||||
c.write().unwrap().insert(20 * i, adj.get_value());
|
let b = apply_button.clone();
|
||||||
b.set_sensitive(true);
|
|
||||||
});
|
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| {
|
||||||
|
let curve = curve.read().unwrap().clone();
|
||||||
|
println!("setting curve to {:?}", curve);
|
||||||
|
d.set_fan_curve(current_gpu_id, curve).unwrap();
|
||||||
|
b.set_sensitive(false);
|
||||||
|
|
||||||
|
match automatic_fan_control_switch.get_active() {
|
||||||
|
true => {
|
||||||
|
d.stop_fan_control(current_gpu_id).unwrap();
|
||||||
|
|
||||||
|
let diag = MessageDialog::new(
|
||||||
|
None::<&Window>,
|
||||||
|
DialogFlags::empty(),
|
||||||
|
MessageType::Error,
|
||||||
|
ButtonsType::Ok,
|
||||||
|
"WARNING: Due to a driver bug, the GPU fan may misbehave after switching to automatic control. You may need to reboot your system to avoid issues.",
|
||||||
|
);
|
||||||
|
diag.run();
|
||||||
|
diag.hide();
|
||||||
|
}
|
||||||
|
false => {
|
||||||
|
d.start_fan_control(current_gpu_id).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
Err(_) => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
apply_button.connect_clicked(move |b| {
|
|
||||||
let curve = curve.read().unwrap().clone();
|
|
||||||
println!("setting curve to {:?}", curve);
|
|
||||||
d.set_fan_curve(current_gpu_id, curve).unwrap();
|
|
||||||
b.set_sensitive(false);
|
|
||||||
|
|
||||||
match automatic_fan_control_switch.get_active() {
|
|
||||||
true => {
|
|
||||||
d.stop_fan_control(current_gpu_id).unwrap();
|
|
||||||
|
|
||||||
let diag = MessageDialog::new(
|
|
||||||
None::<&Window>,
|
|
||||||
DialogFlags::empty(),
|
|
||||||
MessageType::Error,
|
|
||||||
ButtonsType::Ok,
|
|
||||||
"WARNING: Due to a driver bug, the GPU fan may misbehave after switching to automatic control. You may need to reboot your system to avoid issues.",
|
|
||||||
);
|
|
||||||
diag.run();
|
|
||||||
diag.hide();
|
|
||||||
}
|
|
||||||
false => {
|
|
||||||
d.start_fan_control(current_gpu_id).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
main_window.set_application(Some(application));
|
main_window.set_application(Some(application));
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user