Skip to content

Commit

Permalink
add random offset to announce interval duration
Browse files Browse the repository at this point in the history
  • Loading branch information
Folkert authored and davidv1992 committed Jul 27, 2023
1 parent ef30e27 commit af90df3
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 20 deletions.
49 changes: 49 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion statime-linux/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ statime = { path = "../statime" }
thiserror = "1.0.43"
pin-project = "1.1"
tokio = { version = "1.29", features = ["full"] }

rand = { version = "0.8.5", default-features = false, features = ["std", "std_rng"] }
4 changes: 3 additions & 1 deletion statime-linux/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::{

use clap::Parser;
use fern::colors::Color;
use rand::{rngs::StdRng, SeedableRng};
use statime::{
BasicFilter, Clock, ClockIdentity, DefaultDS, DelayMechanism, Duration, Interval, PortAction,
PortActionIterator, PortConfig, PortIdentity, PtpInstance, SdoId, Time, TimePropertiesDS,
Expand Down Expand Up @@ -237,7 +238,8 @@ async fn actual_main() {
local_clock.clone(),
BasicFilter::new(0.25),
);
let mut bmca_port = instance.add_port(port_config);
let rng = StdRng::from_entropy();
let mut bmca_port = instance.add_port(port_config, rng);

let mut bmca_timer = pin!(Timer::new());
let mut port_sync_timer = pin!(Timer::new());
Expand Down
1 change: 1 addition & 0 deletions statime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@ fixed = "1.23"
getset = "0.1.2"
libm = "0.2.7"
log = { version = "0.4.19", default-features = false }
rand = { version = "0.8.5", default-features = false }
12 changes: 9 additions & 3 deletions statime/src/config/port.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use rand::Rng;

use crate::{time::Interval, Duration, PortIdentity};

/// Which delay mechanism a port is using.
Expand Down Expand Up @@ -37,8 +39,12 @@ impl PortConfig {
}
}

pub fn announce_duration(&self) -> core::time::Duration {
// timeout is the number of announce intervals before the announce expires
self.announce_interval.as_core_duration() * self.announce_receipt_timeout as u32
// section 9.2.6.12
pub fn announce_duration(&self, rng: &mut impl Rng) -> core::time::Duration {
// add some randomness so that not all timers expire at the same time
let factor = 1.0 + rng.sample::<f64, _>(rand::distributions::Open01);
let duration = self.announce_interval.as_core_duration();

duration.mul_f64(factor * self.announce_receipt_timeout as u32 as f64)
}
}
28 changes: 17 additions & 11 deletions statime/src/port/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use core::{
use arrayvec::ArrayVec;
pub use error::{PortError, Result};
pub use measurement::Measurement;
use rand::Rng;
use state::{MasterState, PortState};

use self::state::SlaveState;
Expand Down Expand Up @@ -58,13 +59,14 @@ pub mod state;
/// A single port of the PTP instance
///
/// One of these needs to be created per port of the PTP instance.
pub struct Port<L> {
pub struct Port<L, R> {
config: PortConfig,
// Corresponds with PortDS port_state and enabled
port_state: PortState,
bmca: Bmca,
packet_buffer: [u8; MAX_DATA_LEN],
lifecycle: L,
rng: R,
}

pub struct Running<'a, C, F> {
Expand Down Expand Up @@ -136,7 +138,7 @@ impl<'a> Iterator for PortActionIterator<'a> {
}
}

impl<'a, C: Clock, F: Filter> Port<Running<'a, C, F>> {
impl<'a, C: Clock, F: Filter, R: Rng> Port<Running<'a, C, F>, R> {
// Send timestamp for last timecritical message became available
pub fn handle_send_timestamp(
&mut self,
Expand Down Expand Up @@ -264,7 +266,7 @@ impl<'a, C: Clock, F: Filter> Port<Running<'a, C, F>> {
self.lifecycle.state.local_clock.borrow().now().into(),
);
actions![PortAction::ResetAnnounceReceiptTimer {
duration: self.config.announce_duration(),
duration: self.config.announce_duration(&mut self.rng),
}]
}
_ => {
Expand All @@ -286,11 +288,12 @@ impl<'a, C: Clock, F: Filter> Port<Running<'a, C, F>> {

// Start a BMCA cycle and ensure this happens instantly from the perspective of
// the port
pub fn start_bmca(self) -> Port<InBmca<'a, C, F>> {
pub fn start_bmca(self) -> Port<InBmca<'a, C, F>, R> {
Port {
port_state: self.port_state,
config: self.config,
bmca: self.bmca,
rng: self.rng,
packet_buffer: [0; MAX_DATA_LEN],
lifecycle: InBmca {
pending_action: actions![],
Expand All @@ -301,14 +304,15 @@ impl<'a, C: Clock, F: Filter> Port<Running<'a, C, F>> {
}
}

impl<'a, C, F> Port<InBmca<'a, C, F>> {
impl<'a, C, F, R> Port<InBmca<'a, C, F>, R> {
// End a BMCA cycle and make the port available again
pub fn end_bmca(self) -> (Port<Running<'a, C, F>>, PortActionIterator<'static>) {
pub fn end_bmca(self) -> (Port<Running<'a, C, F>, R>, PortActionIterator<'static>) {
(
Port {
port_state: self.port_state,
config: self.config,
bmca: self.bmca,
rng: self.rng,
packet_buffer: [0; MAX_DATA_LEN],
lifecycle: Running {
state_refcell: self.lifecycle.state_refcell,
Expand All @@ -320,7 +324,7 @@ impl<'a, C, F> Port<InBmca<'a, C, F>> {
}
}

impl<L> Port<L> {
impl<L, R> Port<L, R> {
fn set_forced_port_state(&mut self, state: PortState) {
log::info!(
"new state for port {}: {} -> {}",
Expand All @@ -340,7 +344,7 @@ impl<L> Port<L> {
}
}

impl<'a, C, F> Port<InBmca<'a, C, F>> {
impl<'a, C, F, R: Rng> Port<InBmca<'a, C, F>, R> {
pub(crate) fn calculate_best_local_announce_message(&mut self, current_time: WireTimestamp) {
self.lifecycle.local_best = self.bmca.take_best_port_announce_message(current_time)
}
Expand Down Expand Up @@ -419,7 +423,7 @@ impl<'a, C, F> Port<InBmca<'a, C, F>> {
if update_state {
self.set_forced_port_state(state);

let duration = self.config.announce_duration();
let duration = self.config.announce_duration(&mut self.rng);
let action = PortAction::ResetAnnounceReceiptTimer { duration };
self.lifecycle.pending_action = actions![action];
}
Expand Down Expand Up @@ -448,23 +452,25 @@ impl<'a, C, F> Port<InBmca<'a, C, F>> {
}
}

impl<'a, C, F> Port<InBmca<'a, C, F>> {
impl<'a, C, F, R: Rng> Port<InBmca<'a, C, F>, R> {
/// Create a new port from a port dataset on a given interface.
pub(crate) fn new(
state_refcell: &'a RefCell<PtpInstanceState<C, F>>,
config: PortConfig,
mut rng: R,
) -> Self {
let bmca = Bmca::new(
config.announce_interval.as_duration().into(),
config.port_identity,
);

let duration = config.announce_duration();
let duration = config.announce_duration(&mut rng);

Port {
config,
port_state: PortState::Listening,
bmca,
rng,
packet_buffer: [0; MAX_DATA_LEN],
lifecycle: InBmca {
pending_action: actions![PortAction::ResetAnnounceReceiptTimer { duration }],
Expand Down
10 changes: 6 additions & 4 deletions statime/src/ptp_instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ use core::{
sync::atomic::{AtomicI8, Ordering},
};

use rand::Rng;

use crate::{
bmc::bmca::Bmca,
clock::Clock,
Expand Down Expand Up @@ -70,7 +72,7 @@ pub(crate) struct PtpInstanceState<C, F> {
}

impl<C: Clock, F> PtpInstanceState<C, F> {
fn bmca(&mut self, ports: &mut [&mut Port<InBmca<'_, C, F>>]) {
fn bmca<R: Rng>(&mut self, ports: &mut [&mut Port<InBmca<'_, C, F>, R>]) {
let current_time = self.local_clock.get_mut().now().into();

for port in ports.iter_mut() {
Expand Down Expand Up @@ -137,13 +139,13 @@ impl<C: Clock, F> PtpInstance<C, F> {
}
}

pub fn add_port(&self, config: PortConfig) -> Port<InBmca<'_, C, F>> {
pub fn add_port<R: Rng>(&self, config: PortConfig, rng: R) -> Port<InBmca<'_, C, F>, R> {
self.log_bmca_interval
.fetch_min(config.announce_interval.as_log_2(), Ordering::Relaxed);
Port::new(&self.state, config)
Port::new(&self.state, config, rng)
}

pub fn bmca(&self, ports: &mut [&mut Port<InBmca<'_, C, F>>]) {
pub fn bmca<R: Rng>(&self, ports: &mut [&mut Port<InBmca<'_, C, F>, R>]) {
self.state.borrow_mut().bmca(ports)
}

Expand Down

0 comments on commit af90df3

Please sign in to comment.