gondola_core/monitoring/heartbeats/
data_sink_hb.rs

1// This file is part of gaps-online-software and published 
2// under the GPLv3 license
3
4use crate::prelude::*;
5
6#[derive(Debug, Copy, Clone, PartialEq)]
7#[cfg_attr(feature="pybindings", pyclass)]
8pub struct DataSinkHB {
9
10  /// mission elapsed time in seconds
11  pub met                : u64,
12  pub n_packets_sent     : u64,
13  pub n_packets_incoming : u64,
14  /// bytes written to disk
15  pub n_bytes_written    : u64,
16  /// event id check - missing event ids
17  pub n_evid_missing     : u64,
18  /// event id check - chunksize
19  pub n_evid_chunksize   : u64,
20  /// length of incoming buffer for 
21  /// the thread
22  /// check for missing event ids
23  pub evid_missing       : u64,
24  /// probe size for missing event id check
25  pub evid_check_len     : u64,
26  /// number of packets written to disk
27  pub n_pack_write_disk  : u64,
28  /// length of the incoming channel, which 
29  /// is basically packets queued to be sent
30  pub incoming_ch_len    : u64,
31  // not seriealized 
32  pub timestamp          : u64,
33}
34
35impl DataSinkHB {
36
37  pub fn new() -> Self {
38    Self {
39      met                : 0,
40      n_packets_sent     : 0,
41      n_packets_incoming : 0,
42      n_bytes_written    : 0,
43      n_evid_missing     : 0,
44      n_evid_chunksize   : 0,
45      evid_missing       : 0,
46      evid_check_len     : 0,
47      n_pack_write_disk  : 0,
48      incoming_ch_len    : 0,
49      timestamp          : 0,
50    }
51  }
52
53  pub fn get_sent_packet_rate(&self) -> f64 {
54    if self.met == 0 {
55      return 0.0;
56    }
57    self.n_packets_sent as f64 /  self.met as f64
58  }
59
60  pub fn get_mbytes_to_disk_per_sec(&self) -> f64 {
61    if self.met == 0 {
62      return 0.0;
63    }
64    self.n_bytes_written as f64/(1e6 * self.met as f64)
65  }
66}
67
68impl Default for DataSinkHB {
69  fn default() -> Self {
70    Self::new()
71  }
72}
73  
74impl MoniData for DataSinkHB {
75  fn get_board_id(&self) -> u8 {
76    0
77  }
78  
79  fn get_timestamp(&self) -> u64 {
80    if self.timestamp == 0 {
81      return self.met;
82    } else {
83      return self.timestamp;
84    }
85  }
86
87  fn set_timestamp(&mut self, ts : u64) {
88    self.timestamp = ts;
89  }
90
91  /// Access the (data) members by name 
92  fn get(&self, varname : &str) -> Option<f32> {
93    match varname {
94    "board_id"           => Some(0.0),
95    "met"                => Some(self.met as f32),
96    "n_packets_sent"     => Some(self.n_packets_sent as f32),
97    "n_packets_incoming" => Some(self.n_packets_incoming as f32),
98    "n_bytes_written"    => Some(self.n_bytes_written as f32),
99    "n_evid_missing"     => Some(self.n_evid_missing as f32),
100    "n_evid_chunksize"   => Some(self.n_evid_chunksize as f32),
101    "evid_missing"       => Some(self.evid_missing as f32),
102    "evid_check_len"     => Some(self.evid_check_len as f32),
103    "n_pack_write_disk"  => Some(self.n_pack_write_disk as f32),
104    "incoming_ch_len"    => Some(self.incoming_ch_len as f32),
105    "timestamp"          => Some(self.timestamp as f32),
106    _                    => None
107    }
108  }
109
110  /// A list of the variables in this MoniData
111  fn keys() -> Vec<&'static str> {
112    vec!["board_id", "met", "n_packets_sent",
113         "n_packets_incoming", "n_bytes_written", "n_evid_missing",
114         "n_evid_chunksize", "evid_missing", "evid_check_len", 
115         "n_pack_write_disk", "incoming_ch_len", "timestamp"]
116  }
117}
118
119moniseries!(DataSinkHBSeries, DataSinkHB);
120
121//--------------------------------------------------------------
122
123#[cfg(feature="pybindings")]
124#[pymethods]
125impl DataSinkHB {
126
127  /// Mission elapsed time
128  #[getter]
129  fn get_met(&self) -> PyResult<u64> {
130    Ok(self.met)
131  }
132  
133  #[getter]
134  fn get_n_packets_sent(&self) -> PyResult<u64> {
135    Ok(self.n_packets_sent)
136  }
137  
138  #[getter]
139  fn get_n_packets_incoming(&self) -> PyResult<u64> {
140    Ok(self.n_packets_incoming)
141  }
142  
143  #[getter]
144  fn get_n_bytes_written(&self) -> PyResult<u64> {
145    Ok(self.n_bytes_written)
146  }
147  #[getter]
148  fn get_n_evid_chunksize(&self) -> PyResult<u64> {
149    Ok(self.n_evid_chunksize)
150  }
151  #[getter]
152  fn get_evid_missing(&self) -> PyResult<u64> {
153    Ok(self.evid_missing)
154  }
155  
156  #[getter]
157  fn get_evid_check_len(&self) -> PyResult<u64> {
158    Ok(self.evid_check_len)
159  }
160  
161  #[getter]
162  fn get_n_pack_write_disk(&self) -> PyResult<u64> {
163    Ok(self.n_pack_write_disk)
164  }  
165
166  #[getter]
167  #[pyo3(name="timestamp")]
168  fn get_timestamp_py(&self) -> PyResult<u64> {
169    Ok(self.timestamp) 
170  }
171}
172
173#[cfg(feature="pybindings")]
174pythonize_monidata!(DataSinkHB);
175#[cfg(feature="pybindings")]
176pythonize_packable!(DataSinkHB);
177
178//--------------------------------------------------------------
179
180impl TofPackable for DataSinkHB {
181  const TOF_PACKET_TYPE : TofPacketType = TofPacketType::DataSinkHB;
182}
183
184impl Serialization for DataSinkHB {
185  
186  const HEAD : u16 = 0xAAAA;
187  const TAIL : u16 = 0x5555;
188  const SIZE : usize = 84; 
189  
190  fn from_bytestream(stream    : &Vec<u8>, 
191                     pos       : &mut usize) 
192    -> Result<Self, SerializationError>{
193    Self::verify_fixed(stream, pos)?;  
194    let mut hb            = Self::new();
195    hb.met                = parse_u64(stream, pos);
196    hb.n_packets_sent     = parse_u64(stream, pos);
197    hb.n_packets_incoming = parse_u64(stream, pos);
198    hb.n_bytes_written    = parse_u64(stream, pos);
199    hb.n_evid_missing     = parse_u64(stream, pos);
200    hb.n_evid_chunksize   = parse_u64(stream, pos);
201    hb.evid_missing       = parse_u64(stream, pos);
202    hb.evid_check_len     = parse_u64(stream, pos);
203    hb.n_pack_write_disk  = parse_u64(stream, pos);
204    hb.incoming_ch_len    = parse_u64(stream, pos);
205    *pos += 2;
206    Ok(hb)
207  }
208  
209  fn to_bytestream(&self) -> Vec<u8> {
210    let mut bs = Vec::<u8>::with_capacity(Self::SIZE);
211    bs.extend_from_slice(&Self::HEAD.to_le_bytes());
212    bs.extend_from_slice(&self.met.to_le_bytes());
213    bs.extend_from_slice(&self.n_packets_sent.to_le_bytes());
214    bs.extend_from_slice(&self.n_packets_incoming.to_le_bytes());
215    bs.extend_from_slice(&self.n_bytes_written.to_le_bytes());
216    bs.extend_from_slice(&self.n_evid_missing.to_le_bytes());
217    bs.extend_from_slice(&self.n_evid_chunksize.to_le_bytes());
218    bs.extend_from_slice(&self.evid_missing     .to_le_bytes() );
219    bs.extend_from_slice(&self.evid_check_len   .to_le_bytes() );
220    bs.extend_from_slice(&self.n_pack_write_disk.to_le_bytes() );
221    bs.extend_from_slice(&self.incoming_ch_len.to_le_bytes());
222    bs.extend_from_slice(&Self::TAIL.to_le_bytes());
223    bs
224  }
225}
226
227#[cfg(feature = "random")]
228impl FromRandom for DataSinkHB {
229  fn from_random() -> Self {
230    let mut rng            = rand::rng();
231    Self {
232      met                : rng.random::<u64>(),
233      n_packets_sent     : rng.random::<u64>(),
234      n_packets_incoming : rng.random::<u64>(),
235      n_bytes_written    : rng.random::<u64>(),
236      n_evid_missing     : rng.random::<u64>(),
237      n_evid_chunksize   : rng.random::<u64>(),
238      evid_missing       : rng.random::<u64>(),
239      evid_check_len     : rng.random::<u64>(),
240      n_pack_write_disk  : rng.random::<u64>(),
241      incoming_ch_len    : rng.random::<u64>(),
242      timestamp          : 0
243    }
244  }
245}
246
247impl fmt::Display for DataSinkHB {
248  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
249    let mut repr = String::from("<DataSinkHB");
250    repr += &(format!("\n \u{1F98B} \u{1F98B} \u{1F98B} \u{1F98B} \u{1F98B} DATA SENDER HEARTBEAT \u{1F98B} \u{1F98B} \u{1F98B} \u{1F98B} \u{1F98B}"));
251    repr += &(format!("\n Sent {} TofPackets! (packet rate {:.2}/s)", self.n_packets_sent , self.get_sent_packet_rate()));
252    repr += &(format!("\n Writing events to disk: {} packets written, data write rate {:.2} MB/sec", self.n_pack_write_disk, self.get_mbytes_to_disk_per_sec()));
253    repr += &(format!("\n Missing evid analysis:  {} of {} a chunk of events missing ({:.2}%)", self.evid_missing, self.evid_check_len, 100.0*(self.evid_missing as f64/self.evid_check_len as f64)));
254    repr += &(format!("\n Incoming channel length: {}", self.incoming_ch_len));
255    repr += &(format!("\n \u{1F98B} \u{1F98B} \u{1F98B} \u{1F98B} \u{1F98B} END HEARTBEAT \u{1F98B} \u{1F98B} \u{1F98B} \u{1F98B} \u{1F98B}"));
256    write!(f, "{}", repr)
257  }
258}
259