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    self.timestamp 
81  }
82
83  fn set_timestamp(&mut self, ts : u64) {
84    self.timestamp = ts;
85  }
86
87  /// Access the (data) members by name 
88  fn get(&self, varname : &str) -> Option<f32> {
89    match varname {
90    "board_id"           => Some(0.0),
91    "met"                => Some(self.met as f32),
92    "n_packets_sent"     => Some(self.n_packets_sent as f32),
93    "n_packets_incoming" => Some(self.n_packets_incoming as f32),
94    "n_bytes_written"    => Some(self.n_bytes_written as f32),
95    "n_evid_missing"     => Some(self.n_evid_missing as f32),
96    "n_evid_chunksize"   => Some(self.n_evid_chunksize as f32),
97    "evid_missing"       => Some(self.evid_missing as f32),
98    "evid_check_len"     => Some(self.evid_check_len as f32),
99    "n_pack_write_disk"  => Some(self.n_pack_write_disk as f32),
100    "incoming_ch_len"    => Some(self.incoming_ch_len as f32),
101    "timestamp"          => Some(self.timestamp as f32),
102    _                    => None
103    }
104  }
105
106  /// A list of the variables in this MoniData
107  fn keys() -> Vec<&'static str> {
108    vec!["board_id", "met", "n_packets_sent",
109         "n_packets_incoming", "n_bytes_written", "n_evid_missing",
110         "n_evid_chunksize", "evid_missing", "evid_check_len", 
111         "n_pack_write_disk", "incoming_ch_len", "timestamp"]
112  }
113}
114
115moniseries!(DataSinkHBSeries, DataSinkHB);
116
117//--------------------------------------------------------------
118
119#[cfg(feature="pybindings")]
120#[pymethods]
121impl DataSinkHB {
122
123  /// Mission elapsed time
124  #[getter]
125  fn get_met(&self) -> PyResult<u64> {
126    Ok(self.met)
127  }
128  
129  #[getter]
130  fn get_n_packets_sent(&self) -> PyResult<u64> {
131    Ok(self.n_packets_sent)
132  }
133  
134  #[getter]
135  fn get_n_packets_incoming(&self) -> PyResult<u64> {
136    Ok(self.n_packets_incoming)
137  }
138  
139  #[getter]
140  fn get_n_bytes_written(&self) -> PyResult<u64> {
141    Ok(self.n_bytes_written)
142  }
143  #[getter]
144  fn get_n_evid_chunksize(&self) -> PyResult<u64> {
145    Ok(self.n_evid_chunksize)
146  }
147  #[getter]
148  fn get_evid_missing(&self) -> PyResult<u64> {
149    Ok(self.evid_missing)
150  }
151  
152  #[getter]
153  fn get_evid_check_len(&self) -> PyResult<u64> {
154    Ok(self.evid_check_len)
155  }
156  
157  #[getter]
158  fn get_n_pack_write_disk(&self) -> PyResult<u64> {
159    Ok(self.n_pack_write_disk)
160  }  
161
162  #[getter]
163  #[pyo3(name="timestamp")]
164  fn get_timestamp_py(&self) -> PyResult<u64> {
165    Ok(self.timestamp) 
166  }
167}
168
169#[cfg(feature="pybindings")]
170pythonize_monidata!(DataSinkHB);
171#[cfg(feature="pybindings")]
172pythonize_packable!(DataSinkHB);
173
174//--------------------------------------------------------------
175
176impl TofPackable for DataSinkHB {
177  const TOF_PACKET_TYPE : TofPacketType = TofPacketType::DataSinkHB;
178}
179
180impl Serialization for DataSinkHB {
181  
182  const HEAD : u16 = 0xAAAA;
183  const TAIL : u16 = 0x5555;
184  const SIZE : usize = 84; 
185  
186  fn from_bytestream(stream    : &Vec<u8>, 
187                     pos       : &mut usize) 
188    -> Result<Self, SerializationError>{
189    Self::verify_fixed(stream, pos)?;  
190    let mut hb            = Self::new();
191    hb.met                = parse_u64(stream, pos);
192    hb.n_packets_sent     = parse_u64(stream, pos);
193    hb.n_packets_incoming = parse_u64(stream, pos);
194    hb.n_bytes_written    = parse_u64(stream, pos);
195    hb.n_evid_missing     = parse_u64(stream, pos);
196    hb.n_evid_chunksize   = parse_u64(stream, pos);
197    hb.evid_missing       = parse_u64(stream, pos);
198    hb.evid_check_len     = parse_u64(stream, pos);
199    hb.n_pack_write_disk  = parse_u64(stream, pos);
200    hb.incoming_ch_len    = parse_u64(stream, pos);
201    *pos += 2;
202    Ok(hb)
203  }
204  
205  fn to_bytestream(&self) -> Vec<u8> {
206    let mut bs = Vec::<u8>::with_capacity(Self::SIZE);
207    bs.extend_from_slice(&Self::HEAD.to_le_bytes());
208    bs.extend_from_slice(&self.met.to_le_bytes());
209    bs.extend_from_slice(&self.n_packets_sent.to_le_bytes());
210    bs.extend_from_slice(&self.n_packets_incoming.to_le_bytes());
211    bs.extend_from_slice(&self.n_bytes_written.to_le_bytes());
212    bs.extend_from_slice(&self.n_evid_missing.to_le_bytes());
213    bs.extend_from_slice(&self.n_evid_chunksize.to_le_bytes());
214    bs.extend_from_slice(&self.evid_missing     .to_le_bytes() );
215    bs.extend_from_slice(&self.evid_check_len   .to_le_bytes() );
216    bs.extend_from_slice(&self.n_pack_write_disk.to_le_bytes() );
217    bs.extend_from_slice(&self.incoming_ch_len.to_le_bytes());
218    bs.extend_from_slice(&Self::TAIL.to_le_bytes());
219    bs
220  }
221}
222
223#[cfg(feature = "random")]
224impl FromRandom for DataSinkHB {
225  fn from_random() -> Self {
226    let mut rng            = rand::rng();
227    Self {
228      met                : rng.random::<u64>(),
229      n_packets_sent     : rng.random::<u64>(),
230      n_packets_incoming : rng.random::<u64>(),
231      n_bytes_written    : rng.random::<u64>(),
232      n_evid_missing     : rng.random::<u64>(),
233      n_evid_chunksize   : rng.random::<u64>(),
234      evid_missing       : rng.random::<u64>(),
235      evid_check_len     : rng.random::<u64>(),
236      n_pack_write_disk  : rng.random::<u64>(),
237      incoming_ch_len    : rng.random::<u64>(),
238      timestamp          : 0
239    }
240  }
241}
242
243impl fmt::Display for DataSinkHB {
244  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
245    let mut repr = String::from("<DataSinkHB");
246    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}"));
247    repr += &(format!("\n Sent {} TofPackets! (packet rate {:.2}/s)", self.n_packets_sent , self.get_sent_packet_rate()));
248    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()));
249    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)));
250    repr += &(format!("\n Incoming channel length: {}", self.incoming_ch_len));
251    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}"));
252    write!(f, "{}", repr)
253  }
254}
255