workflow_perf_monitor/cpu/
mod.rs1#[cfg(any(target_os = "linux", target_os = "android"))]
35mod android_linux;
36#[cfg(any(target_os = "ios", target_os = "macos"))]
37mod ios_macos;
38#[cfg(target_os = "windows")]
39mod windows;
40
41#[cfg(any(target_os = "linux", target_os = "android"))]
42use android_linux as platform;
43#[cfg(any(target_os = "ios", target_os = "macos"))]
44use ios_macos as platform;
45#[cfg(target_os = "windows")]
46use windows as platform;
47
48#[cfg(any(target_os = "ios", target_os = "macos"))]
49pub use ios_macos::get_thread_basic_info;
50pub use platform::{cpu_time, ThreadId};
51pub use std::io::Result;
52
53use std::{
54 io, mem,
55 time::{Duration, Instant},
56};
57
58pub fn processor_numbers() -> std::io::Result<usize> {
60 std::thread::available_parallelism().map(|x| x.get())
61}
62
63pub struct ProcessStat {
65 now: Instant,
66 cpu_time: Duration,
67}
68
69impl ProcessStat {
70 pub fn cur() -> io::Result<Self> {
72 Ok(ProcessStat {
73 now: Instant::now(),
74 cpu_time: platform::cpu_time()?,
75 })
76 }
77
78 pub fn cpu(&mut self) -> io::Result<f64> {
81 let old_time = mem::replace(&mut self.cpu_time, platform::cpu_time()?);
82 let old_now = mem::replace(&mut self.now, Instant::now());
83 let real_time = self.now.saturating_duration_since(old_now).as_secs_f64();
84 let cpu_time = self.cpu_time.saturating_sub(old_time).as_secs_f64();
85 Ok(cpu_time / real_time)
86 }
87}
88
89pub struct ThreadStat {
91 stat: platform::ThreadStat,
92}
93
94impl ThreadStat {
95 pub fn cur() -> Result<Self> {
97 Ok(ThreadStat {
98 stat: platform::ThreadStat::cur()?,
99 })
100 }
101
102 pub fn build(thread_id: ThreadId) -> Result<Self> {
107 Ok(ThreadStat {
108 stat: platform::ThreadStat::build(thread_id)?,
109 })
110 }
111
112 pub fn cpu(&mut self) -> Result<f64> {
115 self.stat.cpu()
116 }
117
118 pub fn cpu_time(&mut self) -> Result<Duration> {
121 self.stat.cpu_time()
122 }
123}
124
125#[cfg(test)]
126mod test {
127 use super::*;
128
129 #[test]
131 #[ignore]
132 fn test_process_usage() {
133 let mut stat = ProcessStat::cur().unwrap();
134
135 std::thread::sleep(std::time::Duration::from_secs(1));
136
137 let usage = stat.cpu().unwrap();
138
139 assert!(usage < 0.01);
140
141 let num = processor_numbers().unwrap();
142 for _ in 0..num * 10 {
143 std::thread::spawn(move || loop {
144 let _ = (0..10_000_000).into_iter().sum::<u128>();
145 });
146 }
147
148 let mut stat = ProcessStat::cur().unwrap();
149
150 std::thread::sleep(std::time::Duration::from_secs(1));
151
152 let usage = stat.cpu().unwrap();
153
154 assert!(usage > 0.9 * num as f64)
155 }
156
157 #[test]
158 fn test_thread_usage() {
159 let mut stat = ThreadStat::cur().unwrap();
160
161 std::thread::sleep(std::time::Duration::from_secs(1));
162 let usage = stat.cpu().unwrap();
163 assert!(usage < 0.01);
164
165 let mut x = 1_000_000u64;
166 std::hint::black_box(&mut x);
167 let mut times = 1000u64;
168 std::hint::black_box(&mut times);
169 for i in 0..times {
170 let x = (0..x + i).into_iter().sum::<u64>();
171 std::hint::black_box(x);
172 }
173 let usage = stat.cpu().unwrap();
174 assert!(usage > 0.5)
175 }
176}