hbs_acc/
lib.rs

1extern crate libc;
2extern crate hbs_acc_sys;
3
4use hbs_acc_sys::*;
5use std::mem;
6use std::io::{self, Write};
7use std::fs::File;
8
9pub use hbs_acc_sys::heartbeat_acc_context as HeartbeatAccContext;
10pub use hbs_acc_sys::heartbeat_acc_record as HeartbeatAccRecord;
11pub use hbs_acc_sys::heartbeat_acc_window_complete as HeartbeatAccWindowComplete;
12
13/// Contains the Heartbeat and its window data buffer.
14pub struct HeartbeatAcc {
15    pub hb: HeartbeatAccContext,
16    pub hbr: Vec<HeartbeatAccRecord>,
17    pub log: Option<File>,
18}
19
20impl HeartbeatAcc {
21    /// Allocate and initialize a new `Heartbeat`.
22    pub fn new(window_size: usize,
23               hwc_callback: Option<HeartbeatAccWindowComplete>,
24               mut log: Option<File>) -> Result<HeartbeatAcc, &'static str> {
25        let mut hbr: Vec<HeartbeatAccRecord> = Vec::with_capacity(window_size);
26        let hb: HeartbeatAccContext = unsafe {
27            // must explicitly set size so we can read data later
28            // (Rust isn't aware of native code modifying the buffer)
29            hbr.set_len(window_size);
30            let mut hb = mem::uninitialized();
31            match heartbeat_acc_init(&mut hb,
32                                     hbr.capacity() as u64,
33                                     hbr.as_mut_ptr(),
34                                     -1,
35                                     hwc_callback) {
36                0 => hb,
37                _ => return Err("Failed to initialize heartbeat")
38            }
39        };
40        // write header to log file if there is one
41        if let Some(ref mut l) = log {
42            l.write_all(format!("{:6} {:6} \
43                         {:11} {:11} {:11} \
44                         {:15} {:15} {:20} {:20} \
45                         {:15} {:15} {:15} \
46                         {:15} {:15} {:15} \
47                         {:15} {:15} {}\n",
48                        "HB", "Tag",
49                        "Global_Work", "Window_Work", "Work",
50                        "Global_Time", "Window_Time", "Start_Time", "End_Time",
51                        "Global_Perf", "Window_Perf", "Instant_Perf",
52                        "Global_Acc", "Window_Acc", "Acc",
53                        "Global_Acc_Rate", "Window_Acc_Rate", "Instant_Acc_Rate")
54                        .as_bytes()).unwrap()
55        }
56        Ok(HeartbeatAcc { hb: hb, hbr: hbr, log: log, })
57    }
58
59    /// Issue a heartbeat
60    pub fn heartbeat(&mut self,
61                     tag: u64,
62                     work: u64,
63                     start_time: u64,
64                     end_time: u64,
65                     accuracy: u64) {
66        unsafe {
67            heartbeat_acc(&mut self.hb, tag, work, start_time, end_time, accuracy)
68        }
69    }
70
71    fn write_log(r: &HeartbeatAccRecord, l: &mut File) -> io::Result<usize> {
72        l.write(format!("{:<6} {:<6} \
73                         {:<11} {:<11} {:<11} \
74                         {:<15} {:<15} {:<20} {:<20} \
75                         {:<15.6} {:<15.6} {:<15.6} \
76                         {:<15} {:<15} {:<15} \
77                         {:<15.6} {:<15.6} {:<.6}\n",
78                        r.id, r.user_tag,
79                        r.wd.global, r.wd.window, r.work,
80                        r.td.global, r.td.window, r.start_time, r.end_time,
81                        r.perf.global, r.perf.window, r.perf.instant,
82                        r.ad.global, r.ad.window, r.accuracy,
83                        r.acc.global, r.acc.window, r.acc.instant).as_bytes())
84    }
85
86    /// Rust-only function that logs the buffer (up to buffer_index) to a file.
87    pub fn log_to_buffer_index(&mut self) -> io::Result<()> {
88        match self.log {
89            Some(ref mut l) => {
90                for i in 0..self.hb.ws.buffer_index {
91                    match HeartbeatAcc::write_log(self.hbr.get(i as usize).unwrap(), l) {
92                        Ok(_) => (),
93                        Err(e) => return Err(e),
94                    }
95                }
96                l.flush()
97            }
98            None => Ok(())
99        }
100    }
101
102    pub fn get_window_size(&self) -> u64 {
103        unsafe {
104            hb_acc_get_window_size(&self.hb)
105        }
106    }
107
108    pub fn get_user_tag(&self) -> u64 {
109        unsafe {
110            hb_acc_get_user_tag(&self.hb)
111        }
112    }
113
114    pub fn get_global_time(&self) -> u64 {
115        unsafe {
116            hb_acc_get_global_time(&self.hb)
117        }
118    }
119
120    pub fn get_window_time(&self) -> u64 {
121        unsafe {
122            hb_acc_get_window_time(&self.hb)
123        }
124    }
125
126    pub fn get_global_work(&self) -> u64 {
127        unsafe {
128            hb_acc_get_global_work(&self.hb)
129        }
130    }
131
132    pub fn get_window_work(&self) -> u64 {
133        unsafe {
134            hb_acc_get_window_work(&self.hb)
135        }
136    }
137
138    pub fn get_global_perf(&self) -> f64 {
139        unsafe {
140            hb_acc_get_global_perf(&self.hb)
141        }
142    }
143
144    pub fn get_window_perf(&self) -> f64 {
145        unsafe {
146            hb_acc_get_window_perf(&self.hb)
147        }
148    }
149
150    pub fn get_instant_perf(&self) -> f64 {
151        unsafe {
152            hb_acc_get_instant_perf(&self.hb)
153        }
154    }
155
156    pub fn get_global_accuracy(&self) -> u64 {
157        unsafe {
158            hb_acc_get_global_accuracy(&self.hb)
159        }
160    }
161
162    pub fn get_window_accuracy(&self) -> u64 {
163        unsafe {
164            hb_acc_get_window_accuracy(&self.hb)
165        }
166    }
167
168    pub fn get_global_accuracy_rate(&self) -> f64 {
169        unsafe {
170            hb_acc_get_global_accuracy_rate(&self.hb)
171        }
172    }
173
174    pub fn get_window_accuracy_rate(&self) -> f64 {
175        unsafe {
176            hb_acc_get_window_accuracy_rate(&self.hb)
177        }
178    }
179
180    pub fn get_instant_accuracy_rate(&self) -> f64 {
181        unsafe {
182            hb_acc_get_instant_accuracy_rate(&self.hb)
183        }
184    }
185}
186
187#[cfg(test)]
188mod test {
189    use super::*;
190    use std::fs::File;
191
192    #[test]
193    fn test_simple() {
194        const TIME_INC: u64 = 1000000000;
195        let mut hb = HeartbeatAcc::new(5, None, None).unwrap();
196        let mut start_time: u64 = 0;
197        let mut end_time: u64 = TIME_INC;
198        for tag in 0..10 {
199            hb.heartbeat(tag, 1, start_time, end_time, 1);
200            start_time = end_time;
201            end_time += TIME_INC;
202        }
203    }
204
205    #[test]
206    fn test_callback() {
207        static mut received_cb: bool = false;
208        extern fn callback(_hb: *const HeartbeatAccContext) {
209            unsafe {
210                received_cb = true;
211            }
212        }
213
214        let mut hb = HeartbeatAcc::new(1, Some(callback), None).unwrap();
215        hb.heartbeat(0, 1, 0, 1000, 1);
216        unsafe {
217            assert!(received_cb);
218        }
219    }
220
221    #[test]
222    fn test_file() {
223        let mut hb = HeartbeatAcc::new(5, None, Some(File::create("foo.log").unwrap())).unwrap();
224        hb.heartbeat(0, 1, 0, 1000, 1);
225        hb.log_to_buffer_index().unwrap();
226    }
227}