From 50918476f31bb07bfd9eddb6939f3687c5302ff6 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Wed, 4 Jul 2018 17:22:41 +0200 Subject: [PATCH] Add a sysinfo wrapper --- CHANGELOG.md | 2 ++ src/sys/mod.rs | 3 ++ src/sys/sysinfo.rs | 73 ++++++++++++++++++++++++++++++++++++++++ test/sys/mod.rs | 2 ++ test/sys/test_sysinfo.rs | 18 ++++++++++ 5 files changed, 98 insertions(+) create mode 100644 src/sys/sysinfo.rs create mode 100644 test/sys/test_sysinfo.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 240054bb5a..ba0eefcc9f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] ### Added +- Added a `sysinfo` wrapper. + ([#922](https://github.com/nix-rust/nix/pull/922)) ### Changed diff --git a/src/sys/mod.rs b/src/sys/mod.rs index e75e9d88dc..e6c7880c1e 100644 --- a/src/sys/mod.rs +++ b/src/sys/mod.rs @@ -70,6 +70,9 @@ pub mod statfs; pub mod statvfs; +#[cfg(any(target_os = "android", target_os = "linux"))] +pub mod sysinfo; + pub mod termios; pub mod time; diff --git a/src/sys/sysinfo.rs b/src/sys/sysinfo.rs new file mode 100644 index 0000000000..98ef7bd517 --- /dev/null +++ b/src/sys/sysinfo.rs @@ -0,0 +1,73 @@ +use libc::{self, SI_LOAD_SHIFT}; +use std::{cmp, mem}; +use std::time::Duration; + +use Result; +use errno::Errno; + +/// System info structure returned by `sysinfo`. +#[derive(Copy, Clone)] +#[allow(missing_debug_implementations)] // libc::sysinfo doesn't impl Debug +pub struct SysInfo(libc::sysinfo); + +impl SysInfo { + /// Returns the load average tuple. + /// + /// The returned values represent the load average over time intervals of + /// 1, 5, and 15 minutes, respectively. + pub fn load_average(&self) -> (f64, f64, f64) { + ( + self.0.loads[0] as f64 / (1 << SI_LOAD_SHIFT) as f64, + self.0.loads[1] as f64 / (1 << SI_LOAD_SHIFT) as f64, + self.0.loads[2] as f64 / (1 << SI_LOAD_SHIFT) as f64, + ) + } + + /// Returns the time since system boot. + pub fn uptime(&self) -> Duration { + // Truncate negative values to 0 + Duration::from_secs(cmp::max(self.0.uptime, 0) as u64) + } + + /// Current number of processes. + pub fn process_count(&self) -> u16 { + self.0.procs + } + + /// Returns the amount of swap memory in Bytes. + pub fn swap_total(&self) -> u64 { + self.scale_mem(self.0.totalswap) + } + + /// Returns the amount of unused swap memory in Bytes. + pub fn swap_free(&self) -> u64 { + self.scale_mem(self.0.freeswap) + } + + /// Returns the total amount of installed RAM in Bytes. + pub fn ram_total(&self) -> u64 { + self.scale_mem(self.0.totalram) + } + + /// Returns the amount of completely unused RAM in Bytes. + /// + /// "Unused" in this context means that the RAM in neither actively used by + /// programs, nor by the operating system as disk cache or buffer. It is + /// "wasted" RAM since it currently serves no purpose. + pub fn ram_unused(&self) -> u64 { + self.scale_mem(self.0.freeram) + } + + fn scale_mem(&self, units: libc::c_ulong) -> u64 { + units as u64 * self.0.mem_unit as u64 + } +} + +/// Returns system information. +/// +/// [See `sysinfo(2)`](http://man7.org/linux/man-pages/man2/sysinfo.2.html). +pub fn sysinfo() -> Result { + let mut info: libc::sysinfo = unsafe { mem::uninitialized() }; + let res = unsafe { libc::sysinfo(&mut info) }; + Errno::result(res).map(|_| SysInfo(info)) +} diff --git a/test/sys/mod.rs b/test/sys/mod.rs index 1b3e67aa9f..bdc079d84c 100644 --- a/test/sys/mod.rs +++ b/test/sys/mod.rs @@ -16,6 +16,8 @@ mod test_signalfd; mod test_socket; mod test_sockopt; mod test_select; +#[cfg(any(target_os = "android", target_os = "linux"))] +mod test_sysinfo; mod test_termios; mod test_ioctl; mod test_wait; diff --git a/test/sys/test_sysinfo.rs b/test/sys/test_sysinfo.rs new file mode 100644 index 0000000000..73e6586f62 --- /dev/null +++ b/test/sys/test_sysinfo.rs @@ -0,0 +1,18 @@ +use nix::sys::sysinfo::*; + +#[test] +fn sysinfo_works() { + let info = sysinfo().unwrap(); + + let (l1, l5, l15) = info.load_average(); + assert!(l1 >= 0.0); + assert!(l5 >= 0.0); + assert!(l15 >= 0.0); + + info.uptime(); // just test Duration construction + + assert!(info.swap_free() <= info.swap_total(), + "more swap available than installed (free: {}, total: {})", + info.swap_free(), + info.swap_total()); +}