Added pci.ids path for ubuntu and fixed crash for GPUs without hwmon interface

This commit is contained in:
Ilya Zlobintsev 2020-11-11 17:25:37 +02:00
parent 55bc2ee468
commit d5d0829e4e
4 changed files with 191 additions and 137 deletions

View File

@ -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();

View File

@ -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)]

View File

@ -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),
} }

View File

@ -146,17 +146,28 @@ fn build_ui(application: &gtk::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: &gtk::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));