gondola_core/monitoring/heartbeats/
event_builder_hb.rs

1// This file is part of gaps-online-software and published 
2// under the GPLv3 license
3
4use crate::prelude::*;
5use colored::Colorize;
6
7
8#[derive(Debug, Copy, Clone, PartialEq)]
9#[cfg_attr(feature="pybindings", pyclass)]
10pub struct EventBuilderHB {
11  /// Mission elapsed time in seconds
12  pub met_seconds           : u64,
13  /// Total number of received MasterTriggerEvents (from MTB)
14  pub n_mte_received_tot    : u64,
15  /// Total number of received RBEvents (from all RB)
16  pub n_rbe_received_tot    : u64,
17  /// Average number of RBEvents per each MTEvent
18  pub n_rbe_per_te          : u64,
19  /// Total number of discarded RBEvents (accross all boards)
20  pub n_rbe_discarded_tot   : u64,
21  /// TOtal number of missed MTEvents. "Skipped means" gaps in 
22  /// consecutive rising event ids
23  pub n_mte_skipped         : u64,
24  /// Total number of events that timed out, which means they 
25  /// got send before all RBEvents could be associated with 
26  /// this event
27  pub n_timed_out           : u64,
28  /// Total number of events passed on to the gloabl data sink 
29  /// thread
30  pub n_sent                  : u64,
31  /// ?
32  pub delta_mte_rbe           : u64,
33  /// The total size of the current event cache in number of events
34  pub event_cache_size        : u64,
35  /// In paralel to the event_cache, the event_id cache holds event ids.
36  /// This should be perfectly aligned to the event_cache by design.
37  pub event_id_cache_size     : u64, 
38  /// The total number of hits which we lost due to the DRS being busy
39  /// (this is on the Readoutboards)
40  pub drs_bsy_lost_hg_hits    : u64,
41  /// The total number of RBEvents which do not have a MasterTriggerEvent
42  pub rbe_wo_mte              : u64,
43  /// The current length of the channel which we use to send events from 
44  /// the MasterTrigger thread to the event builder
45  pub mte_receiver_cbc_len    : u64,
46  /// The current length of the channel whcih we use for all readoutboard
47  /// threads to send their events to the event builder
48  pub rbe_receiver_cbc_len    : u64,
49  /// the current length of the channel which we use to send built events 
50  /// to the global data sink thread
51  pub tp_sender_cbc_len       : u64,
52  /// The total number of RBEvents which have an event id which is SMALLER
53  /// than the smallest event id in the event cache. 
54  pub n_rbe_from_past         : u64,
55  pub n_rbe_orphan            : u64,
56  // let's deprecate this!
57  pub n_rbe_per_loop          : u64,
58  /// The totabl number of events with the "AnyDataMangling" flag set
59  pub data_mangled_ev         : u64,
60  // pub seen_rbevents         : HashMap<u8, usize>,
61  // this will not get serialized - can be filled by 
62  // gcu timestamp 
63  pub timestamp               : u64,
64}
65
66impl EventBuilderHB {
67  pub fn new() -> Self {
68    Self {
69      met_seconds          : 0,
70      n_mte_received_tot   : 0,
71      n_rbe_received_tot   : 0,
72      n_rbe_per_te         : 0,
73      n_rbe_discarded_tot  : 0,
74      n_mte_skipped        : 0,
75      n_timed_out          : 0,
76      n_sent               : 0,
77      delta_mte_rbe        : 0,
78      event_cache_size     : 0,
79      event_id_cache_size  : 0,
80      drs_bsy_lost_hg_hits : 0,
81      rbe_wo_mte           : 0,
82      mte_receiver_cbc_len : 0,
83      rbe_receiver_cbc_len : 0,
84      tp_sender_cbc_len    : 0,
85      n_rbe_per_loop       : 0,
86      n_rbe_orphan         : 0,
87      n_rbe_from_past      : 0,
88      data_mangled_ev      : 0,
89      // seen_rbevents        : seen_rbevents, 
90      timestamp            : 0,
91    }
92  }
93
94  /// The average number of RBEvents per
95  /// TofEvent, tis is the average number
96  /// of active ReadoutBoards per TofEvent
97  pub fn get_average_rbe_te(&self) -> f64 {
98   if self.n_sent > 0 {
99     return self.n_rbe_per_te as f64 / self.n_sent as f64;
100   }
101   0.0
102  }
103
104  pub fn get_timed_out_frac(&self) -> f64 {
105    if self.n_sent > 0 {
106      return self.n_timed_out as f64 / self.n_sent as f64;
107    }
108    0.0
109  }
110
111  // pub fn add_rbevent(&mut self, rb_id : u8) {
112  //   *self.seen_rbevents.get_mut(&rb_id).unwrap() += 1;
113  // }
114  
115  pub fn get_incoming_vs_outgoing_mte(&self) -> f64 {
116    if self.n_sent > 0 {
117      return self.n_mte_received_tot as f64 /  self.n_sent as f64;
118    }
119    0.0
120  }
121
122  pub fn get_nrbe_discarded_frac(&self) -> f64 {
123    if self.n_rbe_received_tot > 0 {
124     return self.n_rbe_discarded_tot as f64 / self.n_rbe_received_tot as f64;
125   }
126   0.0
127  }
128  
129  pub fn get_mangled_frac(&self) -> f64 {
130    if self.n_mte_received_tot > 0 {
131     return self.data_mangled_ev as f64 / self.n_mte_received_tot as f64;
132   }
133   0.0
134  }
135
136  pub fn get_drs_lost_frac(&self) -> f64 {
137    if self.n_rbe_received_tot > 0 {
138      return self.drs_bsy_lost_hg_hits as f64 / self.n_rbe_received_tot as f64;
139    }
140    0.0
141  }
142
143  pub fn pretty_print(&self) -> String {
144    let mut repr = String::from("");
145    repr += &(format!("\n \u{2B50} \u{2B50} \u{2B50} \u{2B50} \u{2B50} EVENTBUILDER HEARTBTEAT \u{2B50} \u{2B50} \u{2B50} \u{2B50} \u{2B50} "));
146    repr += &(format!("\n Mission elapsed time (MET) [s]      : {}", self.met_seconds).bright_purple());
147    repr += &(format!("\n Num. events sent                    : {}", self.n_sent).bright_purple());
148    repr += &(format!("\n Size of event cache                 : {}", self.event_cache_size).bright_purple());
149    //repr += &(format!("\n Size of event ID cache              : {}", self.event_id_cache_size).bright_purple());
150    repr += &(format!("\n Num. events timed out               : {}", self.n_timed_out).bright_purple());
151    repr += &(format!("\n Percent events timed out            : {:.2}%", self.get_timed_out_frac()*(100 as f64)).bright_purple());
152    //if self.n_sent > 0 && self.n_rbe_per_loop > 0 {
153    //  repr += &(format!("\n Percent events w/out event ID : {:.2}%", (((self.n_rbe_per_loop / self.n_sent) as f64)*(100 as f64))).bright_purple());
154    //} else if self.n_rbe_per_loop > 0 { 
155    //  repr += &(format!("\n Percent events w/out event ID : N/A").bright_purple());
156    //}
157    if self.n_mte_received_tot > 0{ 
158      repr += &(format!("\n \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504}"));
159      repr += &(format!("\n Num. evts with ANY data mangling  : {}"     , self.data_mangled_ev));
160      repr += &(format!("\n Per. evts with ANY data mangling  : {:.2}%" , self.get_mangled_frac()*(100 as f64)));
161    }
162    else {repr += &(format!("\n Percent events with data mangling: unable to calculate"));}
163    repr += &(format!("\n \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504}"));
164    repr += &(format!("\n Received MTEvents                   : {}", self.n_mte_received_tot).bright_purple());
165    repr += &(format!("\n Skipped MTEvents                    : {}", self.n_mte_skipped).bright_purple());
166    repr += &(format!("\n Incoming/outgoing MTEvents fraction : {:.2}", self.get_incoming_vs_outgoing_mte()).bright_purple());
167    repr += &(format!("\n \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504}"));
168    repr += &(format!("\n Received RBEvents                   : {}", self.n_rbe_received_tot).bright_purple());
169    repr += &(format!("\n RBEvents Discarded                  : {}", self.n_rbe_discarded_tot).bright_purple());
170    repr += &(format!("\n Percent RBEvents discarded          : {:.2}%", self.get_nrbe_discarded_frac()*(100 as f64)).bright_purple());
171    repr += &(format!("\n DRS4 busy lost hits                 : {}", self.drs_bsy_lost_hg_hits).bright_purple());
172    repr += &(format!("\n RDS4 busy lost hits fraction        : {:.2}%", self.get_drs_lost_frac()*(100.0 as f64)).bright_purple());
173    repr += &(format!("\n \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504}"));
174    if self.n_sent > 0 && self.n_mte_received_tot > 0 {
175        repr += &(format!("\n RBEvent/Evts sent               : {:.2}", (self.n_rbe_received_tot as f64/ self.n_sent as f64)).bright_purple());
176        repr += &(format!("\n RBEvent/MTEvents                : {:.2}", (self.n_rbe_received_tot as f64 / self.n_mte_received_tot as f64)).bright_purple()); }
177    repr += &(format!("\n Current RBevents / iteration        : {:.2}", self.n_rbe_per_loop).bright_purple());
178    repr += &(format!("\n Num. RBEvents with evid from past   : {}",  self.n_rbe_from_past).bright_purple());
179    repr += &(format!("\n Num. orphan RBEvents                : {}",  self.n_rbe_orphan).bright_purple());
180    repr += &(format!("\n\n Getting MTE from cache for RBEvent failed {} times :(", self.rbe_wo_mte).bright_blue());
181    repr += &(format!("\n \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504}"));
182    repr += &(format!("\n Ch. len MTE Receiver                : {}", self.mte_receiver_cbc_len).bright_purple());
183    repr += &(format!("\n Ch. len RBE Reveiver                : {}", self.rbe_receiver_cbc_len).bright_purple());
184    repr += &(format!("\n Ch. len TP Sender                   : {}", self.tp_sender_cbc_len).bright_purple());
185    repr += &(format!("\n \u{2B50} \u{2B50} \u{2B50} \u{2B50} \u{2B50} END EVENTBUILDER HEARTBTEAT \u{2B50} \u{2B50} \u{2B50} \u{2B50} \u{2B50}"));
186    repr
187  }
188}
189
190
191impl MoniData for EventBuilderHB {
192  fn get_board_id(&self) -> u8 {
193    0
194  }
195 
196  fn get_timestamp(&self) -> u64 { 
197    self.timestamp 
198  }
199
200  fn set_timestamp(&mut self, ts : u64) {
201    self.timestamp = ts;
202  }
203
204  /// Access the (data) members by name 
205  fn get(&self, varname : &str) -> Option<f32> {
206    match varname {
207      "board_id"             => Some(0.0),
208      "met_seconds"          => Some(self.met_seconds as f32),
209      "n_mte_received_tot"   => Some(self.n_mte_received_tot as f32),
210      "n_rbe_received_tot"   => Some(self.n_rbe_received_tot as f32),
211      "n_rbe_per_te"         => Some(self.n_rbe_per_te as f32),
212      "n_rbe_discarded_tot"  => Some(self.n_rbe_discarded_tot as f32),
213      "n_mte_skipped"        => Some(self.n_mte_skipped as f32),
214      "n_timed_out"          => Some(self.n_timed_out as f32),
215      "n_sent"               => Some(self.n_sent as f32),
216      "delta_mte_rbe"        => Some(self.delta_mte_rbe as f32),
217      "event_cache_size"     => Some(self.event_cache_size as f32),
218      "event_id_cache_size"  => Some(self.event_id_cache_size as f32),
219      "drs_bsy_lost_hg_hits" => Some(self.drs_bsy_lost_hg_hits as f32),
220      "rbe_wo_mte"           => Some(self.rbe_wo_mte as f32),
221      "mte_receiver_cbc_len" => Some(self.mte_receiver_cbc_len as f32),
222      "rbe_receiver_cbc_len" => Some(self.rbe_receiver_cbc_len as f32),
223      "tp_sender_cbc_len"    => Some(self.tp_sender_cbc_len as f32),
224      "n_rbe_per_loop"       => Some(self.n_rbe_per_loop as f32),
225      "n_rbe_orphan"         => Some(self.n_rbe_orphan as f32),
226      "n_rbe_from_past"      => Some(self.n_rbe_from_past as f32),
227      "data_mangled_ev"      => Some(self.data_mangled_ev as f32),
228      "timestamp"            => Some(self.timestamp as f32),
229      _                      => None
230    }
231  }
232
233  /// A list of the variables in this MoniData
234  fn keys() -> Vec<&'static str> {
235    vec!["board_id", "met_seconds", "n_mte_received_tot",
236         "n_rbe_received_tot", "n_rbe_per_te", "n_rbe_discarded_tot",
237         "n_mte_skipped", "n_timed_out", "n_sent", "delta_mte_rbe",
238         "event_cache_size", "event_id_cache_size","drs_bsy_lost_hg_hits",
239         "rbe_wo_mte", "mte_receiver_cbc_len", "rbe_receiver_cbc_len",
240         "tp_sender_cbc_len", "n_rbe_per_loop", "n_rbe_orphan", "n_rbe_from_past",
241         "data_mangled_ev", "timestamp"]
242  }
243}
244
245moniseries!(EventBuilderHBSeries,EventBuilderHB);
246
247#[cfg(feature="pybindings")]
248#[pymethods]
249impl EventBuilderHB {
250  /// The average number of RBEvents per
251  /// TofEvent, tis is the average number
252  /// of active ReadoutBoards per TofEvent
253  #[getter]
254  #[pyo3(name="average_rbe_te")]
255  fn get_average_rbe_te_py(&self) -> f64 {
256    self.get_average_rbe_te()
257  }
258
259  #[getter]
260  #[pyo3(name="timed_out_frac")]
261  pub fn get_timed_out_frac_py(&self) -> f64 {
262    self.get_timed_out_frac()
263  }
264 
265  #[getter]
266  #[pyo3(name="incoming_vs_outgoing_mte")]
267  pub fn get_incoming_vs_outgoing_mte_py(&self) -> f64 {
268    self.get_incoming_vs_outgoing_mte()
269  }
270
271  #[getter]
272  #[pyo3(name="nrbe_discarded_frac")]
273  pub fn get_nrbe_discarded_frac_py(&self) -> f64 {
274    self.get_nrbe_discarded_frac()
275  }
276  
277  #[getter]
278  #[pyo3(name="mangled_frac")]
279  pub fn get_mangled_frac_py(&self) -> f64 {
280    self.get_mangled_frac()
281  }
282
283  #[getter]
284  #[pyo3(name="drs_lost_frac")]
285  pub fn get_drs_lost_frac_py(&self) -> f64 {
286    self.get_drs_lost_frac()
287  }  
288}
289
290#[cfg(feature="pybindings")]
291pythonize_monidata!(EventBuilderHB);
292#[cfg(feature="pybindings")]
293pythonize_packable!(EventBuilderHB);
294
295//-----------------------------------------------------
296
297impl Default for EventBuilderHB {
298  fn default () -> Self {
299    Self::new()
300  }
301}
302
303impl TofPackable for EventBuilderHB {
304  const TOF_PACKET_TYPE : TofPacketType = TofPacketType::EventBuilderHB;
305}
306
307impl Serialization for EventBuilderHB {
308  const HEAD : u16 = 0xAAAA;
309  const TAIL : u16 = 0x5555;
310  const SIZE : usize = 156; //
311
312  fn from_bytestream(stream : &Vec<u8>, 
313                     pos        : &mut usize)
314    -> Result<Self, SerializationError>{
315    Self::verify_fixed(stream,pos)?;
316    let mut hb = EventBuilderHB::new();
317    hb.met_seconds          = parse_u64(stream,pos);
318    hb.n_mte_received_tot   = parse_u64(stream,pos);
319    hb.n_rbe_received_tot   = parse_u64(stream,pos);
320    hb.n_rbe_per_te         = parse_u64(stream,pos);
321    hb.n_rbe_discarded_tot  = parse_u64(stream,pos);
322    hb.n_mte_skipped        = parse_u64(stream,pos);
323    hb.n_timed_out          = parse_u64(stream,pos);
324    hb.n_sent               = parse_u64(stream,pos);
325    hb.delta_mte_rbe        = parse_u64(stream,pos);
326    hb.event_cache_size     = parse_u64(stream,pos);
327    //hb.event_id_cache_size  = parse_u64(stream,pos);
328    hb.drs_bsy_lost_hg_hits = parse_u64(stream,pos);
329    hb.rbe_wo_mte           = parse_u64(stream,pos);
330    hb.mte_receiver_cbc_len = parse_u64(stream,pos);
331    hb.rbe_receiver_cbc_len = parse_u64(stream,pos);
332    hb.tp_sender_cbc_len    = parse_u64(stream,pos);
333    hb.n_rbe_per_loop         = parse_u64(stream,pos);
334    hb.n_rbe_from_past      = parse_u64(stream,pos);
335    hb.n_rbe_orphan         = parse_u64(stream,pos);
336    hb.data_mangled_ev      = parse_u64(stream,pos);
337    // hb.seen_rbevents        = HashMap::from(parse_u8(stream, pos));
338    *pos += 2;
339    Ok(hb)
340  }
341    
342  fn to_bytestream(&self) -> Vec<u8> {
343    let mut bs = Vec::<u8>::with_capacity(Self::SIZE);
344    bs.extend_from_slice(&Self::HEAD.to_le_bytes());
345    bs.extend_from_slice(&self.met_seconds.to_le_bytes());
346    bs.extend_from_slice(&self.n_mte_received_tot.to_le_bytes());
347    bs.extend_from_slice(&self.n_rbe_received_tot.to_le_bytes());
348    bs.extend_from_slice(&self.n_rbe_per_te.to_le_bytes());
349    bs.extend_from_slice(&self.n_rbe_discarded_tot.to_le_bytes());
350    bs.extend_from_slice(&self.n_mte_skipped.to_le_bytes());
351    bs.extend_from_slice(&self.n_timed_out.to_le_bytes());
352    bs.extend_from_slice(&self.n_sent.to_le_bytes());
353    bs.extend_from_slice(&self.delta_mte_rbe.to_le_bytes());
354    bs.extend_from_slice(&self.event_cache_size.to_le_bytes());
355    //bs.extend_from_slice(&self.event_id_cache_size.to_le_bytes());
356    bs.extend_from_slice(&self.drs_bsy_lost_hg_hits.to_le_bytes());
357    bs.extend_from_slice(&self.rbe_wo_mte.to_le_bytes());
358    bs.extend_from_slice(&self.mte_receiver_cbc_len.to_le_bytes());
359    bs.extend_from_slice(&self.rbe_receiver_cbc_len.to_le_bytes());
360    bs.extend_from_slice(&self.tp_sender_cbc_len.to_le_bytes());
361    bs.extend_from_slice(&self.n_rbe_per_loop.to_le_bytes());
362    bs.extend_from_slice(&self.n_rbe_from_past.to_le_bytes());
363    bs.extend_from_slice(&self.n_rbe_orphan.to_le_bytes());
364    bs.extend_from_slice(&self.data_mangled_ev.to_le_bytes());
365    // bs.push(self.seen_rbevents.to_u8());
366    bs.extend_from_slice(&Self::TAIL.to_le_bytes());
367    bs
368  }
369}
370
371#[cfg(feature="random")]
372impl FromRandom for EventBuilderHB {
373  fn from_random() -> Self {
374    let mut rng              = rand::rng();
375    Self {
376      met_seconds            : rng.random::<u64>(),
377      n_rbe_received_tot     : rng.random::<u64>(),
378      n_rbe_per_te           : rng.random::<u64>(),
379      n_rbe_discarded_tot    : rng.random::<u64>(),
380      n_mte_skipped          : rng.random::<u64>(),
381      n_timed_out            : rng.random::<u64>(),
382      n_sent                 : rng.random::<u64>(),
383      delta_mte_rbe          : rng.random::<u64>(),
384      event_cache_size       : rng.random::<u64>(),
385      // don't randomize this, since it 
386      // won't get serialized
387      event_id_cache_size    :                0,
388      drs_bsy_lost_hg_hits   : rng.random::<u64>(),
389      rbe_wo_mte             : rng.random::<u64>(),
390      mte_receiver_cbc_len   : rng.random::<u64>(),
391      rbe_receiver_cbc_len   : rng.random::<u64>(),
392      tp_sender_cbc_len      : rng.random::<u64>(),
393      n_mte_received_tot     : rng.random::<u64>(),
394      n_rbe_per_loop         : rng.random::<u64>(),
395      n_rbe_from_past        : rng.random::<u64>(),
396      n_rbe_orphan           : rng.random::<u64>(),
397      data_mangled_ev        : rng.random::<u64>(),
398      timestamp              : 0
399    }
400  }
401} 
402
403impl fmt::Display for EventBuilderHB {
404  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
405    let mut repr = String::from("<EVTBLDRHearbeat:   ");
406    repr += &self.pretty_print();
407    write!(f, "{}>", repr)
408  }
409}  
410
411#[cfg(feature="random")]
412#[test]
413fn pack_eventbuilderhb() {
414  for _ in 0..100 {
415    let hb = EventBuilderHB::from_random();
416    let test : EventBuilderHB = hb.pack().unpack().unwrap();
417    assert_eq!(hb, test);
418  }
419}
420