#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(dead_code)]
use std::mem::size_of;
use std::os::raw::{c_int, c_ulong, c_void};
use std::ptr;
use crate::ported::linux::linuxmachine::{memory_t, ZfsArcStats};
use crate::ported::machine::{Machine, Machine_done};
#[repr(C)]
#[derive(Clone, Copy)]
pub struct CPUData {
pub userPercent: f64,
pub nicePercent: f64,
pub systemPercent: f64,
pub irqPercent: f64,
pub systemAllPercent: f64,
pub frequency: f64,
pub temperature: f64,
}
impl Default for CPUData {
fn default() -> Self {
CPUData {
userPercent: 0.0,
nicePercent: 0.0,
systemPercent: 0.0,
irqPercent: 0.0,
systemAllPercent: 0.0,
frequency: 0.0,
temperature: 0.0,
}
}
}
#[repr(C)]
pub struct FreeBSDMachine {
pub super_: Machine,
pub kd: *mut libc::kvm_t,
pub pageSize: c_int,
pub pageSizeKb: c_int,
pub kernelFScale: c_int,
pub wiredMem: memory_t,
pub buffersMem: memory_t,
pub activeMem: memory_t,
pub laundryMem: memory_t,
pub inactiveMem: memory_t,
pub arcMem: memory_t,
pub zfs: ZfsArcStats,
pub cpus: Vec<CPUData>,
pub cp_time_o: Vec<c_ulong>,
pub cp_time_n: Vec<c_ulong>,
pub cp_times_o: Vec<c_ulong>,
pub cp_times_n: Vec<c_ulong>,
pub MIB_hw_physmem: [c_int; 2],
pub MIB_vm_stats_vm_v_wire_count: [c_int; 4],
pub MIB_vm_stats_vm_v_active_count: [c_int; 4],
pub MIB_vm_stats_vm_v_laundry_count: [c_int; 4],
pub MIB_vm_stats_vm_v_inactive_count: [c_int; 4],
pub MIB_vfs_bufspace: [c_int; 2],
pub MIB_kern_cp_time: [c_int; 2],
pub MIB_kern_cp_times: [c_int; 2],
}
pub fn Machine_new() {
todo!("port of FreeBSDMachine.c:53 — needs base Machine_init (macos-gated in machine.rs)")
}
pub fn Machine_delete(mut this: Box<FreeBSDMachine>) {
Machine_done(&mut this.super_);
if !this.kd.is_null() {
unsafe { libc::kvm_close(this.kd) };
}
}
pub fn FreeBSDMachine_scanCPU(this: &mut FreeBSDMachine) {
let cpus = this.super_.existingCPUs; let mut maxcpu = cpus; debug_assert!(cpus > 0);
let cpustates = libc::CPUSTATES as usize;
let mut len = size_of::<c_ulong>() * cpustates;
unsafe {
libc::sysctl(
this.MIB_kern_cp_time.as_ptr() as *mut c_int,
2,
this.cp_time_n.as_mut_ptr() as *mut c_void,
&mut len,
ptr::null_mut(),
0,
);
}
if cpus > 1 {
maxcpu = cpus + 1;
let mut len = cpus as usize * size_of::<c_ulong>() * cpustates;
unsafe {
libc::sysctl(
this.MIB_kern_cp_times.as_ptr() as *mut c_int,
2,
this.cp_times_n.as_mut_ptr() as *mut c_void,
&mut len,
ptr::null_mut(),
0,
);
}
}
let show_temp = this
.super_
.settings
.as_ref()
.is_some_and(|s| s.showCPUTemperature);
let show_freq = this
.super_
.settings
.as_ref()
.is_some_and(|s| s.showCPUFrequency);
for i in 0..maxcpu {
let mut cp_time_p = [0.0f64; 8];
{
let (n, o): (&[c_ulong], &mut [c_ulong]) = if cpus == 1 || i == 0 {
(&this.cp_time_n, &mut this.cp_time_o)
} else {
let off = (i as usize - 1) * cpustates;
(
&this.cp_times_n[off..off + cpustates],
&mut this.cp_times_o[off..off + cpustates],
)
};
let mut total_o: u64 = 0;
let mut total_n: u64 = 0;
let mut cp_time_d = [0 as c_ulong; 8];
for s in 0..cpustates {
cp_time_d[s] = n[s].wrapping_sub(o[s]);
total_o += o[s] as u64;
total_n += n[s] as u64;
}
let mut total_d = total_n.wrapping_sub(total_o);
if total_d < 1 {
total_d = 1;
}
for s in 0..cpustates {
o[s] = n[s];
cp_time_p[s] = (cp_time_d[s] as f64) / (total_d as f64) * 100.0;
}
}
let cpuData = &mut this.cpus[i as usize];
cpuData.userPercent = cp_time_p[libc::CP_USER as usize];
cpuData.nicePercent = cp_time_p[libc::CP_NICE as usize];
cpuData.systemPercent = cp_time_p[libc::CP_SYS as usize];
cpuData.irqPercent = cp_time_p[libc::CP_INTR as usize];
cpuData.systemAllPercent =
cp_time_p[libc::CP_SYS as usize] + cp_time_p[libc::CP_INTR as usize];
cpuData.temperature = f64::NAN;
cpuData.frequency = f64::NAN;
let coreId = if cpus == 1 { 0 } else { i as i32 - 1 };
if coreId < 0 {
continue;
}
if show_temp {
let mut temperature: c_int = 0;
let mut len = size_of::<c_int>();
let mib = format!("dev.cpu.{}.temperature\0", coreId);
let r = unsafe {
libc::sysctlbyname(
mib.as_ptr() as *const libc::c_char,
&mut temperature as *mut c_int as *mut c_void,
&mut len,
ptr::null_mut(),
0,
)
};
if r == 0 {
cpuData.temperature = (temperature - 2732) as f64 / 10.0;
}
}
if show_freq {
let mut frequency: c_int = 0;
let mut len = size_of::<c_int>();
let mib = format!("dev.cpu.{}.freq\0", coreId);
let r = unsafe {
libc::sysctlbyname(
mib.as_ptr() as *const libc::c_char,
&mut frequency as *mut c_int as *mut c_void,
&mut len,
ptr::null_mut(),
0,
)
};
if r == 0 {
cpuData.frequency = frequency as f64; }
}
}
if cpus > 1 {
if show_temp {
let mut maxTemp = f64::NEG_INFINITY;
for i in 1..maxcpu as usize {
if this.cpus[i].temperature > maxTemp {
maxTemp = this.cpus[i].temperature;
this.cpus[0].temperature = maxTemp;
}
}
}
if show_freq {
let coreZeroFreq = this.cpus[1].frequency;
let mut freqSum = coreZeroFreq;
if coreZeroFreq >= 0.0 {
for i in 2..maxcpu as usize {
if !(this.cpus[i].frequency >= 0.0) {
this.cpus[i].frequency = coreZeroFreq;
}
freqSum += this.cpus[i].frequency;
}
this.cpus[0].frequency = freqSum / (maxcpu - 1) as f64;
}
}
}
}
pub fn FreeBSDMachine_scanMemoryInfo(this: &mut FreeBSDMachine) {
fn read_page_count(mib: &[c_int; 4]) -> memory_t {
let mut count: libc::c_uint = 0;
let mut len = size_of::<libc::c_uint>();
let r = unsafe {
libc::sysctl(
mib.as_ptr() as *mut c_int,
4,
&mut count as *mut libc::c_uint as *mut c_void,
&mut len,
ptr::null_mut(),
0,
)
};
if r == 0 && count > 0 {
count as memory_t
} else {
0
}
}
let page_kb = this.pageSizeKb as memory_t;
let mut totalMem: libc::c_ulong = 0;
let mut len = size_of::<libc::c_ulong>();
if unsafe {
libc::sysctl(
this.MIB_hw_physmem.as_ptr() as *mut c_int,
2,
&mut totalMem as *mut libc::c_ulong as *mut c_void,
&mut len,
ptr::null_mut(),
0,
)
} == 0
&& totalMem > 0
{
this.super_.totalMem = totalMem as u64 / 1024;
} else {
this.super_.totalMem = 0;
}
this.activeMem = read_page_count(&this.MIB_vm_stats_vm_v_active_count) * page_kb;
this.wiredMem = read_page_count(&this.MIB_vm_stats_vm_v_wire_count) * page_kb;
this.inactiveMem = read_page_count(&this.MIB_vm_stats_vm_v_inactive_count) * page_kb;
this.laundryMem = read_page_count(&this.MIB_vm_stats_vm_v_laundry_count) * page_kb;
let mut buffersMem: libc::c_long = 0;
let mut len = size_of::<libc::c_long>();
if unsafe {
libc::sysctl(
this.MIB_vfs_bufspace.as_ptr() as *mut c_int,
2,
&mut buffersMem as *mut libc::c_long as *mut c_void,
&mut len,
ptr::null_mut(),
0,
)
} == 0
&& buffersMem > 0
{
this.buffersMem = buffersMem as memory_t / 1024;
} else {
this.buffersMem = 0;
}
this.wiredMem = this.wiredMem.saturating_sub(this.buffersMem);
let mut swap: [libc::kvm_swap; 16] = unsafe { std::mem::zeroed() };
let nswap = unsafe { libc::kvm_getswapinfo(this.kd, swap.as_mut_ptr(), swap.len() as c_int, 0) };
this.super_.totalSwap = 0;
this.super_.usedSwap = 0;
for s in swap.iter().take(nswap.max(0) as usize) {
this.super_.totalSwap += s.ksw_total as u64;
this.super_.usedSwap += s.ksw_used as u64;
}
this.super_.totalSwap *= page_kb;
this.super_.usedSwap *= page_kb;
}
pub fn Machine_scan(this: &mut FreeBSDMachine) {
FreeBSDMachine_scanMemoryInfo(this);
FreeBSDMachine_scanCPU(this);
}
pub fn Machine_isCPUonline(host: &Machine, id: u32) -> bool {
debug_assert!(id < host.existingCPUs);
true
}
pub fn Machine_getCPUPhysicalCoreID(host: &Machine, id: u32) -> i32 {
debug_assert!(id < host.existingCPUs);
id as i32
}
pub fn Machine_getCPUThreadIndex(host: &Machine, id: u32) -> i32 {
debug_assert!(id < host.existingCPUs);
0
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn super_is_at_offset_zero() {
assert_eq!(core::mem::offset_of!(FreeBSDMachine, super_), 0);
}
}