Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions crates/asm/src/darwin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,35 @@ pub fn macos_meminfo() -> Option<(u64, u64)> {
Some((used.min(total), total))
}

/// Mirror of `struct xsw_usage` (`<sys/sysctl.h>`), the `vm.swapusage` value.
#[repr(C)]
#[derive(Default)]
struct XswUsage {
total: u64,
avail: u64,
used: u64,
pagesize: u32,
encrypted: i32,
}

/// Returns `(used_bytes, total_bytes)` of swap from `vm.swapusage`.
#[must_use = "this only queries the kernel"]
pub fn macos_swapinfo() -> Option<(u64, u64)> {
let mut usage = XswUsage::default();
let mut len = size_of::<XswUsage>();
let ret = unsafe {
sysctlbyname(
c"vm.swapusage".as_ptr(),
ptr::from_mut(&mut usage).cast::<c_void>(),
&raw mut len,
ptr::null(),
0,
)
};
(ret == 0_i32 && len == size_of::<XswUsage>())
.then_some((usage.used, usage.total))
}

/// `struct timeval` (`time_t` is 64-bit, `suseconds_t` is 32-bit on macOS).
#[repr(C)]
#[derive(Default)]
Expand Down
13 changes: 11 additions & 2 deletions crates/benchmarks/benches/microfetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use microfetch_lib::{
cpu,
desktop,
release,
system,
system::{self, Memory},
uptime,
};

Expand Down Expand Up @@ -36,6 +36,14 @@ fn main_benchmark(criterion: &mut Criterion) {
black_box(writer.written());
});
});
criterion.bench_function("machine", |bencher| {
bencher.iter(|| {
let mut buf = [MaybeUninit::uninit(); 256];
let mut writer = StackWriter::new(&mut buf);
release::write_machine(&mut writer);
black_box(writer.written());
});
});
criterion.bench_function("kernel_version", |bencher| {
bencher.iter(|| {
let mut buf = [MaybeUninit::uninit(); 256];
Expand Down Expand Up @@ -88,7 +96,8 @@ fn main_benchmark(criterion: &mut Criterion) {
bencher.iter(|| {
let mut buf = [MaybeUninit::uninit(); 256];
let mut writer = StackWriter::new(&mut buf);
system::write_memory_usage(&mut writer, &colors);
let memory = Memory::read();
system::write_memory_usage(&mut writer, &colors, memory.as_ref());
black_box(writer.written());
});
});
Expand Down
80 changes: 44 additions & 36 deletions crates/lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ use core::{

use microfetch_asm::{UtsNameBuf, sys_uname, sys_write};

use crate::system::Memory;

/// A simple error type for microfetch operations.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Error {
Expand Down Expand Up @@ -252,7 +254,7 @@ impl<'buf> StackWriter<'buf> {
}

/// Custom logo art embedded at compile time via the `MICROFETCH_LOGO`
/// environment variable. Set it to 11 newline-separated lines of ASCII/Unicode
/// environment variable. Set it to 13 newline-separated lines of ASCII/Unicode
/// art when building to replace the default NixOS logo:
///
/// ```sh
Expand All @@ -268,17 +270,19 @@ const CUSTOM_LOGO: &str = match option_env!("MICROFETCH_LOGO") {

/// Packed logo rows. `0` separates rows; `1` and `2` select colors.
const LOGO: &[u8] = concat!(
"\x01⠀⠀⠀⠀⠀⠀⢼⣿⣄⠀⠀⠀\x02⠹⣿⣷⡀⠀⣠⣿⡧⠀⠀⠀⠀⠀⠀\0",
"\x01⠀⠀⠀⠀⠀⠀⠈⢿⣿⣆⠀⠀⠀\x02⠘⣿⣿⣴⣿⡿⠁⠀⠀⠀⠀⠀⠀\0",
"\x01⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⡜\x02⢿⣿⣟⠀⠀⠀\x01⢀⡄⠀⠀⠀\0",
"\x01⠀⠀⠀⠉⠉⠉⠉\x02⣩⣭⡭\x01⠉⠉⠉⠉⠉\x02⠈⢿⣿⣆⠀\x01⢠⣿⣿⠂⠀⠀\0",
"\x02⠀⠀⠀⠀⠀⠀⣼⣿⡟⠀⠀⠀⠀⠀⠀⠀⠀⢻⡟\x01⣡⣿⣿⠃⠀⠀⠀\0",
"\x02⢸⣿⣿⣿⣿⣿⣿⠏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\x01⣰⣿⣿⣿⣿⣿⣿⡇\0",
"\x02⠀⠀⠀⢠⣿⣿⢋\x01⣼⣧⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⡟⠀⠀⠀⠀⠀⠀\0",
"\x02⠀⠀⠠⣿⣿⠃⠀\x01⠹⣿⣷⡀\x02⣀⣀⣀⣀⣀\x01⣚⣛⣋\x02⣀⣀⣀⣀⠀⠀⠀\0",
"\x02⠀⠀⠀⠘⠁⠀⠀⠀\x01⣽⣿⣷⡜\x02⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠃⠀⠀⠀\0",
"\x01⠀⠀⠀⠀⠀⠀⢀⣾⣿⠟⣿⣿⡄⠀⠀⠀\x02⠹⣿⣷⡀⠀⠀⠀⠀⠀⠀\0",
"\x01⠀⠀⠀⠀⠀⠀⢺⣿⠋⠀⠈⢿⣿⣆⠀⠀⠀\x02⠙⣿⡗⠀⠀⠀⠀⠀⠀",
"\x01⠀⠀⠀⠀⠀⠀⠀⣼⣿⣦⠀⠀⠀⠀\x02⢿⣿⣷⡄⠀⢀⣴⣿⣦⠀⠀⠀⠀⠀⠀⠀\0",
"\x01⠀⠀⠀⠀⠀⠀⠀⠙⣿⣿⣷⡀⠀⠀\x02⠈⢻⣿⣿⣆⣾⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀\0",
"\x01⠀⠀⠀⠀⢠⣤⣤⣤⣼⣿⣿⣷⣤⣤⣤⣤\x02⢻⣿⣿⣿⡿⠁⠀⠀⠀\x01⡀⠀⠀⠀⠀\0",
"\x01⠀⠀⠀⠠⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠷\x02⠹⣿⣿⣧⠀⠀\x01⢀⣼⣷⡄⠀⠀⠀\0",
"\x02⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⠃⠀⠀⠀⠀⠀⠀⠹⣿⣿⣧\x01⢀⣾⣿⣿⠃⠀⠀⠀\0",
"\x02⠀⣀⣀⣀⣀⣀⣠⣾⣿⡿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⠏\x01⣿⣿⣿⣁⣀⣀⣀⠀\0",
"\x02⠰⣿⣿⣿⣿⣿⣿⣿⡿\x01⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣿⠂\0",
"\x02⠀⠈⠉⠉⣹⣿⣿⡟\x01⣼⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⡟⠁⠀⠀⠀⠀⠀⠀\0",
"\x02⠀⠀⠀⣰⣿⣿⡟⠀\x01⢻⣿⣿⣆⠀⠀⠀⠀⠀⠀⠴⠿⠿⠟⠀⠀⠀⠀⠀⠀⠀⠀\0",
"\x02⠀⠀⠀⠈⢿⠏⠀⠀⠀\x01⢻⣿⣿⣧\x02⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠁⠀⠀⠀\0",
"\x01⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⣧\x02⠉⠉⠉⠉⢿⣿⣿⣏⠉⠉⠉⠀⠀⠀⠀⠀\0",
"\x01⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⡟⠙⣿⣿⣷⡀⠀⠀⠀\x02⢻⣿⣿⣆⠀⠀⠀⠀⠀⠀⠀\0",
"\x01⠀⠀⠀⠀⠀⠀⠀⠹⠿⠏⠀⠀⠘⠿⠿⠷⠀⠀⠀⠀\x02⠻⠿⠏⠀⠀⠀⠀⠀⠀⠀",
)
.as_bytes();

Expand Down Expand Up @@ -313,39 +317,33 @@ fn write_styled_row(
}
}

const ROW_COUNT: usize = 11;
const ROW_COUNT: usize = 13;
const ROW_LABELS: &[u8] = concat!(
"\x02\u{F313} \x01System\x03 \u{E621} \0",
"\x02\u{F108} \x01Machine\x03 \u{E621} \0",
"\x02\u{E712} \x01Kernel\x03 \u{E621} \0",
"\x02\u{F2DB} \x01CPU\x03 \u{E621} \0",
"\x02\u{F4BC} \x01Topology\x03 \u{E621} \0",
"\x02\u{E795} \x01Shell\x03 \u{E621} \0",
"\x02\u{F017} \x01Uptime\x03 \u{E621} \0",
"\x02\u{F2D2} \x01Desktop\x03 \u{E621} \0",
"\x02\u{F035B} \x01Memory\x03 \u{E621} \0",
"\x02\u{F04E1} \x01Swap\x03 \u{E621} \0",
"\x02\u{F194E} \x01Storage (/)\x03 \u{E621} \0",
"\x02\u{E22B} \x01Colors\x03 \u{E621} \0",
)
.as_bytes();

/// Write one row: logo + label + value.
/// Write the label and value of one row, after its logo line.
#[inline(never)]
fn write_row(
writer: &mut StackWriter,
colors: &colors::Colors,
row: usize,
custom_logo: Option<&str>,
logo: &mut &[u8],
labels: &mut &[u8],
utsname: &UtsName,
memory: Option<&Memory>,
) {
writer.push_str(" ");
if let Some(logo_text) = custom_logo {
writer.push_str(colors.cyan);
writer.push_str(logo_text);
} else {
write_styled_row(writer, colors, logo);
}
writer.push_str(colors.reset);
writer.push_str(" ");
if row != 0 {
Expand All @@ -358,14 +356,16 @@ fn write_row(
writer.push_str(colors.reset);
},
1 => release::write_os_pretty_name(writer),
2 => release::write_system_info(writer, utsname),
3 => cpu::write_cpu_name(writer),
4 => cpu::write_cpu_cores(writer),
5 => system::write_shell(writer),
6 => uptime::write(writer),
7 => desktop::write_desktop_info(writer),
8 => system::write_memory_usage(writer, colors),
9 => system::write_root_disk_usage(writer, colors),
2 => release::write_machine(writer),
3 => release::write_system_info(writer, utsname),
4 => cpu::write_cpu_name(writer),
5 => cpu::write_cpu_cores(writer),
6 => system::write_shell(writer),
7 => uptime::write(writer),
8 => desktop::write_desktop_info(writer),
9 => system::write_memory_usage(writer, colors, memory),
10 => system::write_swap_usage(writer, colors, memory),
11 => system::write_root_disk_usage(writer, colors),
_ => colors::write_dots(writer, colors),
}
writer.push_byte(b'\n');
Expand Down Expand Up @@ -429,14 +429,15 @@ pub unsafe fn run(argc: i32, argv: *const *const u8) -> Result<(), Error> {
}

let utsname = UtsName::uname()?;
let memory = Memory::read();
let no_color = colors::is_no_color();
let colors = colors::Colors::new(no_color);

let mut buf = [MaybeUninit::uninit(); 2560];
let mut buf = [MaybeUninit::uninit(); 3072];
let mut writer = StackWriter::new(&mut buf);

// Custom logo is 11 lines from MICROFETCH_LOGO env var, one per info row.
// Lines beyond 11 are ignored; missing lines render as empty.
// Custom logo is 13 lines from MICROFETCH_LOGO env var, one per info row.
// Lines beyond 13 are ignored; missing lines render as empty.
let custom_lines: [&str; ROW_COUNT];
let use_custom = !CUSTOM_LOGO.is_empty();
let logo_lines = if use_custom {
Expand All @@ -452,14 +453,21 @@ pub unsafe fn run(argc: i32, argv: *const *const u8) -> Result<(), Error> {
writer.push_byte(b'\n');

for (row, &line) in logo_lines.iter().enumerate() {
writer.push_str(" ");
if use_custom {
writer.push_str(colors.cyan);
writer.push_str(line);
} else {
write_styled_row(&mut writer, &colors, &mut logo);
}

write_row(
&mut writer,
&colors,
row,
use_custom.then_some(line),
&mut logo,
&mut labels,
&utsname,
memory.as_ref(),
);
}

Expand Down
60 changes: 60 additions & 0 deletions crates/lib/src/release.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,63 @@ pub fn write_os_pretty_name(writer: &mut StackWriter) {

writer.push_str("Unknown");
}

/// Writes the hardware model from `hw.model` (macOS), e.g. `Mac14,2`.
#[cfg(target_os = "macos")]
#[cfg_attr(feature = "hotpath", hotpath::measure)]
pub fn write_machine(writer: &mut StackWriter) {
use microfetch_asm::darwin::macos_sysctl_str;

let mut buf = [0_u8; 64];
match macos_sysctl_str(b"hw.model\0", &mut buf) {
Some(len) if len > 0 => writer.push_bytes(&buf[..len]),
_ => writer.push_str("Unknown"),
}
}

/// Writes the hardware model from the DMI product or board name, or the
/// devicetree model on boards without DMI.
#[cfg(target_os = "linux")]
#[cfg_attr(feature = "hotpath", hotpath::measure)]
pub fn write_machine(writer: &mut StackWriter) {
// https://github.com/fastfetch-cli/fastfetch/blob/2.70.0/src/common/impl/smbios.c#L7-L47
const PLACEHOLDERS: &[u8] = concat!(
"*to be filled\0*to be set\0*oem\0*o.e.m.\0*system product\0",
"*unknown product\0none\0system name\0system version\0default string\0",
"undefined\0not specified\0not applicable\0not defined\0not available\0",
"invalid\0type1productconfigid\0all series\0n/a\0unknown\0standard",
)
.as_bytes();

let mut buffer = [0_u8; 128];

for path in [
"/sys/devices/virtual/dmi/id/product_name",
"/sys/devices/virtual/dmi/id/board_name",
"/sys/firmware/devicetree/base/model",
] {
let Ok(len) = read_file_fast(path, &mut buffer) else {
continue;
};
let raw = &buffer[..len];
let value = raw.strip_suffix(b"\0").unwrap_or(raw).trim_ascii();

let placeholder = value.is_empty()
|| PLACEHOLDERS.split(|&byte| byte == 0).any(|entry| {
let (pattern, is_prefix) = entry
.strip_prefix(b"*")
.map_or((entry, false), |pattern| (pattern, true));
(is_prefix || value.len() == pattern.len())
&& value
.get(..pattern.len())
.is_some_and(|head| head.eq_ignore_ascii_case(pattern))
});

if !placeholder {
writer.push_bytes(value);
return;
}
}

writer.push_str("Unknown");
}
Loading
Loading