added system info slimes

This commit is contained in:
2026-03-24 16:37:18 +01:00
parent fca667e380
commit 03b1b54299
6 changed files with 1616 additions and 54 deletions

View File

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

View File

@@ -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#"

View File

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

View File

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