#![feature(step_by)] extern crate argparse; extern crate sleep; extern crate time; use std::io::prelude::*; use std::fs::File; use std::path::Path; use std::time::Duration; use argparse::{ArgumentParser, Print, Store, StoreTrue}; use sleep::{set_priority, sleep}; use time::precise_time_ns; fn duration_from_ns(duration_ns: u64) -> Duration { Duration::new(duration_ns / 1_000_000_000, (duration_ns % 1_000_000_000) as u32) } fn duration_to_ns(duration: Duration) -> u64 { duration.as_secs() * 1_000_000_000u64 + duration.subsec_nanos() as u64 } fn measure_duration(sleep_duration: Duration) -> Duration { let start = precise_time_ns(); let remain = sleep(sleep_duration); let end = precise_time_ns(); #[cfg(debug_assertions)] println!("remain = {:?}", remain); let duration = end - start; let duration = duration_from_ns(duration); #[cfg(debug_assertions)] println!("duration = {:?}", duration); duration } fn measure_delay(sleep_duration: Duration) -> (Duration, Duration) { let duration = measure_duration(sleep_duration); let delay = duration - sleep_duration; #[cfg(debug_assertions)] println!("delay = {:?}", delay); (duration, delay) } fn measure_delay_loop(sleep_duration: Duration, count: u64) -> Vec<(Duration, Duration)> { println!("Starting measurment with period {}s {}ns for {} loops", sleep_duration.as_secs(), sleep_duration.subsec_nanos(), count); let mut data: Vec<(Duration, Duration)> = Vec::with_capacity(count as usize); for _ in 0..count { let (duration, delay) = measure_delay(sleep_duration); data.push((duration, delay)); #[cfg(debug_assertions)] print_delay(duration, delay); } data } fn print_delay(duration: Duration, delay: Duration) { println!("value: {} s {} ns\tdelay: {} s {} ns\trelativ delay = {:.2}%\traw_data: {:?}", duration.as_secs(), duration.subsec_nanos(), delay.as_secs(), delay.subsec_nanos(), (duration_to_ns(delay) * 100) as f64 / duration_to_ns(duration) as f64, delay); } fn main() { let mut min: u64 = 1_000_000; let mut max: u64 = 100_000_000; let mut step: u64 = 1_000_000; let mut count: u64 = 100; let mut realtime: bool = false; let mut output: String = "".to_string(); let mut file: Option = None; { let mut ap = ArgumentParser::new(); ap.set_description(env!("CARGO_PKG_DESCRIPTION")); ap.refer(&mut min) .add_option(&["--min"], Store, "Sleep period start"); ap.refer(&mut max) .add_option(&["--max"], Store, "Sleep period end"); ap.refer(&mut step) .add_option(&["--step"], Store, "Sleep period step size"); ap.refer(&mut count) .add_option(&["--loop"], Store, "Count of measurements per period"); ap.refer(&mut realtime) .add_option(&["--rt"], StoreTrue, "Output file"); ap.refer(&mut output) .add_option(&["-o", "--out"], Store, "Output file"); ap.add_option(&["-V", "--version"], Print(env!("CARGO_PKG_VERSION").to_string()), "Show version"); ap.parse_args_or_exit(); } if realtime { let ret = set_priority(99); if ret != 0 { panic!("Set realtime priority failed."); } } if output != "" { file = Some(File::create(Path::new(output.as_str())) .expect(format!("Open file '{}' failed", output).as_str())); } for duration in (min..max+1).step_by(step) { let data = measure_delay_loop(duration_from_ns(duration), count); let max_delay = data.iter().max().expect("Max delay not found"); #[cfg(debug_assertions)] println!("max_delay = {:?}", max_delay); print_delay(max_delay.0, max_delay.1); match file.as_ref() { Some(mut f) => { let value = format!("{: >9} {}\n", duration, duration_to_ns(max_delay.1)); f.write_all(value.as_bytes()) .expect(format!("Write value '{}' to '{}' file failed", value, output).as_str()); } None => {} } } }