From 970dccccd15fded78aa8ff6b6c48a15fb140a173 Mon Sep 17 00:00:00 2001 From: roblabla Date: Thu, 10 Dec 2020 16:41:18 +0000 Subject: [PATCH] Add usage --- heim-cpu/Cargo.toml | 1 + heim-cpu/src/lib.rs | 2 + heim-cpu/src/usage.rs | 89 +++++++++++++++++++++++++++++++++++++++++ heim-cpu/tests/smoke.rs | 5 +++ 4 files changed, 97 insertions(+) create mode 100644 heim-cpu/src/usage.rs diff --git a/heim-cpu/Cargo.toml b/heim-cpu/Cargo.toml index 7eb74d59..aab9677a 100644 --- a/heim-cpu/Cargo.toml +++ b/heim-cpu/Cargo.toml @@ -47,6 +47,7 @@ heim-derive = { version = "0.1.0-beta.1", path = "../heim-derive" } smol = "~1.2" futures = "~0.3" version-sync = "0.9" +futures-timer = "^3.0" [package.metadata.docs.rs] rustdoc-args = ["--cfg", "docsrs"] diff --git a/heim-cpu/src/lib.rs b/heim-cpu/src/lib.rs index 8e057c4f..8d05f9dc 100644 --- a/heim-cpu/src/lib.rs +++ b/heim-cpu/src/lib.rs @@ -37,8 +37,10 @@ mod count; mod freq; mod stats; mod times; +mod usage; pub use self::count::*; pub use self::freq::*; pub use self::stats::*; pub use self::times::*; +pub use self::usage::*; diff --git a/heim-cpu/src/usage.rs b/heim-cpu/src/usage.rs new file mode 100644 index 00000000..efa17d00 --- /dev/null +++ b/heim-cpu/src/usage.rs @@ -0,0 +1,89 @@ +use std::ops; +use std::time::Instant; + +use heim_common::prelude::*; +use heim_common::units::{ratio, time, Ratio}; + +use super::{logical_count, time, CpuTime}; + +/// System CPU usage measurement. +/// +/// See [cpu_usage](./fn.cpu_usage.html) method for details. +#[derive(Debug, Clone)] +pub struct CpuUsage { + pub(crate) cpu_count: u64, + pub(crate) cpu_time: CpuTime, + pub(crate) at: Instant, +} + +impl ops::Sub for CpuUsage { + type Output = Ratio; + + #[allow(clippy::suspicious_arithmetic_impl, clippy::cast_lossless)] + fn sub(self, rhs: CpuUsage) -> Self::Output { + let delta_proc = (self.cpu_time.user() - rhs.cpu_time.user()) + + (self.cpu_time.system() - rhs.cpu_time.system()); + let delta_time = self.at - rhs.at; + + // TODO: Can be replaced with a `delta_time.as_secs_f64()` + // as soon as https://github.com/rust-lang/rust/issues/54361 will be stable + const NANOS_PER_SEC: u32 = 1_000_000_000; + let mut delta_time_secs = + (delta_time.as_secs() as f64) + (delta_time.as_nanos() as f64) / (NANOS_PER_SEC as f64); + + // Time should calculated across all the cores available + delta_time_secs *= self.cpu_count as f64; + + if delta_time_secs != 0.0 { + let overall_cpus_ratio = delta_proc.get::() / delta_time_secs; + let single_cpu_ratio = overall_cpus_ratio * self.cpu_count as f64; + + Ratio::new::(single_cpu_ratio as f32) + } else { + Ratio::new::(0.0) + } + } +} + +/// Returns CPU usage measurement. +/// +/// Returned [`CpuUsage`] struct represents instantaneous CPU usage and does not represent +/// any reasonable value by itself. +/// It is suggested to wait for a while with help of any async timer +/// (for accuracy recommended delay should be at least 100 ms), +/// call this method once again and subtract former [`CpuUsage`] from the new one. +/// +/// Same to any *nix system, calculated CPU usage might exceed 100 % +/// if the process is running multiple threads on different CPU cores. +/// +/// ## Example +/// +/// ```rust +/// # use std::time::Duration; +/// # use heim_common::units::ratio; +/// # use heim_common::prelude::*; +/// # use heim_cpu::usage; +/// # +/// # #[heim_derive::main] +/// # async fn main() -> Result<()> { +/// let measurement_1 = usage().await?; +/// // Or any other async timer at your choice +/// futures_timer::Delay::new(Duration::from_millis(100)).await; +/// let measurement_2 = usage().await?; +/// +/// println!("CPU usage: {} %", (measurement_2 - measurement_1).get::()); +/// # Ok(()) +/// # } +/// ``` +/// +/// [`CpuUsage`]: ./struct.CpuUsage.html +pub async fn usage() -> Result { + let (cpu_time, cpu_count) = + future::try_join(time(), logical_count().map_err(Into::into)).await?; + + Ok(CpuUsage { + cpu_count, + cpu_time, + at: Instant::now(), + }) +} diff --git a/heim-cpu/tests/smoke.rs b/heim-cpu/tests/smoke.rs index ac2573f2..ed8edd54 100644 --- a/heim-cpu/tests/smoke.rs +++ b/heim-cpu/tests/smoke.rs @@ -130,3 +130,8 @@ async fn smoke_cpu_physical_count() { assert!(cpus < 1024); // Some sane value till we will have proper unittests } } + +#[heim_derive::test] +async fn smoke_cpu_usage() { + let _measurement = cpu::usage().await.unwrap(); +}