use {
crossbeam_channel::{Receiver, Sender},
log::*,
solana_sdk::clock::Slot,
std::fmt,
};
pub type PohTimingReceiver = Receiver<SlotPohTimingInfo>;
pub type PohTimingSender = Sender<SlotPohTimingInfo>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum PohTimingPoint {
PohSlotStart(u64),
PohSlotEnd(u64),
FullSlotReceived(u64),
}
impl fmt::Display for PohTimingPoint {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
PohTimingPoint::PohSlotStart(t) => write!(f, "poh_start={t}"),
PohTimingPoint::PohSlotEnd(t) => write!(f, "poh_end ={t}"),
PohTimingPoint::FullSlotReceived(t) => write!(f, "poh_full ={t}"),
}
}
}
#[derive(Clone, Debug)]
pub struct SlotPohTimingInfo {
pub slot: Slot,
pub root_slot: Option<Slot>,
pub timing_point: PohTimingPoint,
}
impl fmt::Display for SlotPohTimingInfo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"PohTimingPoint: {}, slot={}, root_slot={}",
self.timing_point,
self.slot,
self.root_slot.unwrap_or(0),
)
}
}
impl SlotPohTimingInfo {
pub fn new_slot_start_poh_time_point(
slot: Slot,
root_slot: Option<Slot>,
timestamp: u64,
) -> SlotPohTimingInfo {
SlotPohTimingInfo {
slot,
root_slot,
timing_point: PohTimingPoint::PohSlotStart(timestamp),
}
}
pub fn new_slot_end_poh_time_point(
slot: Slot,
root_slot: Option<Slot>,
timestamp: u64,
) -> SlotPohTimingInfo {
SlotPohTimingInfo {
slot,
root_slot,
timing_point: PohTimingPoint::PohSlotEnd(timestamp),
}
}
pub fn new_slot_full_poh_time_point(
slot: Slot,
root_slot: Option<Slot>,
timestamp: u64,
) -> SlotPohTimingInfo {
SlotPohTimingInfo {
slot,
root_slot,
timing_point: PohTimingPoint::FullSlotReceived(timestamp),
}
}
}
pub fn send_poh_timing_point(sender: &PohTimingSender, slot_timing: SlotPohTimingInfo) {
trace!("{}", slot_timing);
if let Err(e) = sender.try_send(slot_timing) {
info!("failed to send slot poh timing {:?}", e);
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_poh_timing_point() {
let p = SlotPohTimingInfo::new_slot_start_poh_time_point(100, Some(101), 100);
assert!(p.slot == 100);
assert_eq!(p.root_slot, Some(101));
assert_eq!(p.timing_point, PohTimingPoint::PohSlotStart(100));
assert_eq!(
format!("{p}"),
"PohTimingPoint: poh_start=100, slot=100, root_slot=101"
);
let p = SlotPohTimingInfo::new_slot_start_poh_time_point(100, None, 100);
assert!(p.slot == 100);
assert_eq!(p.root_slot, None);
assert_eq!(p.timing_point, PohTimingPoint::PohSlotStart(100));
assert_eq!(
format!("{p}"),
"PohTimingPoint: poh_start=100, slot=100, root_slot=0"
);
let p = SlotPohTimingInfo::new_slot_end_poh_time_point(100, Some(101), 100);
assert!(p.slot == 100);
assert_eq!(p.root_slot, Some(101));
assert_eq!(p.timing_point, PohTimingPoint::PohSlotEnd(100));
assert_eq!(
format!("{p}"),
"PohTimingPoint: poh_end =100, slot=100, root_slot=101"
);
let p = SlotPohTimingInfo::new_slot_end_poh_time_point(100, None, 100);
assert!(p.slot == 100);
assert_eq!(p.root_slot, None);
assert_eq!(p.timing_point, PohTimingPoint::PohSlotEnd(100));
assert_eq!(
format!("{p}"),
"PohTimingPoint: poh_end =100, slot=100, root_slot=0"
);
let p = SlotPohTimingInfo::new_slot_full_poh_time_point(100, Some(101), 100);
assert!(p.slot == 100);
assert_eq!(p.root_slot, Some(101));
assert_eq!(p.timing_point, PohTimingPoint::FullSlotReceived(100));
assert_eq!(
format!("{p}"),
"PohTimingPoint: poh_full =100, slot=100, root_slot=101"
);
let p = SlotPohTimingInfo::new_slot_full_poh_time_point(100, None, 100);
assert!(p.slot == 100);
assert_eq!(p.root_slot, None);
assert_eq!(p.timing_point, PohTimingPoint::FullSlotReceived(100));
assert_eq!(
format!("{p}"),
"PohTimingPoint: poh_full =100, slot=100, root_slot=0"
);
}
}