1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
extern crate regex;
extern crate separator;
extern crate time;

use std;
use std::fs::File;
use std::io::prelude::*;
use std::io::{Error, ErrorKind};

use self::regex::Regex;
use self::separator::Separatable;
use self::time::precise_time_ns;

#[derive(Debug)]
pub struct Measure {
    pub min: u64,
    pub max: u64,
    time: u64,
    last: u64,
    data: Vec<u64>,
    pub name: String,
}

impl Measure {
    /// Constructs a new `Measure`.
    ///
    /// # Parameter
    /// - `name` Name of measured component.
    pub fn new(name: String) -> Self {
        Measure {
            min: u64::max_value(),
            max: 0u64,
            time: 0u64,
            last: 0u64,
            data: Vec::with_capacity(1_000_000),
            name: name,
        }
    }

    /// Start measurement
    pub fn start(&mut self) {
        self.last = precise_time_ns();
    }

    /// Pause measurement
    pub fn pause(&mut self) {
        if self.last == 0 {
            #[cfg(debug_assertions)]
            println!("WARNING: {:?} pause called without start!", self);

            return;
        }

        self.time += self.time_diff();
    }

    /// Stop measurement and calculate time difference
    pub fn stop(&mut self) {
        if self.last == 0 {
            #[cfg(debug_assertions)]
            println!("WARNING: {:?} stop called without start!", self);

            return;
        }

        self.time += self.time_diff();
        self.data.push(self.time);

        if self.time < self.min {
            self.min = self.time;
        }

        if self.time > self.max {
            self.max = self.time;
        }

        self.time = 0u64;
        self.last = 0u64;
    }

    fn time_diff(&mut self) -> u64 {
        let current_time = precise_time_ns();
        let time_diff = current_time - self.last;
        self.last = current_time;

        time_diff
    }

    fn write_data(&self) -> std::io::Result<()> {
        let re = Regex::new(r"[^\w\-.]")
            .or(Err(Error::new(ErrorKind::Other, "Create filename regex failed.")))?;

        let file_name = format!("measure_{}.txt", self.name);
        let file_name = re.replace_all(file_name.as_str(), "_").to_string();
        println!("{}: Write data to {}", self.name, file_name);

        let mut file = File::create(file_name)?;

        for value in &self.data {
            file.write_fmt(format_args!("{}\n", value))?;
        }

        Ok(())
    }
}

impl Drop for Measure {
    /// Print measure results and write times to file
    fn drop(&mut self) {
        println!("{}:\n\tmin: {} ns\n\tmax: {} ns",
                 self.name,
                 self.min.separated_string(),
                 self.max.separated_string());

        if let Err(e) = self.write_data() {
            println!("{}: Write measure data failed: {}", self.name, e);
        }
    }
}