153 lines
4.8 KiB
Rust
153 lines
4.8 KiB
Rust
#![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};
|
|
use sleep::sleep;
|
|
use time::precise_time_ns;
|
|
|
|
#[cfg(target_os = "linux")]
|
|
use argparse::StoreTrue;
|
|
|
|
#[cfg(target_os = "linux")]
|
|
use sleep::set_priority;
|
|
|
|
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 output: String = "".to_string();
|
|
let mut file: Option<File> = None;
|
|
|
|
#[cfg(target_os = "linux")]
|
|
let mut realtime: bool = false;
|
|
|
|
#[cfg(target_os = "macos")]
|
|
let realtime: bool = false;
|
|
|
|
{
|
|
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");
|
|
#[cfg(target_os = "linux")]
|
|
ap.refer(&mut realtime).add_option(&["--rt"], StoreTrue, "Set realtime priority");
|
|
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 {
|
|
#[cfg(target_os = "linux")]
|
|
let ret = set_priority(99);
|
|
|
|
#[cfg(target_os = "macos")]
|
|
let ret = 0;
|
|
|
|
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 => {}
|
|
}
|
|
}
|
|
}
|