added system info slimes
This commit is contained in:
@@ -92,15 +92,15 @@ pub fn run_benchmark_multithread(prime_limit: u64, jobs: usize) -> BenchmarkResu
|
||||
let final_count = *shared_total_prime_count.lock().unwrap();
|
||||
|
||||
// Calculate average time a thread spent working
|
||||
let durations_guard = shared_thread_durations.lock().unwrap();
|
||||
let total_thread_microseconds: u128 = durations_guard.iter().map(|d| d.as_micros()).sum();
|
||||
// let durations_guard = shared_thread_durations.lock().unwrap();
|
||||
// let total_thread_microseconds: u128 = durations_guard.iter().map(|d| d.as_micros()).sum();
|
||||
|
||||
let average_thread_microseconds = if !durations_guard.is_empty() {
|
||||
total_thread_microseconds / durations_guard.len() as u128
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let average_thread_duration = Duration::from_micros(average_thread_microseconds as u64);
|
||||
// let average_thread_microseconds = if !durations_guard.is_empty() {
|
||||
// total_thread_microseconds / durations_guard.len() as u128
|
||||
// } else {
|
||||
// 0
|
||||
// };
|
||||
// let average_thread_duration = Duration::from_micros(average_thread_microseconds as u64);
|
||||
|
||||
// Score normalized by load factor to represent "Speed per unit of work"
|
||||
let score = calculate_score(duration, MULTI_THREAD_LOAD_FACTOR as u64, prime_limit);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// use colored::Colorize;
|
||||
|
||||
mod benchmark;
|
||||
mod slimes;
|
||||
pub mod benchmark;
|
||||
pub mod slimes;
|
||||
|
||||
pub fn application_header() -> &'static str {
|
||||
let ascii_art = r#"
|
||||
|
||||
69
src/main.rs
69
src/main.rs
@@ -1,9 +1,12 @@
|
||||
use clap::Parser;
|
||||
use colored::Colorize;
|
||||
use slimefetch::application_header;
|
||||
use sysinfo::System;
|
||||
|
||||
mod benchmark;
|
||||
use crate::benchmark::{BenchmarkResults, run_benchmark_multithread, run_benchmark_singlethread};
|
||||
use slimes::{
|
||||
application_header,
|
||||
benchmark::{BenchmarkResults, run_benchmark_multithread, run_benchmark_singlethread},
|
||||
slimes::get_all_slimes,
|
||||
};
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
@@ -31,35 +34,47 @@ fn main() {
|
||||
|
||||
println!("{}", application_header().bright_blue());
|
||||
|
||||
let logical_core_count = match cli.jobs {
|
||||
Some(j) => j,
|
||||
None => num_cpus::get(),
|
||||
};
|
||||
let slimes = get_all_slimes();
|
||||
|
||||
print_section_header("Single Threaded CPU Benchmark");
|
||||
let singlethread_benchmark = run_benchmark_singlethread(cli.prime_limit);
|
||||
print_detailed_result(&singlethread_benchmark);
|
||||
print_section_header("Multi Threaded CPU Benchmark");
|
||||
let multithread_benchmark = run_benchmark_multithread(cli.prime_limit, logical_core_count);
|
||||
print_detailed_result(&multithread_benchmark);
|
||||
let mut sys = System::new_all();
|
||||
sys.refresh_all();
|
||||
|
||||
let multi_thread_speedup_ratio = if singlethread_benchmark.score > 0 {
|
||||
multithread_benchmark.score / singlethread_benchmark.score
|
||||
} else {
|
||||
0
|
||||
};
|
||||
for slime in slimes {
|
||||
slime.print(&sys);
|
||||
}
|
||||
println!();
|
||||
|
||||
let scaling_color_formatter =
|
||||
if multi_thread_speedup_ratio as f64 > (logical_core_count as f64 * 0.7) {
|
||||
|s: String| s.green()
|
||||
} else {
|
||||
|s: String| s.yellow()
|
||||
if !cli.skip_benchmark {
|
||||
let logical_core_count = match cli.jobs {
|
||||
Some(j) => j,
|
||||
None => num_cpus::get(),
|
||||
};
|
||||
|
||||
println!(
|
||||
"Parallel Scaling : {}",
|
||||
scaling_color_formatter(format!("{:.2}x", multi_thread_speedup_ratio)).bold()
|
||||
);
|
||||
print_section_header("Single Threaded CPU Benchmark");
|
||||
let singlethread_benchmark = run_benchmark_singlethread(cli.prime_limit);
|
||||
print_detailed_result(&singlethread_benchmark);
|
||||
print_section_header("Multi Threaded CPU Benchmark");
|
||||
let multithread_benchmark = run_benchmark_multithread(cli.prime_limit, logical_core_count);
|
||||
print_detailed_result(&multithread_benchmark);
|
||||
|
||||
let multi_thread_speedup_ratio = if singlethread_benchmark.score > 0 {
|
||||
multithread_benchmark.score / singlethread_benchmark.score
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
let scaling_color_formatter =
|
||||
if multi_thread_speedup_ratio as f64 > (logical_core_count as f64 * 0.7) {
|
||||
|s: String| s.green()
|
||||
} else {
|
||||
|s: String| s.yellow()
|
||||
};
|
||||
|
||||
println!(
|
||||
"Parallel Scaling : {}",
|
||||
scaling_color_formatter(format!("{:.2}x", multi_thread_speedup_ratio)).bold()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_section_header(title_text: &str) {
|
||||
|
||||
424
src/slimes.rs
424
src/slimes.rs
@@ -1,18 +1,420 @@
|
||||
use colored::Color;
|
||||
use colored::Colorize;
|
||||
use sysinfo::System;
|
||||
|
||||
trait Slime {
|
||||
fn label(&self) -> String;
|
||||
fn value(&self) -> String;
|
||||
fn icon(&self) -> String;
|
||||
pub trait Slime {
|
||||
fn label(&self) -> &str;
|
||||
fn values(&self, sys: &System) -> Vec<String>;
|
||||
fn icon(&self) -> &str;
|
||||
fn color(&self) -> Color;
|
||||
|
||||
fn print(&self) {
|
||||
println!(
|
||||
"{} {:<12} {}",
|
||||
self.icon().color(self.color()),
|
||||
format!("{}:", self.label()).bold().color(self.color()),
|
||||
self.value().white()
|
||||
);
|
||||
fn print(&self, sys: &System) {
|
||||
for (i, val) in self.values(sys).iter().enumerate() {
|
||||
if i == 0 {
|
||||
print!(
|
||||
"{} {:<10} ",
|
||||
self.icon().color(self.color()),
|
||||
format!("{}:", self.label()).bold().color(self.color())
|
||||
);
|
||||
} else {
|
||||
print!("{} {:<10} ", " ", " ");
|
||||
}
|
||||
println!("{}", val.white());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_all_slimes() -> Vec<Box<dyn Slime>> {
|
||||
vec![
|
||||
Box::new(OsSlime),
|
||||
Box::new(KernelSlime),
|
||||
Box::new(HostnameSlime),
|
||||
Box::new(BoardSlime),
|
||||
Box::new(CpuSlime),
|
||||
Box::new(GpuSlime),
|
||||
Box::new(RamSlime),
|
||||
Box::new(MonitorSlime),
|
||||
Box::new(NetworkSlime),
|
||||
Box::new(AudioSlime),
|
||||
]
|
||||
}
|
||||
|
||||
/// OS name
|
||||
pub struct OsSlime;
|
||||
impl Slime for OsSlime {
|
||||
fn label(&self) -> &str {
|
||||
"OS"
|
||||
}
|
||||
fn values(&self, _sys: &System) -> Vec<String> {
|
||||
vec![format!(
|
||||
"{}",
|
||||
System::long_os_version().unwrap_or_else(|| "Unknown".into()),
|
||||
)]
|
||||
}
|
||||
fn icon(&self) -> &str {
|
||||
""
|
||||
}
|
||||
fn color(&self) -> Color {
|
||||
Color::Blue
|
||||
}
|
||||
}
|
||||
|
||||
/// Kernel version
|
||||
pub struct KernelSlime;
|
||||
impl Slime for KernelSlime {
|
||||
fn label(&self) -> &str {
|
||||
"Kernel"
|
||||
}
|
||||
fn values(&self, _sys: &System) -> Vec<String> {
|
||||
vec![System::kernel_version().unwrap_or_else(|| "Unknown".into())]
|
||||
}
|
||||
fn icon(&self) -> &str {
|
||||
""
|
||||
}
|
||||
fn color(&self) -> Color {
|
||||
Color::Blue
|
||||
}
|
||||
}
|
||||
|
||||
/// Hostname
|
||||
pub struct HostnameSlime;
|
||||
impl Slime for HostnameSlime {
|
||||
fn label(&self) -> &str {
|
||||
"Hostname"
|
||||
}
|
||||
fn values(&self, _sys: &System) -> Vec<String> {
|
||||
vec![System::host_name().unwrap_or_else(|| "Unknown".into())]
|
||||
}
|
||||
fn icon(&self) -> &str {
|
||||
""
|
||||
}
|
||||
fn color(&self) -> Color {
|
||||
Color::Blue
|
||||
}
|
||||
}
|
||||
|
||||
/// CPU name with highest frequency found in all cores
|
||||
pub struct CpuSlime;
|
||||
impl Slime for CpuSlime {
|
||||
fn label(&self) -> &str {
|
||||
"CPU"
|
||||
}
|
||||
fn values(&self, sys: &System) -> Vec<String> {
|
||||
// sys.cpus()
|
||||
// .iter()
|
||||
// .map(|cpu| format!("{} @ {:.2}GHz", cpu.name(), cpu.frequency() as f32 / 1000.0))
|
||||
// .collect()
|
||||
|
||||
let cpus = sys.cpus();
|
||||
|
||||
let max_freq_mhz = cpus.iter().map(|c| c.frequency()).max().unwrap_or(0) as f32 / 1000.0;
|
||||
|
||||
if let Some(cpu) = cpus.first() {
|
||||
vec![format!(
|
||||
"{} @ ~{:.2}GHz",
|
||||
cpu.brand(),
|
||||
// c.vendor_id(),
|
||||
max_freq_mhz
|
||||
)]
|
||||
} else {
|
||||
vec![String::from("Unknown")]
|
||||
}
|
||||
}
|
||||
fn icon(&self) -> &str {
|
||||
""
|
||||
}
|
||||
fn color(&self) -> Color {
|
||||
Color::Yellow
|
||||
}
|
||||
}
|
||||
|
||||
/// RAM usage over available
|
||||
pub struct RamSlime;
|
||||
impl Slime for RamSlime {
|
||||
fn label(&self) -> &str {
|
||||
"RAM"
|
||||
}
|
||||
fn values(&self, sys: &System) -> Vec<String> {
|
||||
let total_ram = sys.total_memory() / 1024 / 1024;
|
||||
let used_ram = sys.used_memory() / 1024 / 1024;
|
||||
vec![format!(
|
||||
"{}MB / {}MB",
|
||||
used_ram.to_string(),
|
||||
total_ram.to_string()
|
||||
)]
|
||||
}
|
||||
fn icon(&self) -> &str {
|
||||
""
|
||||
}
|
||||
fn color(&self) -> Color {
|
||||
Color::Magenta
|
||||
}
|
||||
}
|
||||
|
||||
/// Motherboard / chassis
|
||||
pub struct BoardSlime;
|
||||
impl Slime for BoardSlime {
|
||||
fn label(&self) -> &str {
|
||||
"Board"
|
||||
}
|
||||
fn icon(&self) -> &str {
|
||||
""
|
||||
}
|
||||
fn color(&self) -> Color {
|
||||
Color::Green
|
||||
}
|
||||
fn values(&self, _sys: &System) -> Vec<String> {
|
||||
let Some(mobo) = sysinfo::Motherboard::new() else {
|
||||
return vec!["Unknown Model".into()];
|
||||
};
|
||||
|
||||
let parts = [
|
||||
mobo.vendor_name(),
|
||||
mobo.version().filter(|v| v != "Default string"),
|
||||
mobo.name(),
|
||||
];
|
||||
|
||||
let result = parts
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.filter(|s| !s.is_empty())
|
||||
.collect::<Vec<_>>()
|
||||
.join(" ");
|
||||
|
||||
vec![if result.is_empty() {
|
||||
"Unknown Model".into()
|
||||
} else {
|
||||
result
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
/// GPUs
|
||||
pub struct GpuSlime;
|
||||
impl Slime for GpuSlime {
|
||||
fn label(&self) -> &str {
|
||||
"GPU"
|
||||
}
|
||||
fn icon(&self) -> &str {
|
||||
""
|
||||
}
|
||||
fn color(&self) -> Color {
|
||||
Color::Cyan
|
||||
}
|
||||
fn values(&self, _sys: &System) -> Vec<String> {
|
||||
let mut gpus = Vec::new();
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
if let Ok(output) = Command::new("wmic")
|
||||
.args(["path", "win32_VideoController", "get", "name"])
|
||||
.output()
|
||||
{
|
||||
let s = String::from_utf8_lossy(&output.stdout);
|
||||
for line in s.lines().skip(1) {
|
||||
let name = line.trim();
|
||||
if !name.is_empty() {
|
||||
gpus.push(name.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
use std::process::Command;
|
||||
|
||||
if let Ok(output) = Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg("lspci | grep -E 'VGA|3D'")
|
||||
.output()
|
||||
{
|
||||
let s = String::from_utf8_lossy(&output.stdout);
|
||||
for line in s.lines() {
|
||||
if let Some(pos) = line.find(": ") {
|
||||
gpus.push(
|
||||
line[pos + 2..]
|
||||
.to_string()
|
||||
.replace("Advanced Micro Devices, Inc. [AMD/ATI]", "AMD"),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if gpus.is_empty() {
|
||||
vec!["Unknown GPU".into()]
|
||||
} else {
|
||||
gpus
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Monitors
|
||||
pub struct MonitorSlime;
|
||||
impl Slime for MonitorSlime {
|
||||
fn label(&self) -> &str {
|
||||
"Monitors"
|
||||
}
|
||||
fn icon(&self) -> &str {
|
||||
""
|
||||
}
|
||||
fn color(&self) -> Color {
|
||||
Color::Blue
|
||||
}
|
||||
fn values(&self, _sys: &System) -> Vec<String> {
|
||||
match display_info::DisplayInfo::all() {
|
||||
Ok(displays) => displays
|
||||
.iter()
|
||||
.map(|d| {
|
||||
format!(
|
||||
"{} {}x{} @ {}Hz {}",
|
||||
d.friendly_name,
|
||||
d.width,
|
||||
d.height,
|
||||
d.frequency,
|
||||
if d.is_primary {
|
||||
"[Primary]"
|
||||
} else {
|
||||
"[External]"
|
||||
}
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
Err(_) => vec!["No monitors found".into()],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Network (wifi/ethernet) hardware
|
||||
pub struct NetworkSlime;
|
||||
impl Slime for NetworkSlime {
|
||||
fn label(&self) -> &str {
|
||||
"Network"
|
||||
}
|
||||
fn icon(&self) -> &str {
|
||||
""
|
||||
}
|
||||
fn color(&self) -> Color {
|
||||
Color::Cyan
|
||||
}
|
||||
fn values(&self, _sys: &System) -> Vec<String> {
|
||||
let mut nets = Vec::new();
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
use std::process::Command;
|
||||
|
||||
if let Ok(output) = Command::new("wmic")
|
||||
.args([
|
||||
"path",
|
||||
"win32_networkadapter",
|
||||
"where",
|
||||
"PhysicalAdapter=True",
|
||||
"get",
|
||||
"name",
|
||||
])
|
||||
.output()
|
||||
{
|
||||
let s = String::from_utf8_lossy(&output.stdout);
|
||||
for line in s.lines().skip(1) {
|
||||
let name = line.trim();
|
||||
if !name.is_empty() {
|
||||
nets.push(name.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
use std::process::Command;
|
||||
|
||||
if let Ok(output) = Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg("lspci | grep -E 'Network|Ethernet'")
|
||||
.output()
|
||||
{
|
||||
let s = String::from_utf8_lossy(&output.stdout);
|
||||
for line in s.lines() {
|
||||
if let Some(pos) = line.find(": ") {
|
||||
nets.push(line[pos + 2..].trim().to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if nets.is_empty() {
|
||||
vec!["Unknown Network Controller".into()]
|
||||
} else {
|
||||
nets
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Audio hardware
|
||||
pub struct AudioSlime;
|
||||
impl Slime for AudioSlime {
|
||||
fn label(&self) -> &str {
|
||||
"Audio"
|
||||
}
|
||||
fn icon(&self) -> &str {
|
||||
""
|
||||
}
|
||||
fn color(&self) -> Color {
|
||||
Color::Red
|
||||
}
|
||||
fn values(&self, _sys: &System) -> Vec<String> {
|
||||
let mut audio_cards = Vec::new();
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
use std::process::Command;
|
||||
|
||||
if let Ok(output) = Command::new("wmic")
|
||||
.args(["path", "win32_sounddevice", "get", "name"])
|
||||
.output()
|
||||
{
|
||||
let s = String::from_utf8_lossy(&output.stdout);
|
||||
for line in s.lines().skip(1) {
|
||||
let name = line.trim();
|
||||
if !name.is_empty() && name != "Microsoft Streaming Service Proxy" {
|
||||
audio_cards.push(name.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
use std::process::Command;
|
||||
|
||||
if let Ok(output) = Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg("lspci | grep -i 'Audio'")
|
||||
.output()
|
||||
{
|
||||
let s = String::from_utf8_lossy(&output.stdout);
|
||||
for line in s.lines() {
|
||||
if let Some(pos) = line.find(": ") {
|
||||
audio_cards.push(
|
||||
line[pos + 2..]
|
||||
.trim()
|
||||
.to_string()
|
||||
.replace("Advanced Micro Devices, Inc. [AMD/ATI]", "AMD")
|
||||
.replace("Advanced Micro Devices, Inc. [AMD]", "AMD"),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if audio_cards.is_empty() {
|
||||
vec!["No hardware audio found".into()]
|
||||
} else {
|
||||
// Deduplicate in case multiple logical devices refer to one controller
|
||||
audio_cards.dedup();
|
||||
audio_cards
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user