heartbeats_simple/
hbs_acc_pow.rs

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