diff --git a/src/console_writer.rs b/src/console_writer.rs index 9b71835..ad86f6c 100644 --- a/src/console_writer.rs +++ b/src/console_writer.rs @@ -55,7 +55,7 @@ pub fn handle_arguments_listing(data: &Data, args: &crate::args::Args) { if args.list_available { let pci_devices = &data.pci_devices; if args.detail { - crate::device::print_available_profiles_in_detail(pci_devices); + crate::device_misc::print_available_profiles_in_detail(pci_devices); } else { for pci_device in pci_devices.iter() { let available_profiles = &pci_device.get_available_profiles(); @@ -105,7 +105,7 @@ pub fn print_installed_profiles(installed_profiles: &[Profile]) { } for profile in installed_profiles.iter() { - crate::profile::print_profile_details(profile); + crate::profile_misc::print_profile_details(profile); } println!(); } diff --git a/src/data.rs b/src/data.rs index f46c215..4a73c02 100644 --- a/src/data.rs +++ b/src/data.rs @@ -245,7 +245,7 @@ pub fn get_all_devices_of_profile(devices: &ListOfDevicesT, profile: &Profile) - } if let Some(gc_versions) = &profile.gc_versions { - if let Some(hwd_gc_versions) = crate::misc::get_gc_versions() { + if let Some(hwd_gc_versions) = crate::hwd_misc::get_gc_versions() { return get_all_devices_from_gc_versions(devices, &hwd_gc_versions, gc_versions); } return vec![]; diff --git a/src/device.rs b/src/device.rs index 9a9d640..336f26e 100644 --- a/src/device.rs +++ b/src/device.rs @@ -15,7 +15,6 @@ // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. use crate::profile::Profile; -use crate::{console_writer, fl, profile}; use std::sync::Arc; @@ -55,45 +54,3 @@ pub fn get_unique_devices(devices: &[Device]) -> Vec { uniq_devices } - -pub fn print_available_profiles_in_detail(devices: &[Device]) { - let mut config_found = false; - for device in devices.iter() { - let available_profiles = &device.available_profiles; - let installed_profiles = &device.installed_profiles; - if available_profiles.is_empty() && installed_profiles.is_empty() { - continue; - } - config_found = true; - - log::info!( - "{} {}: {} ({}:{}:{})", - "PCI", - fl!("device"), - device.sysfs_id, - device.class_id, - device.vendor_id, - device.device_id - ); - println!(" {} {} {}", device.class_name, device.vendor_name, device.device_name); - println!(); - if !installed_profiles.is_empty() { - println!(" > {}:\n", fl!("installed")); - for installed_profile in installed_profiles.iter() { - profile::print_profile_details(installed_profile); - } - println!("\n"); - } - if !available_profiles.is_empty() { - println!(" > {}:\n", fl!("available")); - for available_profile in available_profiles.iter() { - profile::print_profile_details(available_profile); - } - println!("\n"); - } - } - - if !config_found { - console_writer::print_warn_msg!("no-profile-device"); - } -} diff --git a/src/device_misc.rs b/src/device_misc.rs new file mode 100644 index 0000000..41c1fca --- /dev/null +++ b/src/device_misc.rs @@ -0,0 +1,60 @@ +// Copyright (C) 2023-2024 Vladislav Nepogodin +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use crate::device::Device; +use crate::{console_writer, fl, profile_misc}; + +pub fn print_available_profiles_in_detail(devices: &[Device]) { + let mut config_found = false; + for device in devices.iter() { + let available_profiles = &device.available_profiles; + let installed_profiles = &device.installed_profiles; + if available_profiles.is_empty() && installed_profiles.is_empty() { + continue; + } + config_found = true; + + log::info!( + "{} {}: {} ({}:{}:{})", + "PCI", + fl!("device"), + device.sysfs_id, + device.class_id, + device.vendor_id, + device.device_id + ); + println!(" {} {} {}", device.class_name, device.vendor_name, device.device_name); + println!(); + if !installed_profiles.is_empty() { + println!(" > {}:\n", fl!("installed")); + for installed_profile in installed_profiles.iter() { + profile_misc::print_profile_details(installed_profile); + } + println!("\n"); + } + if !available_profiles.is_empty() { + println!(" > {}:\n", fl!("available")); + for available_profile in available_profiles.iter() { + profile_misc::print_profile_details(available_profile); + } + println!("\n"); + } + } + + if !config_found { + console_writer::print_warn_msg!("no-profile-device"); + } +} diff --git a/src/hwd_misc.rs b/src/hwd_misc.rs new file mode 100644 index 0000000..62a2b6d --- /dev/null +++ b/src/hwd_misc.rs @@ -0,0 +1,113 @@ +// Copyright (C) 2023-2024 Vladislav Nepogodin +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +pub fn get_sysfs_busid_from_amdgpu_path(amdgpu_path: &str) -> &str { + amdgpu_path.split('/') + // Extract the 7th element (amdgpu id) + .nth(6) + .unwrap_or_default() +} + +// returns Vec of ( sysfs busid, formatted GC version ) +pub fn get_gc_versions() -> Option> { + use std::fs; + + let ip_match_paths = glob::glob("/sys/bus/pci/drivers/amdgpu/*/ip_discovery/die/*/GC/*/") + .expect("Failed to read glob pattern"); + + let gc_versions = ip_match_paths + .filter_map(Result::ok) + .filter_map(|path| path.to_str().map(|s| s.to_owned())) + .filter_map(|ip_match_path| { + let sysfs_busid = get_sysfs_busid_from_amdgpu_path(&ip_match_path).to_owned(); + + let major = + fs::read_to_string(format!("{ip_match_path}/major")).ok()?.trim().to_owned(); + let minor = + fs::read_to_string(format!("{ip_match_path}/minor")).ok()?.trim().to_owned(); + let revision = + fs::read_to_string(format!("{ip_match_path}/revision")).ok()?.trim().to_owned(); + + Some((sysfs_busid, format!("{major}.{minor}.{revision}"))) + }) + .collect::>(); + + // Correctly check for empty Vec: + if gc_versions.is_empty() { + None + } else { + Some(gc_versions) + } +} + +#[cfg(test)] +mod tests { + use crate::hwd_misc; + + #[test] + fn gpu_from_amdgpu_path() { + assert_eq!( + hwd_misc::get_sysfs_busid_from_amdgpu_path( + "/sys/bus/pci/drivers/amdgpu/0000:c2:00.0/ip_discovery/die/0/GC/0/" + ), + "0000:c2:00.0" + ); + assert_eq!( + hwd_misc::get_sysfs_busid_from_amdgpu_path( + "/sys/bus/pci/drivers/amdgpu/0000:c2:00.0/ip_discovery/die//" + ), + "0000:c2:00.0" + ); + assert_eq!( + hwd_misc::get_sysfs_busid_from_amdgpu_path("/sys/bus/pci/drivers/amdgpu/0000:c2:00.0/"), + "0000:c2:00.0" + ); + assert_eq!( + hwd_misc::get_sysfs_busid_from_amdgpu_path( + "/sys/bus/pci/drivers/amdgpu/0000:30:00.0/ip_discovery/die/0/GC/0" + ), + "0000:30:00.0" + ); + assert_eq!( + hwd_misc::get_sysfs_busid_from_amdgpu_path( + "/sys/bus/pci/drivers/amdgpu/0000:30:00.0/ip_discovery/die//" + ), + "0000:30:00.0" + ); + assert_eq!( + hwd_misc::get_sysfs_busid_from_amdgpu_path("/sys/bus/pci/drivers/amdgpu/0000:30:00.0/"), + "0000:30:00.0" + ); + assert_eq!( + hwd_misc::get_sysfs_busid_from_amdgpu_path( + "/sys/bus/pci/drivers/amdgpu/0000:04:00.0/ip_discovery/die/0/GC/0" + ), + "0000:04:00.0" + ); + assert_eq!( + hwd_misc::get_sysfs_busid_from_amdgpu_path( + "/sys/bus/pci/drivers/amdgpu/0000:04:00.0/ip_discovery/die//" + ), + "0000:04:00.0" + ); + assert_eq!( + hwd_misc::get_sysfs_busid_from_amdgpu_path("/sys/bus/pci/drivers/amdgpu/0000:04:00.0/"), + "0000:04:00.0" + ); + + assert_eq!(hwd_misc::get_sysfs_busid_from_amdgpu_path("/sys/bus/pci/drivers/amdgpu/"), ""); + } +} diff --git a/src/lib.rs b/src/lib.rs index 5906405..e1db922 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,5 +19,6 @@ pub mod consts; pub mod data; pub mod device; +pub mod hwd_misc; pub mod localization; pub mod profile; diff --git a/src/main.rs b/src/main.rs index 0931784..93ca9e0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,8 +18,10 @@ pub mod args; pub mod console_writer; +pub mod device_misc; pub mod logger; pub mod misc; +pub mod profile_misc; use chwd::profile::Profile; use chwd::*; diff --git a/src/misc.rs b/src/misc.rs index b3d5f97..347d9b9 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -75,45 +75,6 @@ pub fn check_environment() -> Vec { missing_dirs } -pub fn get_sysfs_busid_from_amdgpu_path(amdgpu_path: &str) -> &str { - amdgpu_path.split('/') - // Extract the 7th element (amdgpu id) - .nth(6) - .unwrap_or_default() -} - -// returns Vec of ( sysfs busid, formatted GC version ) -pub fn get_gc_versions() -> Option> { - use std::fs; - - let ip_match_paths = glob::glob("/sys/bus/pci/drivers/amdgpu/*/ip_discovery/die/*/GC/*/") - .expect("Failed to read glob pattern"); - - let gc_versions = ip_match_paths - .filter_map(Result::ok) - .filter_map(|path| path.to_str().map(|s| s.to_owned())) - .filter_map(|ip_match_path| { - let sysfs_busid = get_sysfs_busid_from_amdgpu_path(&ip_match_path).to_owned(); - - let major = - fs::read_to_string(format!("{ip_match_path}/major")).ok()?.trim().to_owned(); - let minor = - fs::read_to_string(format!("{ip_match_path}/minor")).ok()?.trim().to_owned(); - let revision = - fs::read_to_string(format!("{ip_match_path}/revision")).ok()?.trim().to_owned(); - - Some((sysfs_busid, format!("{major}.{minor}.{revision}"))) - }) - .collect::>(); - - // Correctly check for empty Vec: - if gc_versions.is_empty() { - None - } else { - Some(gc_versions) - } -} - #[cfg(test)] mod tests { use crate::{misc, profile}; @@ -134,58 +95,4 @@ mod tests { assert!(misc::find_profile("nvidia-dkm", &profiles).is_none()); assert!(misc::find_profile("nvidia-dkms.40xxcards", &profiles).is_some()); } - - #[test] - fn gpu_from_amdgpu_path() { - assert_eq!( - misc::get_sysfs_busid_from_amdgpu_path( - "/sys/bus/pci/drivers/amdgpu/0000:c2:00.0/ip_discovery/die/0/GC/0/" - ), - "0000:c2:00.0" - ); - assert_eq!( - misc::get_sysfs_busid_from_amdgpu_path( - "/sys/bus/pci/drivers/amdgpu/0000:c2:00.0/ip_discovery/die//" - ), - "0000:c2:00.0" - ); - assert_eq!( - misc::get_sysfs_busid_from_amdgpu_path("/sys/bus/pci/drivers/amdgpu/0000:c2:00.0/"), - "0000:c2:00.0" - ); - assert_eq!( - misc::get_sysfs_busid_from_amdgpu_path( - "/sys/bus/pci/drivers/amdgpu/0000:30:00.0/ip_discovery/die/0/GC/0" - ), - "0000:30:00.0" - ); - assert_eq!( - misc::get_sysfs_busid_from_amdgpu_path( - "/sys/bus/pci/drivers/amdgpu/0000:30:00.0/ip_discovery/die//" - ), - "0000:30:00.0" - ); - assert_eq!( - misc::get_sysfs_busid_from_amdgpu_path("/sys/bus/pci/drivers/amdgpu/0000:30:00.0/"), - "0000:30:00.0" - ); - assert_eq!( - misc::get_sysfs_busid_from_amdgpu_path( - "/sys/bus/pci/drivers/amdgpu/0000:04:00.0/ip_discovery/die/0/GC/0" - ), - "0000:04:00.0" - ); - assert_eq!( - misc::get_sysfs_busid_from_amdgpu_path( - "/sys/bus/pci/drivers/amdgpu/0000:04:00.0/ip_discovery/die//" - ), - "0000:04:00.0" - ); - assert_eq!( - misc::get_sysfs_busid_from_amdgpu_path("/sys/bus/pci/drivers/amdgpu/0000:04:00.0/"), - "0000:04:00.0" - ); - - assert_eq!(misc::get_sysfs_busid_from_amdgpu_path("/sys/bus/pci/drivers/amdgpu/"), ""); - } } diff --git a/src/profile.rs b/src/profile.rs index 8d2bc09..cfebec2 100644 --- a/src/profile.rs +++ b/src/profile.rs @@ -14,12 +14,7 @@ // with this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -use crate::fl; - use anyhow::Result; -use comfy_table::modifiers::UTF8_ROUND_CORNERS; -use comfy_table::presets::UTF8_FULL; -use comfy_table::*; use std::fs; use std::sync::Arc; @@ -377,30 +372,6 @@ fn replace_escaping_toml(profiles: &toml::Table) -> String { toml_string } -pub fn print_profile_details(profile: &Profile) { - let mut class_ids = String::new(); - let mut vendor_ids = String::new(); - for hwd_id in profile.hwd_ids.iter() { - vendor_ids.push_str(&hwd_id.vendor_ids.join(" ")); - class_ids.push_str(&hwd_id.class_ids.join(" ")); - } - - let desc_formatted = if profile.desc.is_empty() { "-" } else { &profile.desc }; - - let mut table = Table::new(); - table - .load_preset(UTF8_FULL) - .apply_modifier(UTF8_ROUND_CORNERS) - .set_content_arrangement(ContentArrangement::Dynamic) - .add_row(vec![&fl!("name-header"), &profile.name]) - .add_row(vec![&fl!("desc-header"), desc_formatted]) - .add_row(vec![&fl!("priority-header"), &profile.priority.to_string()]) - .add_row(vec![&fl!("classids-header"), &class_ids]) - .add_row(vec![&fl!("vendorids-header"), &vendor_ids]); - - println!("{table}\n"); -} - fn profile_into_toml(profile: &Profile) -> toml::Table { let mut table = toml::Table::new(); table.insert("ai_sdk".to_owned(), profile.is_ai_sdk.into()); diff --git a/src/profile_misc.rs b/src/profile_misc.rs new file mode 100644 index 0000000..b752311 --- /dev/null +++ b/src/profile_misc.rs @@ -0,0 +1,46 @@ +// Copyright (C) 2023-2024 Vladislav Nepogodin +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use crate::fl; +use crate::profile::Profile; + +use comfy_table::modifiers::UTF8_ROUND_CORNERS; +use comfy_table::presets::UTF8_FULL; +use comfy_table::*; + +pub fn print_profile_details(profile: &Profile) { + let mut class_ids = String::new(); + let mut vendor_ids = String::new(); + for hwd_id in profile.hwd_ids.iter() { + vendor_ids.push_str(&hwd_id.vendor_ids.join(" ")); + class_ids.push_str(&hwd_id.class_ids.join(" ")); + } + + let desc_formatted = if profile.desc.is_empty() { "-" } else { &profile.desc }; + + let mut table = Table::new(); + table + .load_preset(UTF8_FULL) + .apply_modifier(UTF8_ROUND_CORNERS) + .set_content_arrangement(ContentArrangement::Dynamic) + .add_row(vec![&fl!("name-header"), &profile.name]) + .add_row(vec![&fl!("desc-header"), desc_formatted]) + .add_row(vec![&fl!("priority-header"), &profile.priority.to_string()]) + .add_row(vec![&fl!("classids-header"), &class_ids]) + .add_row(vec![&fl!("vendorids-header"), &vendor_ids]); + + println!("{table}\n"); +}