1#![cfg_attr(all(coverage_nightly, test), feature(coverage_attribute))]
44#![cfg(unix)]
45#![deny(missing_docs)]
46#![deny(unsafe_code)]
47#![deny(unreachable_pub)]
48
49mod cpu;
50
51pub use cpu::Cpu;
52
53#[derive(Debug, thiserror::Error)]
55pub enum PprofError {
56 #[error(transparent)]
58 Io(#[from] std::io::Error),
59 #[error(transparent)]
61 Pprof(#[from] pprof::Error),
62}
63
64#[cfg(test)]
65#[cfg_attr(all(coverage_nightly, test), coverage(off))]
66mod tests {
67 use std::io::Read;
68 use std::time::SystemTime;
69
70 use flate2::read::GzDecoder;
71 use pprof::protos::Message;
72
73 use crate::Cpu;
74
75 #[test]
76 fn empty_profile() {
77 let before_nanos = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_nanos() as i64;
78
79 let cpu = Cpu::new::<String>(1000, &[]);
80 let profile = cpu.capture(std::time::Duration::from_secs(1)).unwrap();
81
82 let mut reader = GzDecoder::new(profile.as_slice());
84 let mut buf = Vec::new();
85 reader.read_to_end(&mut buf).unwrap();
86 let profile = pprof::protos::Profile::decode(buf.as_slice()).unwrap();
87
88 assert!(profile.duration_nanos > 1_000_000_000);
89 assert!(profile.time_nanos > before_nanos);
90 let now_nanos = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_nanos() as i64;
91 assert!(profile.time_nanos < now_nanos);
92
93 assert_eq!(profile.string_table[profile.drop_frames as usize], "");
94 assert_eq!(profile.string_table[profile.keep_frames as usize], "");
95
96 let Some(period_type) = profile.period_type else {
97 panic!("missing period type");
98 };
99 assert_eq!(profile.string_table[period_type.ty as usize], "cpu");
100 assert_eq!(profile.string_table[period_type.unit as usize], "nanoseconds");
101
102 assert_eq!(profile.period, 1_000_000);
103 }
104}