Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,11 @@ mach = "0.3"
[build-dependencies]
bindgen = "0.59"
cc = "1.0"

[[bench]]
name = "cpu_ios_macos"
path = "benches/cpu/ios_macos.rs"
harness = false

[dev-dependencies]
criterion = "0.5.1"
72 changes: 72 additions & 0 deletions benches/cpu/ios_macos.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#[cfg(any(target_os = "ios", target_os = "macos"))]
mod tests {
use criterion::Criterion;
use libc::time_value_t;
use perf_monitor::{
cpu::ThreadId,
cpu::get_thread_basic_info
};
use std::{
convert::TryInto,
time::Instant,
time::Duration
};

#[inline]
fn time_value_to_u64(t: time_value_t) -> u64 {
(t.seconds.try_into().unwrap_or(0u64))
.saturating_mul(1_000_000)
.saturating_add(t.microseconds.try_into().unwrap_or(0u64))
}
// There is a field named `cpu_usage` in `thread_basic_info` which represents the CPU usage of the thread.
// However, we have no idea about how long the interval is. And it will make the API being different from other platforms.
// We calculate the usage instead of using the field directory to make the API is the same on all platforms.
// The cost of the calculation is very very small according to the result of the following benchmark.
pub fn bench_cpu_usage_by_calculate(c: &mut Criterion) {
c.bench_function("CPU usage by calculate", |b| {
let tid = ThreadId::current();
let last_stat = get_thread_basic_info(tid).unwrap();
let last_time = Instant::now();
b.iter(|| {
let cur_stat = get_thread_basic_info(tid).unwrap();
let cur_time = Instant::now();

let cur_user_time = time_value_to_u64(cur_stat.user_time);
let cur_sys_time = time_value_to_u64(cur_stat.system_time);
let last_user_time = time_value_to_u64(last_stat.user_time);
let last_sys_time = time_value_to_u64(last_stat.system_time);

let dt_duration = cur_time - last_time;
let cpu_time_us = cur_user_time + cur_sys_time - last_user_time - last_sys_time;
let dt_wtime = Duration::from_micros(cpu_time_us);

let _ = (cur_stat, cur_time);
let _ = dt_wtime.as_micros() as f64 / dt_duration.as_micros() as f64;
});
});
}

pub fn bench_cpu_usage_by_field(c: &mut Criterion) {
c.bench_function("CPU usage by field", |b| {
let tid = ThreadId::current();
b.iter(|| {
let cur_stat = get_thread_basic_info(tid).unwrap();
let _ = cur_stat.cpu_usage / 1000;
});
});
}
}

#[cfg(any(target_os = "ios", target_os = "macos"))]
criterion::criterion_group!(
benches,
tests::bench_cpu_usage_by_calculate,
tests::bench_cpu_usage_by_field
);
#[cfg(any(target_os = "ios", target_os = "macos"))]
criterion::criterion_main!(benches);

#[cfg(not(any(target_os = "ios", target_os = "macos")))]
fn main() {
println!("This benchmark can only be run on iOS or MacOS.");
}
51 changes: 3 additions & 48 deletions src/cpu/ios_macos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,15 @@ use std::{
};

#[derive(Clone, Copy)]
pub struct ThreadId(u32);
pub struct ThreadId(pub u32);

impl ThreadId {
#[inline]
pub fn current() -> Self {
ThreadId(unsafe { mach_thread_self() })
}
}

fn get_thread_basic_info(ThreadId(tid): ThreadId) -> Result<thread_basic_info> {
pub fn get_thread_basic_info(ThreadId(tid): ThreadId) -> Result<thread_basic_info> {
let mut thread_basic_info = MaybeUninit::<thread_basic_info>::uninit();
let mut thread_info_cnt = THREAD_BASIC_INFO_COUNT;

Expand Down Expand Up @@ -111,48 +110,4 @@ pub fn cpu_time() -> Result<Duration> {
.saturating_add(time.ru_stime.tv_usec as u32)
.saturating_mul(1000);
Ok(Duration::new(sec, nsec))
}

#[cfg(test)]
#[allow(clippy::all, clippy::print_stdout)]
mod tests {
use super::*;
use test::Bencher;

// There is a field named `cpu_usage` in `thread_basic_info` which represents the CPU usage of the thread.
// However, we have no idea about how long the interval is. And it will make the API being different from other platforms.
// We calculate the usage instead of using the field directory to make the API is the same on all platforms.
// The cost of the calculation is very very small according to the result of the following benchmark.
#[bench]
fn bench_cpu_usage_by_calculate(b: &mut Bencher) {
let tid = ThreadId::current();
let last_stat = get_thread_basic_info(tid).unwrap();
let last_time = Instant::now();

b.iter(|| {
let cur_stat = get_thread_basic_info(tid).unwrap();
let cur_time = Instant::now();

let cur_user_time = time_value_to_u64(cur_stat.user_time);
let cur_sys_time = time_value_to_u64(cur_stat.system_time);
let last_user_time = time_value_to_u64(last_stat.user_time);
let last_sys_time = time_value_to_u64(last_stat.system_time);

let dt_duration = cur_time - last_time;
let cpu_time_us = cur_user_time + cur_sys_time - last_user_time - last_sys_time;
let dt_wtime = Duration::from_micros(cpu_time_us);

let _ = (cur_stat, cur_time);
let _ = dt_wtime.as_micros() as f64 / dt_duration.as_micros() as f64;
});
}

#[bench]
fn bench_cpu_usage_by_field(b: &mut Bencher) {
let tid = ThreadId::current();
b.iter(|| {
let cur_stat = get_thread_basic_info(tid).unwrap();
let _ = cur_stat.cpu_usage / 1000;
});
}
}
}
3 changes: 3 additions & 0 deletions src/cpu/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ use windows as platform;

pub use platform::{cpu_time, ThreadId};
pub use std::io::Result;
#[cfg(any(target_os = "ios", target_os = "macos"))]
pub use ios_macos::get_thread_basic_info;

use std::{
io, mem,
time::{Duration, Instant},
Expand Down
5 changes: 0 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,6 @@
//!

#![cfg_attr(test, allow(clippy::all, clippy::unwrap_used))]
#![cfg_attr(doc, feature(doc_cfg))]
#![cfg_attr(test, feature(test))]

#[cfg(test)]
extern crate test;

#[allow(warnings)]
#[cfg(any(target_os = "macos", target_os = "ios"))]
Expand Down