#[cfg(any(target_os = "linux", target_os = "android"))]
mod android_linux;
#[cfg(any(target_os = "ios", target_os = "macos"))]
mod ios_macos;
#[cfg(target_os = "windows")]
mod windows;
#[cfg(any(target_os = "linux", target_os = "android"))]
use android_linux as platform;
#[cfg(any(target_os = "ios", target_os = "macos"))]
use ios_macos as platform;
#[cfg(target_os = "windows")]
use windows as platform;
pub use platform::{cpu_time, ThreadId};
use core::time::Duration;
use core::cell::Cell;
use std::time::Instant;
pub fn processor_numbers() -> std::io::Result<usize> {
Ok( num_cpus::get() )
}
pub struct ProcessStat {
pid: u32,
last_stat: Cell<(Duration, Instant)>,
}
impl ProcessStat {
pub fn current() -> anyhow::Result<Self> {
let cpu_time = platform::cpu_time()?;
let now = Instant::now();
Ok(ProcessStat {
pid: std::process::id(),
last_stat: Cell::new( (cpu_time, now) ),
})
}
#[deprecated]
pub fn cur() -> std::io::Result<Self> {
match Self::current() {
Ok(v) => Ok(v),
Err(e) => Err( std::io::Error::other(e) ),
}
}
pub fn cpu(&self) -> anyhow::Result<f64> {
let cpu_time = platform::cpu_time()?;
let now = Instant::now();
let (old_cpu_time, old_now) =
self.last_stat.replace(
(cpu_time, now)
);
let real_time: f64 =
now.saturating_duration_since(old_now)
.as_secs_f64();
let cpu_usage: f64 =
cpu_time.saturating_sub(old_cpu_time)
.as_secs_f64();
Ok(cpu_usage / real_time)
}
}
pub struct ThreadStat(platform::ThreadStat);
impl TryFrom<ThreadId> for ThreadStat {
type Error = anyhow::Error;
fn try_from(tid: ThreadId)
-> anyhow::Result<ThreadStat>
{
let stat: platform::ThreadStat =
tid.try_into()?;
Ok( ThreadStat(stat) )
}
}
impl ThreadStat {
pub fn current() -> anyhow::Result<Self> {
let stat = platform::ThreadStat::current()?;
Ok( Self(stat) )
}
#[deprecated]
pub fn cur() -> anyhow::Result<Self> {
Self::current()
}
#[deprecated]
pub fn build(tid: ThreadId) -> anyhow::Result<Self> {
tid.try_into()
}
pub fn cpu_usage(&self) -> anyhow::Result<f64> {
self.0.cpu_usage()
}
#[deprecated]
pub fn cpu(&self) -> std::io::Result<f64> {
self.0.cpu()
}
pub fn cpu_time(&self)
-> anyhow::Result<Duration>
{
self.0.cpu_time()
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
#[ignore]
fn test_process_usage() {
let stat = ProcessStat::current().unwrap();
std::thread::sleep(std::time::Duration::from_secs(1));
let usage = stat.cpu().unwrap();
assert!(usage < 0.01);
let num = processor_numbers().unwrap();
for _ in 0..num * 10 {
std::thread::spawn(move || loop {
let _ = (0..10_000_000).into_iter().sum::<u128>();
});
}
let stat = ProcessStat::current().unwrap();
std::thread::sleep(std::time::Duration::from_secs(1));
let usage = stat.cpu().unwrap();
assert!(usage > 0.9 * num as f64)
}
#[test]
fn test_thread_usage() {
let stat = ThreadStat::current().unwrap();
std::thread::sleep(std::time::Duration::from_secs(1));
let usage = stat.cpu().unwrap();
assert!(usage < 0.01);
let mut x = 1_000_000u64;
std::hint::black_box(&mut x);
let mut times = 1000u64;
std::hint::black_box(&mut times);
for i in 0..times {
let x = (0..x + i).into_iter().sum::<u64>();
std::hint::black_box(x);
}
let usage = stat.cpu().unwrap();
assert!(usage > 0.5)
}
}