@@ -74,7 +74,7 @@ pub trait DelayPerPacketTraceConfig: DynClone + Send {
7474dyn_clone:: clone_trait_object!( DelayPerPacketTraceConfig ) ;
7575
7676use rand:: { rngs:: StdRng , SeedableRng as _} ;
77- use rand_distr:: { Distribution , Normal } ;
77+ use rand_distr:: { Distribution , LogNormal , Normal } ;
7878#[ cfg( feature = "serde" ) ]
7979use serde:: { Deserialize , Serialize } ;
8080
@@ -211,7 +211,7 @@ pub struct RepeatedDelayPerPacketPatternConfig {
211211
212212/// The model of a per-packet delay trace subjects to a normal distribution.
213213///
214- /// The delay will subject to N(mean, std_dev), but bounded within [lower_bound, upper_bound] (optional)
214+ /// The delay will subject to N(mean, std_dev² ), but bounded within [lower_bound, upper_bound] (optional)
215215///
216216/// If the `count` is 0, the delay will be repeated forever, else it will be repeated `count` times.
217217///
@@ -298,6 +298,97 @@ pub struct NormalizedDelayPerPacketConfig {
298298 #[ cfg_attr( feature = "serde" , serde( skip_serializing_if = "Option::is_none" ) ) ]
299299 pub seed : Option < u64 > ,
300300}
301+ /// The model of a per-packet delay trace subjects to a log-normal distribution.
302+ ///
303+ /// The delay will subject to Lognormal(μ, σ²), but bounded within [lower_bound, upper_bound] (optional)
304+ /// The provided mean and std_dev are the one of the log-normal law and not the one of the underlying normal law.
305+ ///
306+ /// If the `count` is 0, the delay will be repeated forever, else it will be repeated `count` times.
307+ ///
308+ /// ## Examples
309+ ///
310+ /// A simple example without any bound on delay:
311+ ///
312+ /// ```
313+ /// # use netem_trace::model::LogNormalizedDelayPerPacketConfig;
314+ /// # use netem_trace::{Delay, DelayPerPacketTrace};
315+ /// let mut log_normal_delay = LogNormalizedDelayPerPacketConfig::new()
316+ /// .mean(Delay::from_millis(12))
317+ /// .std_dev(Delay::from_millis(1))
318+ /// .count(2)
319+ /// .seed(42)
320+ /// .build();
321+ /// assert_eq!(log_normal_delay.next_delay(), Some(Delay::from_nanos(12027817)));
322+ /// assert_eq!(log_normal_delay.next_delay(), Some(Delay::from_nanos(12091533)));
323+ /// assert_eq!(log_normal_delay.next_delay(), None);
324+ /// ```
325+ ///
326+ /// A more complex example with bounds on delay:
327+ ///
328+ /// ```
329+ /// # use netem_trace::model::LogNormalizedDelayPerPacketConfig;
330+ /// # use netem_trace::{Delay, DelayPerPacketTrace};
331+ /// let mut log_normal_delay = LogNormalizedDelayPerPacketConfig::new()
332+ /// .mean(Delay::from_millis(12))
333+ /// .std_dev(Delay::from_millis(1))
334+ /// .count(3)
335+ /// .seed(42)
336+ /// .upper_bound(Delay::from_micros(12100))
337+ /// .lower_bound(Delay::from_micros(11900))
338+ /// .build();
339+ /// assert_eq!(log_normal_delay.next_delay(), Some(Delay::from_nanos(12027817)));
340+ /// assert_eq!(log_normal_delay.next_delay(), Some(Delay::from_nanos(12091533)));
341+ /// assert_eq!(log_normal_delay.next_delay(), Some(Delay::from_nanos(12100000)));
342+ /// assert_eq!(log_normal_delay.next_delay(), None);
343+ /// ```
344+ #[ derive( Debug , Clone ) ]
345+ pub struct LogNormalizedDelayPerPacket {
346+ pub mean : Delay ,
347+ pub std_dev : Delay ,
348+ pub upper_bound : Option < Delay > ,
349+ pub lower_bound : Delay ,
350+ pub seed : u64 ,
351+ pub count : usize ,
352+ current_count : usize ,
353+ rng : StdRng ,
354+ log_normal : LogNormal < f64 > ,
355+ }
356+
357+ /// The configuration struct for [`LogNormalizedDelayPerPacket`].
358+ ///
359+ /// See [`LogNormalizedDelayPerPacket`] for more details.
360+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) , serde( default ) ) ]
361+ #[ derive( Debug , Clone , Default ) ]
362+ pub struct LogNormalizedDelayPerPacketConfig {
363+ #[ cfg_attr( feature = "serde" , serde( skip_serializing_if = "Option::is_none" ) ) ]
364+ #[ cfg_attr(
365+ all( feature = "serde" , feature = "human" ) ,
366+ serde( with = "humantime_serde" )
367+ ) ]
368+ pub mean : Option < Delay > ,
369+ #[ cfg_attr( feature = "serde" , serde( skip_serializing_if = "Option::is_none" ) ) ]
370+ #[ cfg_attr(
371+ all( feature = "serde" , feature = "human" ) ,
372+ serde( with = "humantime_serde" )
373+ ) ]
374+ pub std_dev : Option < Delay > ,
375+ #[ cfg_attr( feature = "serde" , serde( skip_serializing_if = "Option::is_none" ) ) ]
376+ #[ cfg_attr(
377+ all( feature = "serde" , feature = "human" ) ,
378+ serde( with = "humantime_serde" )
379+ ) ]
380+ pub upper_bound : Option < Delay > ,
381+ #[ cfg_attr( feature = "serde" , serde( skip_serializing_if = "Option::is_none" ) ) ]
382+ #[ cfg_attr(
383+ all( feature = "serde" , feature = "human" ) ,
384+ serde( with = "humantime_serde" )
385+ ) ]
386+ pub lower_bound : Option < Delay > ,
387+ #[ cfg_attr( feature = "serde" , serde( default ) ) ]
388+ pub count : usize ,
389+ #[ cfg_attr( feature = "serde" , serde( skip_serializing_if = "Option::is_none" ) ) ]
390+ pub seed : Option < u64 > ,
391+ }
301392
302393impl DelayPerPacketTrace for StaticDelayPerPacket {
303394 fn next_delay ( & mut self ) -> Option < Delay > {
@@ -354,6 +445,23 @@ impl DelayPerPacketTrace for NormalizedDelayPerPacket {
354445 }
355446}
356447
448+ impl DelayPerPacketTrace for LogNormalizedDelayPerPacket {
449+ fn next_delay ( & mut self ) -> Option < Delay > {
450+ if self . count != 0 && self . count == self . current_count {
451+ None
452+ } else {
453+ self . current_count += 1 ;
454+ let delay = self . log_normal . sample ( & mut self . rng ) . max ( 0.0 ) ;
455+ let mut delay = Delay :: from_secs_f64 ( delay) ;
456+ delay = delay. max ( self . lower_bound ) ;
457+ if let Some ( upper_bound) = self . upper_bound {
458+ delay = delay. min ( upper_bound) ;
459+ }
460+ Some ( delay)
461+ }
462+ }
463+ }
464+
357465impl StaticDelayPerPacketConfig {
358466 pub fn new ( ) -> Self {
359467 Self {
@@ -546,6 +654,83 @@ impl NormalizedDelayPerPacketConfig {
546654 self . build ( )
547655 }
548656}
657+
658+ impl LogNormalizedDelayPerPacketConfig {
659+ pub fn new ( ) -> Self {
660+ Self {
661+ mean : None ,
662+ std_dev : None ,
663+ upper_bound : None ,
664+ lower_bound : None ,
665+ count : 0 ,
666+ seed : None ,
667+ }
668+ }
669+
670+ pub fn mean ( mut self , mean : Delay ) -> Self {
671+ self . mean = Some ( mean) ;
672+ self
673+ }
674+
675+ pub fn std_dev ( mut self , std_dev : Delay ) -> Self {
676+ self . std_dev = Some ( std_dev) ;
677+ self
678+ }
679+
680+ pub fn upper_bound ( mut self , upper_bound : Delay ) -> Self {
681+ self . upper_bound = Some ( upper_bound) ;
682+ self
683+ }
684+
685+ pub fn lower_bound ( mut self , lower_bound : Delay ) -> Self {
686+ self . lower_bound = Some ( lower_bound) ;
687+ self
688+ }
689+
690+ pub fn count ( mut self , count : usize ) -> Self {
691+ self . count = count;
692+ self
693+ }
694+
695+ pub fn seed ( mut self , seed : u64 ) -> Self {
696+ self . seed = Some ( seed) ;
697+ self
698+ }
699+
700+ pub fn random_seed ( mut self ) -> Self {
701+ self . seed = Some ( rand:: random ( ) ) ;
702+ self
703+ }
704+
705+ pub fn build ( & self ) -> LogNormalizedDelayPerPacket {
706+ let mean = self . mean . unwrap_or_else ( || Delay :: from_millis ( 10 ) ) ;
707+ let std_dev = self . std_dev . unwrap_or ( Delay :: ZERO ) ;
708+ let upper_bound = self . upper_bound ;
709+ let lower_bound = self . lower_bound . unwrap_or ( Delay :: ZERO ) ;
710+ let count = self . count ;
711+ let seed = self . seed . unwrap_or ( DEFAULT_RNG_SEED ) ;
712+ let rng = StdRng :: seed_from_u64 ( seed) ;
713+ let delay_mean = mean. as_secs_f64 ( ) ;
714+ let delay_std_dev = std_dev. as_secs_f64 ( ) ;
715+ let normal_std_dev = f64:: sqrt ( f64:: ln (
716+ 1.0 + ( delay_std_dev. powi ( 2 ) ) / ( delay_mean. powi ( 2 ) ) ,
717+ ) ) ;
718+ let normal_mean = f64:: ln ( delay_mean) - normal_std_dev. powi ( 2 ) / 2. ;
719+ let log_normal: LogNormal < f64 > = LogNormal :: new ( normal_mean, normal_std_dev) . unwrap ( ) ;
720+ LogNormalizedDelayPerPacket {
721+ mean,
722+ std_dev,
723+ upper_bound,
724+ lower_bound,
725+ count,
726+ current_count : 0 ,
727+ seed,
728+ rng,
729+ log_normal,
730+ }
731+ }
732+ }
733+
549734macro_rules! impl_delay_per_packet_trace_config {
550735 ( $name: ident) => {
551736 #[ cfg_attr( feature = "serde" , typetag:: serde) ]
@@ -559,6 +744,7 @@ macro_rules! impl_delay_per_packet_trace_config {
559744
560745impl_delay_per_packet_trace_config ! ( StaticDelayPerPacketConfig ) ;
561746impl_delay_per_packet_trace_config ! ( NormalizedDelayPerPacketConfig ) ;
747+ impl_delay_per_packet_trace_config ! ( LogNormalizedDelayPerPacketConfig ) ;
562748impl_delay_per_packet_trace_config ! ( RepeatedDelayPerPacketPatternConfig ) ;
563749
564750/// Turn a [`DelayPerPacketTraceConfig`] into a forever repeated [`RepeatedDelayPerPacketPatternConfig`].
0 commit comments