mirror of
https://github.com/ilya-zlobintsev/LACT.git
synced 2025-02-25 18:55:26 -06:00
Reworked the pci.ids parser
This commit is contained in:
parent
2449cc9ee3
commit
b7da2cbad5
@ -67,8 +67,8 @@ fn main() {
|
||||
|
||||
fn print_info(d: &DaemonConnection, gpu_id: u32) {
|
||||
let gpu_info = d.get_gpu_info(gpu_id).unwrap();
|
||||
println!("{} {}", "GPU Model:".blue(), gpu_info.card_model.bold());
|
||||
println!("{} {}", "GPU Vendor:".blue(), gpu_info.gpu_vendor.bold());
|
||||
println!("{} {}", "GPU Model:".blue(), gpu_info.vendor_data.card_model.unwrap_or_default().bold());
|
||||
println!("{} {}", "GPU Vendor:".blue(), gpu_info.vendor_data.gpu_vendor.unwrap_or_default().bold());
|
||||
println!("{} {}", "Driver in use:".blue(), gpu_info.driver.bold());
|
||||
println!("{} {}", "VBIOS Version:".blue(), gpu_info.vbios_version.bold());
|
||||
println!("{} {}", "VRAM Size:".blue(), gpu_info.vram_size.to_string().bold());
|
||||
|
@ -24,8 +24,8 @@ impl From<serde_json::Error> for ConfigError {
|
||||
#[derive(Deserialize, Serialize, Debug, Clone, Hash, Eq)]
|
||||
pub struct GpuIdentifier {
|
||||
pub pci_id: String,
|
||||
pub card_model: String,
|
||||
pub gpu_model: String,
|
||||
pub card_model: Option<String>,
|
||||
pub gpu_model: Option<String>,
|
||||
pub path: PathBuf,
|
||||
}
|
||||
|
||||
|
@ -261,7 +261,7 @@ impl DaemonConnection {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_gpus(&self) -> Result<HashMap<u32, String>, DaemonError> {
|
||||
pub fn get_gpus(&self) -> Result<HashMap<u32, Option<String>>, DaemonError> {
|
||||
log::trace!("sending request");
|
||||
let mut s = UnixStream::connect(SOCK_PATH).unwrap();
|
||||
s.write_all(&bincode::serialize(&Action::GetGpus).unwrap())
|
||||
|
@ -1,6 +1,7 @@
|
||||
use crate::config::{GpuConfig, GpuIdentifier};
|
||||
use crate::hw_mon::{HWMon, HWMonError};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use vendor_data::VendorData;
|
||||
use std::{collections::BTreeMap, fs};
|
||||
use std::{
|
||||
num::ParseIntError,
|
||||
@ -8,6 +9,8 @@ use std::{
|
||||
};
|
||||
use vulkano::instance::{Instance, InstanceExtensions, PhysicalDevice};
|
||||
|
||||
pub mod vendor_data;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub enum GpuControllerError {
|
||||
NotSupported,
|
||||
@ -123,10 +126,7 @@ pub struct VulkanInfo {
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
|
||||
pub struct GpuInfo {
|
||||
pub gpu_vendor: String,
|
||||
pub gpu_model: String,
|
||||
pub card_model: String,
|
||||
pub card_vendor: String,
|
||||
pub vendor_data: VendorData,
|
||||
pub model_id: String,
|
||||
pub vendor_id: String,
|
||||
pub driver: String,
|
||||
@ -190,8 +190,8 @@ impl GpuController {
|
||||
let gpu_info = self.get_info();
|
||||
GpuIdentifier {
|
||||
pci_id: gpu_info.pci_slot.clone(),
|
||||
card_model: gpu_info.card_model.clone(),
|
||||
gpu_model: gpu_info.gpu_model.clone(),
|
||||
card_model: gpu_info.vendor_data.card_model.clone(),
|
||||
gpu_model: gpu_info.vendor_data.gpu_model.clone(),
|
||||
path: self.hw_path.clone(),
|
||||
}
|
||||
}
|
||||
@ -234,54 +234,6 @@ impl GpuController {
|
||||
}
|
||||
}
|
||||
|
||||
let vendor = "AMD".to_string();
|
||||
let mut model = String::new();
|
||||
let mut card_vendor = String::new();
|
||||
let mut card_model = String::new();
|
||||
|
||||
let mut full_hwid_list = String::new();
|
||||
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();
|
||||
}
|
||||
|
||||
if !full_hwid_list.is_empty() {
|
||||
//some weird space character, don't touch
|
||||
let pci_id_line = format!(" {}", model_id.to_lowercase());
|
||||
let card_ids_line = format!(
|
||||
" {} {}",
|
||||
card_vendor_id.to_lowercase(),
|
||||
card_model_id.to_lowercase()
|
||||
);
|
||||
log::trace!("identifying {} \n {}", pci_id_line, card_ids_line);
|
||||
|
||||
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>>()
|
||||
.last()
|
||||
.unwrap()
|
||||
.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")) {
|
||||
Ok(v) => v,
|
||||
Err(_) => "".to_string(),
|
||||
@ -316,11 +268,15 @@ impl GpuController {
|
||||
Err(_) => None,
|
||||
};
|
||||
|
||||
let vendor_data = match VendorData::from_ids(&vendor_id, &model_id, &card_vendor_id, &card_model_id) {
|
||||
Ok(data) => data,
|
||||
Err(e) => VendorData::default(),
|
||||
};
|
||||
|
||||
log::info!("Vendor data: {:?}", vendor_data);
|
||||
|
||||
GpuInfo {
|
||||
gpu_vendor: vendor,
|
||||
gpu_model: model,
|
||||
card_vendor,
|
||||
card_model,
|
||||
vendor_data,
|
||||
model_id,
|
||||
vendor_id,
|
||||
driver,
|
||||
|
221
daemon/src/gpu_controller/vendor_data.rs
Normal file
221
daemon/src/gpu_controller/vendor_data.rs
Normal file
@ -0,0 +1,221 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum VendorDataError {
|
||||
MissingIdsFile,
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct VendorData {
|
||||
pub gpu_vendor: Option<String>,
|
||||
pub gpu_model: Option<String>,
|
||||
pub card_vendor: Option<String>,
|
||||
pub card_model: Option<String>,
|
||||
}
|
||||
|
||||
impl VendorData {
|
||||
pub fn from_ids(
|
||||
vendor_id: &str,
|
||||
model_id: &str,
|
||||
subsys_vendor_id: &str,
|
||||
subsys_model_id: &str,
|
||||
) -> Result<VendorData, VendorDataError> {
|
||||
let vendor_id = vendor_id.to_lowercase();
|
||||
let model_id = model_id.to_lowercase();
|
||||
let subsys_vendor_id = subsys_vendor_id.to_lowercase();
|
||||
let subsys_model_id = subsys_model_id.to_lowercase();
|
||||
|
||||
match PciDatabase::read() {
|
||||
Ok(db) => {
|
||||
let mut gpu_vendor = None;
|
||||
let mut gpu_model = None;
|
||||
let mut card_vendor = None;
|
||||
let mut card_model = None;
|
||||
|
||||
log::trace!("Seacrhing vendor {}", vendor_id);
|
||||
if let Some(vendor) = db.vendors.get(&vendor_id) {
|
||||
log::trace!("Found vendor {}", vendor.name);
|
||||
gpu_vendor = Some(vendor.name.clone());
|
||||
|
||||
log::trace!("Searching device {}", model_id);
|
||||
if let Some(model) = vendor.devices.get(&model_id) {
|
||||
log::trace!("Found device {}", model.name);
|
||||
gpu_model = Some(model.name.clone());
|
||||
|
||||
log::trace!("Searching subdevice {} {}", subsys_vendor_id, subsys_model_id);
|
||||
if let Some(subvendor) = db.vendors.get(&subsys_vendor_id) {
|
||||
log::trace!("Found subvendor {}", subvendor.name);
|
||||
card_vendor = Some(subvendor.name.clone());
|
||||
}
|
||||
if let Some(subdevice) = model.subdevices.get(&(subsys_vendor_id, subsys_model_id)) {
|
||||
log::trace!("Found subdevice {}", subdevice);
|
||||
card_model = Some(subdevice.to_owned());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(VendorData { gpu_vendor, gpu_model, card_vendor, card_model })
|
||||
},
|
||||
Err(_) => Err(VendorDataError::MissingIdsFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum PciDatabaseError {
|
||||
FileNotFound,
|
||||
}
|
||||
|
||||
struct PciDatabase {
|
||||
pub vendors: HashMap<String, PciVendor>,
|
||||
}
|
||||
|
||||
impl PciDatabase {
|
||||
pub fn read<'a>() -> Result<Self, PciDatabaseError> {
|
||||
let _ = env_logger::builder().is_test(true).try_init();
|
||||
|
||||
match Self::read_pci_db() {
|
||||
Some(pci_ids) => {
|
||||
log::trace!("Parsing pci.ids");
|
||||
|
||||
let mut vendors: HashMap<String, PciVendor> = HashMap::new();
|
||||
|
||||
let mut lines = pci_ids.split("\n").into_iter();
|
||||
|
||||
let mut current_vendor_id: Option<String> = None;
|
||||
let mut current_device_id: Option<String> = None;
|
||||
|
||||
while let Some(line) = lines.next() {
|
||||
if line.starts_with("#") | line.is_empty() {
|
||||
continue;
|
||||
} else if line.starts_with("\t\t") {
|
||||
let mut split = line.split_whitespace();
|
||||
|
||||
let vendor_id = split.next().unwrap().to_owned();
|
||||
let device_id = split.next().unwrap().to_owned();
|
||||
let name = split.collect::<Vec<&str>>().join(" ");
|
||||
|
||||
if let Some(current_vendor_id) = ¤t_vendor_id {
|
||||
if let Some(current_device_id) = ¤t_device_id {
|
||||
vendors
|
||||
.get_mut(current_vendor_id)
|
||||
.unwrap()
|
||||
.devices
|
||||
.get_mut(current_device_id)
|
||||
.unwrap()
|
||||
.subdevices
|
||||
.insert((vendor_id, device_id), name);
|
||||
}
|
||||
}
|
||||
} else if line.starts_with("\t") {
|
||||
let mut split = line.split_whitespace();
|
||||
|
||||
let id = split.next().unwrap().to_owned();
|
||||
let name = split.collect::<Vec<&str>>().join(" ");
|
||||
|
||||
let device = PciDevice::new(name);
|
||||
|
||||
current_device_id = Some(id.clone());
|
||||
|
||||
if let Some(current_vendor_id) = ¤t_vendor_id {
|
||||
vendors
|
||||
.get_mut(current_vendor_id)
|
||||
.unwrap()
|
||||
.devices
|
||||
.insert(id, device);
|
||||
}
|
||||
} else {
|
||||
let mut split = line.split_whitespace();
|
||||
|
||||
let id = split.next().unwrap().to_owned();
|
||||
let name = split.collect::<Vec<&str>>().join(" ");
|
||||
|
||||
current_vendor_id = Some(id.clone());
|
||||
|
||||
let vendor = PciVendor::new(name);
|
||||
vendors.insert(id, vendor);
|
||||
}
|
||||
}
|
||||
Ok(PciDatabase { vendors })
|
||||
}
|
||||
None => Err(PciDatabaseError::FileNotFound),
|
||||
}
|
||||
}
|
||||
|
||||
fn read_pci_db() -> Option<String> {
|
||||
let paths = ["/usr/share/hwdata/pci.ids", "/usr/share/misc/pci.ids"];
|
||||
|
||||
if let Some(path) = paths.iter().find(|path| Path::exists(&PathBuf::from(path))) {
|
||||
let all_ids = fs::read_to_string(path).unwrap();
|
||||
|
||||
Some(all_ids)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct PciVendor {
|
||||
pub name: String,
|
||||
pub devices: HashMap<String, PciDevice>,
|
||||
}
|
||||
|
||||
impl PciVendor {
|
||||
pub fn new(name: String) -> Self {
|
||||
PciVendor {
|
||||
name,
|
||||
devices: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct PciDevice {
|
||||
pub name: String,
|
||||
pub subdevices: HashMap<(String, String), String>, // <(vendor_id, device_id), name>
|
||||
}
|
||||
|
||||
impl PciDevice {
|
||||
pub fn new(name: String) -> Self {
|
||||
PciDevice {
|
||||
name,
|
||||
subdevices: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn init() {
|
||||
let _ = env_logger::builder().is_test(true).try_init();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_polaris() {
|
||||
init();
|
||||
let data = VendorData::from_ids("1002", "67DF", "1DA2", "E387").unwrap();
|
||||
|
||||
assert_eq!(data.gpu_vendor, Some("Advanced Micro Devices, Inc. [AMD/ATI]".to_string()));
|
||||
assert_eq!(data.gpu_model, Some("Ellesmere [Radeon RX 470/480/570/570X/580/580X/590]".to_string()));
|
||||
assert_eq!(data.card_vendor, Some("Sapphire Technology Limited".to_string()));
|
||||
assert_eq!(data.card_model, Some("Radeon RX 570 Pulse 4GB".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_vega() {
|
||||
let data = VendorData::from_ids("1002", "687F", "1043", "0555").unwrap();
|
||||
|
||||
assert_eq!(data.gpu_vendor, Some("Advanced Micro Devices, Inc. [AMD/ATI]".to_string()));
|
||||
assert_eq!(data.gpu_model, Some("Vega 10 XL/XT [Radeon RX Vega 56/64]".to_string()));
|
||||
assert_eq!(data.card_vendor, Some("ASUSTeK Computer Inc.".to_string()));
|
||||
assert_eq!(data.card_model, None);
|
||||
}
|
||||
}
|
@ -95,7 +95,7 @@ impl Daemon {
|
||||
let gpu_info = controller.get_info();
|
||||
|
||||
for (id, (gpu_identifier, gpu_config)) in &config.gpu_configs {
|
||||
if gpu_info.pci_slot == gpu_identifier.pci_id && gpu_info.card_model == gpu_identifier.card_model && gpu_info.gpu_model == gpu_identifier.gpu_model {
|
||||
if gpu_info.pci_slot == gpu_identifier.pci_id && gpu_info.vendor_data.card_model == gpu_identifier.card_model && gpu_info.vendor_data.gpu_model == gpu_identifier.gpu_model {
|
||||
controller.load_config(gpu_config.clone());
|
||||
gpu_controllers.insert(id.clone(), controller);
|
||||
log::info!("already known");
|
||||
@ -155,9 +155,9 @@ impl Daemon {
|
||||
let response: Result<DaemonResponse, DaemonError> = match action {
|
||||
Action::CheckAlive => Ok(DaemonResponse::OK),
|
||||
Action::GetGpus => {
|
||||
let mut gpus: HashMap<u32, String> = HashMap::new();
|
||||
let mut gpus: HashMap<u32, Option<String>> = HashMap::new();
|
||||
for (id, controller) in &self.gpu_controllers {
|
||||
gpus.insert(*id, controller.get_info().gpu_model.clone());
|
||||
gpus.insert(*id, controller.get_info().vendor_data.gpu_model.clone());
|
||||
}
|
||||
Ok(DaemonResponse::Gpus(gpus))
|
||||
},
|
||||
@ -336,7 +336,7 @@ pub enum DaemonResponse {
|
||||
OK,
|
||||
GpuInfo(gpu_controller::GpuInfo),
|
||||
GpuStats(gpu_controller::GpuStats),
|
||||
Gpus(HashMap<u32, String>),
|
||||
Gpus(HashMap<u32, Option<String>>),
|
||||
PowerCap((i64, i64)),
|
||||
FanControlInfo(gpu_controller::FanControlInfo),
|
||||
}
|
||||
|
@ -105,8 +105,8 @@ fn build_ui(application: >k::Application) {
|
||||
|
||||
let gpus = d.get_gpus().unwrap();
|
||||
|
||||
for gpu in &gpus {
|
||||
gpu_select_comboboxtext.append(Some(&gpu.0.to_string()), &gpu.1);
|
||||
for (id, gpu) in &gpus {
|
||||
gpu_select_comboboxtext.append(Some(&id.to_string()), &gpu.clone().unwrap_or_default());
|
||||
}
|
||||
|
||||
//limits the length of gpu names in combobox
|
||||
@ -408,8 +408,8 @@ fn set_info(builder: &Builder, d: DaemonConnection, gpu_id: u32, gpu_power_level
|
||||
|
||||
let gpu_info = d.get_gpu_info(gpu_id).unwrap();
|
||||
|
||||
gpu_model_text_buffer.set_text(&gpu_info.card_model);
|
||||
manufacturer_text_buffer.set_text(&gpu_info.card_vendor);
|
||||
gpu_model_text_buffer.set_text(&gpu_info.vendor_data.card_model.unwrap_or_default());
|
||||
manufacturer_text_buffer.set_text(&gpu_info.vendor_data.card_vendor.unwrap_or_default());
|
||||
vbios_version_text_buffer.set_text(&gpu_info.vbios_version);
|
||||
driver_text_buffer.set_text(&gpu_info.driver);
|
||||
vram_size_text_buffer.set_text(&format!("{} MiB", &gpu_info.vram_size));
|
||||
|
Loading…
Reference in New Issue
Block a user