hbs_acc_pow/
lib.rs

1extern crate libc;
2extern crate hbs_acc_pow_sys;
3
4use hbs_acc_pow_sys::*;
5use std::mem;
6use std::io::{self, Write};
7use std::fs::File;
8
9pub use hbs_acc_pow_sys::heartbeat_acc_pow_context as HeartbeatAccPowContext;
10pub use hbs_acc_pow_sys::heartbeat_acc_pow_record as HeartbeatAccPowRecord;
11pub use hbs_acc_pow_sys::heartbeat_acc_pow_window_complete as HeartbeatAccPowWindowComplete;
12
13/// Contains the Heartbeat and its window data buffer.
14pub struct HeartbeatAccPow {
15    pub hb: HeartbeatAccPowContext,
16    pub hbr: Vec<HeartbeatAccPowRecord>,
17    pub log: Option<File>,
18}
19
20impl HeartbeatAccPow {
21    /// Allocate and initialize a new `Heartbeat`.
22    pub fn new(window_size: usize,
23               hwc_callback: Option<HeartbeatAccPowWindowComplete>,
24               mut log: Option<File>) -> Result<HeartbeatAccPow, &'static str> {
25        let mut hbr: Vec<HeartbeatAccPowRecord> = Vec::with_capacity(window_size);
26        let hb: HeartbeatAccPowContext = 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_pow_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(HeartbeatAccPow { 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                     start_energy: u64,
67                     end_energy: u64) {
68        unsafe {
69            heartbeat_acc_pow(&mut self.hb,
70                              tag,
71                              work,
72                              start_time,
73                              end_time,
74                              accuracy,
75                              start_energy,
76                              end_energy)
77        }
78    }
79
80    fn write_log(r: &HeartbeatAccPowRecord, l: &mut File) -> io::Result<usize> {
81        l.write(format!("{:<6} {:<6} \
82                         {:<11} {:<11} {:<11} \
83                         {:<15} {:<15} {:<20} {:<20} \
84                         {:<15.6} {:<15.6} {:<15.6} \
85                         {:<15} {:<15} {:<15} \
86                         {:<15.6} {:<15.6} {:<.6}\n",
87                        r.id, r.user_tag,
88                        r.wd.global, r.wd.window, r.work,
89                        r.td.global, r.td.window, r.start_time, r.end_time,
90                        r.perf.global, r.perf.window, r.perf.instant,
91                        r.ad.global, r.ad.window, r.accuracy,
92                        r.acc.global, r.acc.window, r.acc.instant).as_bytes())
93    }
94
95    /// Rust-only function that logs the buffer (up to buffer_index) to a file.
96    pub fn log_to_buffer_index(&mut self) -> io::Result<()> {
97        match self.log {
98            Some(ref mut l) => {
99                for i in 0..self.hb.ws.buffer_index {
100                    match HeartbeatAccPow::write_log(self.hbr.get(i as usize).unwrap(), l) {
101                        Ok(_) => (),
102                        Err(e) => return Err(e),
103                    }
104                }
105                l.flush()
106            }
107            None => Ok(())
108        }
109    }
110
111    pub fn get_window_size(&self) -> u64 {
112        unsafe {
113            hb_acc_pow_get_window_size(&self.hb)
114        }
115    }
116
117    pub fn get_user_tag(&self) -> u64 {
118        unsafe {
119            hb_acc_pow_get_user_tag(&self.hb)
120        }
121    }
122
123    pub fn get_global_time(&self) -> u64 {
124        unsafe {
125            hb_acc_pow_get_global_time(&self.hb)
126        }
127    }
128
129    pub fn get_window_time(&self) -> u64 {
130        unsafe {
131            hb_acc_pow_get_window_time(&self.hb)
132        }
133    }
134
135    pub fn get_global_work(&self) -> u64 {
136        unsafe {
137            hb_acc_pow_get_global_work(&self.hb)
138        }
139    }
140
141    pub fn get_window_work(&self) -> u64 {
142        unsafe {
143            hb_acc_pow_get_window_work(&self.hb)
144        }
145    }
146
147    pub fn get_global_perf(&self) -> f64 {
148        unsafe {
149            hb_acc_pow_get_global_perf(&self.hb)
150        }
151    }
152
153    pub fn get_window_perf(&self) -> f64 {
154        unsafe {
155            hb_acc_pow_get_window_perf(&self.hb)
156        }
157    }
158
159    pub fn get_instant_perf(&self) -> f64 {
160        unsafe {
161            hb_acc_pow_get_instant_perf(&self.hb)
162        }
163    }
164
165    pub fn get_global_accuracy(&self) -> u64 {
166        unsafe {
167            hb_acc_pow_get_global_accuracy(&self.hb)
168        }
169    }
170
171    pub fn get_window_accuracy(&self) -> u64 {
172        unsafe {
173            hb_acc_pow_get_window_accuracy(&self.hb)
174        }
175    }
176
177    pub fn get_global_accuracy_rate(&self) -> f64 {
178        unsafe {
179            hb_acc_pow_get_global_accuracy_rate(&self.hb)
180        }
181    }
182
183    pub fn get_window_accuracy_rate(&self) -> f64 {
184        unsafe {
185            hb_acc_pow_get_window_accuracy_rate(&self.hb)
186        }
187    }
188
189    pub fn get_instant_accuracy_rate(&self) -> f64 {
190        unsafe {
191            hb_acc_pow_get_instant_accuracy_rate(&self.hb)
192        }
193    }
194
195    pub fn get_global_energy(&self) -> u64 {
196        unsafe {
197            hb_acc_pow_get_global_energy(&self.hb)
198        }
199    }
200
201    pub fn get_window_energy(&self) -> u64 {
202        unsafe {
203            hb_acc_pow_get_window_energy(&self.hb)
204        }
205    }
206
207    pub fn get_global_power(&self) -> f64 {
208        unsafe {
209            hb_acc_pow_get_global_power(&self.hb)
210        }
211    }
212
213    pub fn get_window_power(&self) -> f64 {
214        unsafe {
215            hb_acc_pow_get_window_power(&self.hb)
216        }
217    }
218
219    pub fn get_instant_power(&self) -> f64 {
220        unsafe {
221            hb_acc_pow_get_instant_power(&self.hb)
222        }
223    }
224}
225
226#[cfg(test)]
227mod test {
228    use super::*;
229    use std::fs::File;
230
231    #[test]
232    fn test_simple() {
233        const TIME_INC: u64 = 1000000000;
234        const ENERGY_INC: u64 = 1000000;
235        let mut hb = HeartbeatAccPow::new(5, None, None).unwrap();
236        let mut start_time: u64 = 0;
237        let mut end_time: u64 = TIME_INC;
238        let mut start_energy: u64 = 0;
239        let mut end_energy: u64 = ENERGY_INC;
240        for tag in 0..10 {
241            hb.heartbeat(tag, 1, start_time, end_time, 1, start_energy, end_energy);
242            start_time = end_time;
243            end_time += TIME_INC;
244            start_energy = end_energy;
245            end_energy += ENERGY_INC;
246        }
247    }
248
249    #[test]
250    fn test_callback() {
251        static mut received_cb: bool = false;
252        extern fn callback(_hb: *const HeartbeatAccPowContext) {
253            unsafe {
254                received_cb = true;
255            }
256        }
257
258        let mut hb = HeartbeatAccPow::new(1, Some(callback), None).unwrap();
259        hb.heartbeat(0, 1, 0, 1000, 1, 0, 0);
260        unsafe {
261            assert!(received_cb);
262        }
263    }
264
265    #[test]
266    fn test_file() {
267        let mut hb = HeartbeatAccPow::new(5, None, Some(File::create("foo.log").unwrap())).unwrap();
268        hb.heartbeat(0, 1, 0, 1000, 1, 0, 0);
269        hb.log_to_buffer_index().unwrap();
270    }
271}