From bfbd57da9f6d522a74a58283e6668f9c5414f19d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A9=BA=E7=99=BD?= <3440771474@qq.com> Date: Thu, 28 Nov 2024 22:12:15 +0800 Subject: [PATCH] feat: marcos and sys-info crate --- .../ModelVis/rust/perf/Cargo.toml | 14 ++ .../ModelVis/rust/perf/src/lib.rs | 47 +++++++ .../ModelVis/rust/sys-info/Cargo.toml | 10 ++ .../ModelVis/rust/sys-info/src/lib.rs | 129 ++++++++++++++++++ .../ModelVis/rust/sys-info/tests/tests.rs | 53 +++++++ 5 files changed, 253 insertions(+) create mode 100644 plugins/mindstudio-insight-plugins/ModelVis/rust/perf/Cargo.toml create mode 100644 plugins/mindstudio-insight-plugins/ModelVis/rust/perf/src/lib.rs create mode 100644 plugins/mindstudio-insight-plugins/ModelVis/rust/sys-info/Cargo.toml create mode 100644 plugins/mindstudio-insight-plugins/ModelVis/rust/sys-info/src/lib.rs create mode 100644 plugins/mindstudio-insight-plugins/ModelVis/rust/sys-info/tests/tests.rs diff --git a/plugins/mindstudio-insight-plugins/ModelVis/rust/perf/Cargo.toml b/plugins/mindstudio-insight-plugins/ModelVis/rust/perf/Cargo.toml new file mode 100644 index 000000000..14a348250 --- /dev/null +++ b/plugins/mindstudio-insight-plugins/ModelVis/rust/perf/Cargo.toml @@ -0,0 +1,14 @@ +cargo-features = ["edition2024"] + +[package] +name = "perf" +version = "0.0.1" +authors = ["空白 "] +edition = "2024" + +[lib] +proc-macro = true + +[dependencies] +quote = "1.0.37" +syn = { version = "2.0.87", features = ["full"] } diff --git a/plugins/mindstudio-insight-plugins/ModelVis/rust/perf/src/lib.rs b/plugins/mindstudio-insight-plugins/ModelVis/rust/perf/src/lib.rs new file mode 100644 index 000000000..6d055d3b3 --- /dev/null +++ b/plugins/mindstudio-insight-plugins/ModelVis/rust/perf/src/lib.rs @@ -0,0 +1,47 @@ +use proc_macro::TokenStream; +use quote::{ToTokens, quote}; +use syn::{Ident, ItemFn, parse_macro_input, spanned::Spanned}; + +/// # Add +/// +/// `let start_time_ident = std::time::Instant::now()`
+/// to the previous line and
+/// `println!("{}: {:?}", #stmt_str, start_time_ident.elapsed())`
+/// to the next line of the origin code
+/// So we can find bottleneck of performance +#[proc_macro_attribute] +pub fn profile_lines(_attr: TokenStream, item: TokenStream) -> TokenStream { + let item: ItemFn = parse_macro_input!(item); + let name = &item.sig.ident; + let params = &item.sig.inputs; + + let new_body: Vec<_> = item + .block + .stmts + .iter() + .flat_map(|stmt| { + let stmt_str = stmt.to_token_stream().to_string(); + let stmt_clone = stmt.to_token_stream(); + let start_time_ident = Ident::new("start_time", stmt.span()); + + vec![ + quote! { + let #start_time_ident = std::time::Instant::now(); + }, + stmt_clone, + quote! { + println!("{}: {:?}", #stmt_str, #start_time_ident.elapsed()); + }, + ] + }) + .collect(); + + let expanded = quote! { + #[inline(never)] + pub fn #name(#params) { + #(#new_body)* + } + }; + + expanded.into() +} diff --git a/plugins/mindstudio-insight-plugins/ModelVis/rust/sys-info/Cargo.toml b/plugins/mindstudio-insight-plugins/ModelVis/rust/sys-info/Cargo.toml new file mode 100644 index 000000000..91cdbfec5 --- /dev/null +++ b/plugins/mindstudio-insight-plugins/ModelVis/rust/sys-info/Cargo.toml @@ -0,0 +1,10 @@ +cargo-features = ["edition2024"] + +[package] +name = "sys-info" +version = "0.1.0" +edition = "2024" + +[dependencies] +sysinfo = "0.32.0" +ash = "0.38.0+1.3.281" diff --git a/plugins/mindstudio-insight-plugins/ModelVis/rust/sys-info/src/lib.rs b/plugins/mindstudio-insight-plugins/ModelVis/rust/sys-info/src/lib.rs new file mode 100644 index 000000000..1db6f4115 --- /dev/null +++ b/plugins/mindstudio-insight-plugins/ModelVis/rust/sys-info/src/lib.rs @@ -0,0 +1,129 @@ +use std::ffi::CStr; + +use ash::{ + Entry, + vk::{ApplicationInfo, InstanceCreateInfo, make_api_version}, +}; +use sysinfo::{CpuRefreshKind, MemoryRefreshKind, RefreshKind, System}; + +pub struct CpuInfo { + pub name: String, + pub frequency: u64, + /// Most modern CPUs use both performance cores and efficiency cores, also known as + /// P-cores and E-cores, such as Intel Core series, AMD Ryzen series, and Apple Silicon series. + pub p_core_freq: u64, + pub e_core_freq: u64, + pub logical_cores: usize, + pub physical_cores: usize, +} + +pub struct Gpu { + pub name: String, + /// ```c + /// typedef enum VkPhysicalDeviceType { + /// VK_PHYSICAL_DEVICE_TYPE_OTHER = 0, + /// VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU = 1, + /// VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU = 2, + /// VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU = 3, + /// VK_PHYSICAL_DEVICE_TYPE_CPU = 4, + /// } VkPhysicalDeviceType; + /// ``` + /// device type can only be INTEGRATED_GPU、DISCRETE_GPU or VIRTUAL_GPU + pub device_type: i32, + pub total_memory: u64, +} + +pub struct MemInfo { + pub total_memory: u64, + pub available_memory: u64, + pub used_memory: u64, + pub total_swap: u64, + pub used_swap: u64, +} + +pub struct SysInfo { + pub cpu_info: CpuInfo, + pub gpu_info: Vec, + pub mem_info: MemInfo, +} + +const MB: u64 = 1024 * 1024; + +pub fn cpu_info() -> CpuInfo { + let sys = System::new_with_specifics(RefreshKind::new().with_cpu(CpuRefreshKind::everything())); + + let name = sys.cpus()[0].brand().to_string(); + let frequency = sys.cpus()[0].frequency(); + let logical_cores = sys.cpus().len(); + let physical_cores = sys.physical_core_count().unwrap_or(0); + + /// These cores typically have base frequencies and maximum frequencies, + /// and during normal operation, they often run closer to the maximum frequency. + /// The `sysinfo` crate only retrieves the base frequency, so the method of obtaining + /// the frequency needs to be modified to get a more accurate representation of performance. + let mut frequencies = sys.cpus().iter().map(|cpu| cpu.frequency()).collect::>(); + frequencies.sort_unstable(); + let p_core_freq = *frequencies.last().unwrap_or(&0); + let e_core_freq = *frequencies.first().unwrap_or(&0); + + CpuInfo { name, frequency, logical_cores, physical_cores, p_core_freq, e_core_freq } +} + +pub fn mem_info() -> MemInfo { + let sys = + System::new_with_specifics(RefreshKind::new().with_memory(MemoryRefreshKind::everything())); + + let total_memory = sys.total_memory() / MB; + let available_memory = sys.available_memory() / MB; + let used_memory = sys.used_memory() / MB; + let total_swap = sys.total_swap() / MB; + let used_swap = sys.used_swap() / MB; + + MemInfo { total_memory, available_memory, used_memory, total_swap, used_swap } +} + +pub fn gpu_info() -> Vec { + let entry = unsafe { Entry::load() }.unwrap(); + let app_info = + ApplicationInfo { api_version: make_api_version(0, 1, 0, 0), ..Default::default() }; + let create_info = InstanceCreateInfo { p_application_info: &app_info, ..Default::default() }; + let instance = unsafe { entry.create_instance(&create_info, None).unwrap() }; + + let physical_devices = unsafe { instance.enumerate_physical_devices() }.unwrap(); + + let mut gpu_info = Vec::with_capacity(2); + + for physical_device in physical_devices { + let properties = unsafe { instance.get_physical_device_properties(physical_device) }; + let memory_properties = + unsafe { instance.get_physical_device_memory_properties(physical_device) }; + + /// TODO: use a `buffer` and `String::from_raw_parts` + let name = unsafe { CStr::from_ptr(properties.device_name.as_ptr()) } + .to_string_lossy() + .to_string(); + let total_memory = memory_properties.memory_heaps[0].size / MB; + + let gpu = Gpu { name, device_type: properties.device_type.as_raw(), total_memory }; + + gpu_info.push(gpu) + } + + /// manually drop vulkan instance because ash doesn't impl `Drop` for Instance + unsafe { + instance.destroy_instance(None) + }; + + gpu_info +} + +/// This function retrieves the current machine's CPU, memory, and GPU information. +/// It runs once when the software starts to determine certain configuration options +/// in order to achieve better performance. +pub fn sys_info() -> SysInfo { + let cpu_info = cpu_info(); + let mem_info = mem_info(); + let gpu_info = gpu_info(); + + SysInfo { cpu_info, mem_info, gpu_info } +} diff --git a/plugins/mindstudio-insight-plugins/ModelVis/rust/sys-info/tests/tests.rs b/plugins/mindstudio-insight-plugins/ModelVis/rust/sys-info/tests/tests.rs new file mode 100644 index 000000000..7bed79e48 --- /dev/null +++ b/plugins/mindstudio-insight-plugins/ModelVis/rust/sys-info/tests/tests.rs @@ -0,0 +1,53 @@ +#[cfg(test)] +mod test_sys_info { + use ash::vk::PhysicalDeviceType; + use sys_info::{cpu_info, mem_info, sys_info}; + + #[test] + fn test_cpu_info() { + let cpu_info = cpu_info(); + + assert!(!cpu_info.name.is_empty()); + assert!(cpu_info.frequency > 0); + assert!(cpu_info.p_core_freq >= cpu_info.e_core_freq); + assert!(cpu_info.logical_cores > 0); + assert!(cpu_info.physical_cores > 0); + } + + #[test] + fn test_mem_info() { + let mem_info = mem_info(); + + assert!(mem_info.total_memory > 0); + assert!(mem_info.available_memory <= mem_info.total_memory); + assert!(mem_info.used_memory <= mem_info.total_memory); + assert!(mem_info.total_swap >= mem_info.used_swap); + } + + #[test] + fn test_sys_info() { + let sys_info = sys_info(); + + assert!(!sys_info.cpu_info.name.is_empty()); + assert!(sys_info.cpu_info.frequency > 0); + assert!(sys_info.cpu_info.p_core_freq >= sys_info.cpu_info.e_core_freq); + assert!(sys_info.cpu_info.logical_cores > 0); + assert!(sys_info.cpu_info.physical_cores > 0); + + assert!(sys_info.mem_info.total_memory > 0); + assert!(sys_info.mem_info.available_memory <= sys_info.mem_info.total_memory); + assert!(sys_info.mem_info.used_memory <= sys_info.mem_info.total_memory); + assert!(sys_info.mem_info.total_swap >= sys_info.mem_info.used_swap); + + assert!(!sys_info.gpu_info.is_empty()); + for gpu in &sys_info.gpu_info { + assert!(!gpu.name.is_empty()); + assert!( + gpu.device_type == PhysicalDeviceType::INTEGRATED_GPU.as_raw() + || gpu.device_type == PhysicalDeviceType::DISCRETE_GPU.as_raw() + || gpu.device_type == PhysicalDeviceType::VIRTUAL_GPU.as_raw() + ); + assert!(gpu.total_memory > 0); + } + } +} -- Gitee