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
13pub struct HeartbeatAcc {
15 pub hb: HeartbeatAccContext,
16 pub hbr: Vec<HeartbeatAccRecord>,
17 pub log: Option<File>,
18}
19
20impl HeartbeatAcc {
21 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 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 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 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 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}