Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a sysinfo wrapper #922

Merged
merged 1 commit into from Jul 5, 2018
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -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

Expand Down
3 changes: 3 additions & 0 deletions src/sys/mod.rs
Expand Up @@ -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;
Expand Down
73 changes: 73 additions & 0 deletions 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<SysInfo> {
let mut info: libc::sysinfo = unsafe { mem::uninitialized() };
let res = unsafe { libc::sysinfo(&mut info) };
Errno::result(res).map(|_| SysInfo(info))
}
2 changes: 2 additions & 0 deletions test/sys/mod.rs
Expand Up @@ -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;
Expand Down
18 changes: 18 additions & 0 deletions 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());
}