diff --git a/asynchronix/examples/assembly.rs b/asynchronix/examples/assembly.rs index e550656..8a88a6c 100644 --- a/asynchronix/examples/assembly.rs +++ b/asynchronix/examples/assembly.rs @@ -79,8 +79,8 @@ impl Model for MotorAssembly { // clones. motor.position = self.position.clone(); - setup_context.add_model(driver, driver_mbox); - setup_context.add_model(motor, motor_mbox); + setup_context.add_model(driver, driver_mbox, "driver"); + setup_context.add_model(motor, motor_mbox, "motor"); } } @@ -105,7 +105,9 @@ fn main() { let t0 = MonotonicTime::EPOCH; // Assembly and initialization. - let mut simu = SimInit::new().add_model(assembly, assembly_mbox).init(t0); + let mut simu = SimInit::new() + .add_model(assembly, assembly_mbox, "assembly") + .init(t0); // ---------- // Simulation. diff --git a/asynchronix/examples/espresso_machine.rs b/asynchronix/examples/espresso_machine.rs index bd6b1a6..fcab7c3 100644 --- a/asynchronix/examples/espresso_machine.rs +++ b/asynchronix/examples/espresso_machine.rs @@ -368,9 +368,9 @@ fn main() { // Assembly and initialization. let mut simu = SimInit::new() - .add_model(controller, controller_mbox) - .add_model(pump, pump_mbox) - .add_model(tank, tank_mbox) + .add_model(controller, controller_mbox, "controller") + .add_model(pump, pump_mbox, "pump") + .add_model(tank, tank_mbox, "tank") .init(t0); // ---------- diff --git a/asynchronix/examples/power_supply.rs b/asynchronix/examples/power_supply.rs index bce7b9c..ab694bf 100644 --- a/asynchronix/examples/power_supply.rs +++ b/asynchronix/examples/power_supply.rs @@ -140,10 +140,10 @@ fn main() { // Assembly and initialization. let mut simu = SimInit::new() - .add_model(psu, psu_mbox) - .add_model(load1, load1_mbox) - .add_model(load2, load2_mbox) - .add_model(load3, load3_mbox) + .add_model(psu, psu_mbox, "psu") + .add_model(load1, load1_mbox, "load1") + .add_model(load2, load2_mbox, "load2") + .add_model(load3, load3_mbox, "load3") .init(t0); // ---------- diff --git a/asynchronix/examples/stepper_motor.rs b/asynchronix/examples/stepper_motor.rs index c733af5..5b2130a 100644 --- a/asynchronix/examples/stepper_motor.rs +++ b/asynchronix/examples/stepper_motor.rs @@ -53,8 +53,15 @@ impl Motor { /// For the sake of simplicity, we do as if the rotor rotates /// instantaneously. If the current is too weak to overcome the load or when /// attempting to move to an opposite phase, the position remains unchanged. - pub async fn current_in(&mut self, current: (f64, f64)) { + pub async fn current_in(&mut self, current: (f64, f64), context: &Context) { assert!(!current.0.is_nan() && !current.1.is_nan()); + println!( + "Model instance {} at time {}: setting currents: {:.2} and {:.2}", + context.name(), + context.time(), + current.0, + current.1 + ); let (target_phase, abs_current) = match (current.0 != 0.0, current.1 != 0.0) { (false, false) => return, @@ -78,9 +85,16 @@ impl Motor { } /// Torque applied by the load [N·m] -- input port. - pub fn load(&mut self, torque: f64) { + pub fn load(&mut self, torque: f64, context: &Context) { assert!(torque >= 0.0); + println!( + "Model instance {} at time {}: setting load: {:.2}", + context.name(), + context.time(), + torque + ); + self.torque = torque; } } @@ -124,6 +138,13 @@ impl Driver { /// Sets the pulse rate (sign = direction) [Hz] -- input port. pub async fn pulse_rate(&mut self, pps: f64, context: &Context) { + println!( + "Model instance {} at time {}: setting pps: {:.2}", + context.name(), + context.time(), + pps + ); + let pps = pps.signum() * pps.abs().clamp(Self::MIN_PPS, Self::MAX_PPS); if pps == self.pps { return; @@ -148,6 +169,12 @@ impl Driver { _: (), context: &'a Context, ) -> impl Future + Send + 'a { + println!( + "Model instance {} at time {}: sending pulse", + context.name(), + context.time() + ); + async move { let current_out = match self.next_phase { 0 => (self.current, 0.0), @@ -205,8 +232,8 @@ fn main() { // Assembly and initialization. let mut simu = SimInit::new() - .add_model(driver, driver_mbox) - .add_model(motor, motor_mbox) + .add_model(driver, driver_mbox, "driver") + .add_model(motor, motor_mbox, "motor") .init(t0); // ---------- diff --git a/asynchronix/src/lib.rs b/asynchronix/src/lib.rs index c9c7c76..b8a2954 100644 --- a/asynchronix/src/lib.rs +++ b/asynchronix/src/lib.rs @@ -231,10 +231,10 @@ //! // Pick an arbitrary simulation start time and build the simulation. //! let t0 = MonotonicTime::EPOCH; //! let mut simu = SimInit::new() -//! .add_model(multiplier1, multiplier1_mbox) -//! .add_model(multiplier2, multiplier2_mbox) -//! .add_model(delay1, delay1_mbox) -//! .add_model(delay2, delay2_mbox) +//! .add_model(multiplier1, multiplier1_mbox, "multiplier1") +//! .add_model(multiplier2, multiplier2_mbox, "multiplier2") +//! .add_model(delay1, delay1_mbox, "delay1") +//! .add_model(delay2, delay2_mbox, "delay2") //! .init(t0); //! ``` //! @@ -319,10 +319,10 @@ //! # let input_address = multiplier1_mbox.address(); //! # let t0 = MonotonicTime::EPOCH; //! # let mut simu = SimInit::new() -//! # .add_model(multiplier1, multiplier1_mbox) -//! # .add_model(multiplier2, multiplier2_mbox) -//! # .add_model(delay1, delay1_mbox) -//! # .add_model(delay2, delay2_mbox) +//! # .add_model(multiplier1, multiplier1_mbox, "multiplier1") +//! # .add_model(multiplier2, multiplier2_mbox, "multiplier2") +//! # .add_model(delay1, delay1_mbox, "delay1") +//! # .add_model(delay2, delay2_mbox, "delay2") //! # .init(t0); //! // Send a value to the first multiplier. //! simu.process_event(Multiplier::input, 21.0, &input_address); diff --git a/asynchronix/src/model/context.rs b/asynchronix/src/model/context.rs index 24e0c94..2336196 100644 --- a/asynchronix/src/model/context.rs +++ b/asynchronix/src/model/context.rs @@ -81,6 +81,7 @@ use super::Model; // The self-scheduling caveat seems related to this issue: // https://github.com/rust-lang/rust/issues/78649 pub struct Context { + name: String, sender: Sender, scheduler_queue: Arc>, time: SyncCellReader, @@ -89,17 +90,24 @@ pub struct Context { impl Context { /// Creates a new local context. pub(crate) fn new( + name: String, sender: Sender, scheduler_queue: Arc>, time: SyncCellReader, ) -> Self { Self { + name, sender, scheduler_queue, time, } } + /// Returns the model instance name. + pub fn name(&self) -> &str { + &self.name + } + /// Returns the current simulation time. /// /// # Examples @@ -440,11 +448,13 @@ impl fmt::Debug for Context { /// let b = SubmodelB::default(); /// let a_mbox = Mailbox::new(); /// let b_mbox = Mailbox::new(); +/// let a_name = setup_context.name().to_string() + "::a"; +/// let b_name = setup_context.name().to_string() + "::b"; /// /// a.out.connect(SubmodelB::input, &b_mbox); /// -/// setup_context.add_model(a, a_mbox); -/// setup_context.add_model(b, b_mbox); +/// setup_context.add_model(a, a_mbox, a_name); +/// setup_context.add_model(b, b_mbox, b_name); /// } /// } /// @@ -472,11 +482,25 @@ impl<'a, M: Model> SetupContext<'a, M> { } } + /// Returns the model instance name. + pub fn name(&self) -> &str { + &self.context.name + } + /// Adds a new model and its mailbox to the simulation bench. - pub fn add_model(&self, model: N, mailbox: Mailbox) { + /// + /// The `name` argument needs not be unique (it can be an empty string) and + /// is used for convenience for model instance identification (e.g. for + /// logging purposes). + pub fn add_model(&self, model: N, mailbox: Mailbox, name: impl Into) { + let mut submodel_name = name.into(); + if !self.context.name().is_empty() && !submodel_name.is_empty() { + submodel_name = self.context.name().to_string() + "." + &submodel_name; + } simulation::add_model( model, mailbox, + submodel_name, self.context.scheduler_queue.clone(), self.context.time.clone(), self.executor, diff --git a/asynchronix/src/ports.rs b/asynchronix/src/ports.rs index 60c6821..17362ec 100644 --- a/asynchronix/src/ports.rs +++ b/asynchronix/src/ports.rs @@ -65,7 +65,8 @@ //! let mut child = ChildModel::new(); //! let child_mbox = Mailbox::new(); //! child.output = self.output.clone(); -//! setup_context.add_model(child, child_mbox); +//! let child_name = setup_context.name().to_string() + "::child"; +//! setup_context.add_model(child, child_mbox, child_name); //! } //! } //! ``` diff --git a/asynchronix/src/ports/output/broadcaster.rs b/asynchronix/src/ports/output/broadcaster.rs index cb39f52..b960bf8 100644 --- a/asynchronix/src/ports/output/broadcaster.rs +++ b/asynchronix/src/ports/output/broadcaster.rs @@ -614,8 +614,12 @@ mod tests { let dummy_priority_queue = Arc::new(Mutex::new(PriorityQueue::new())); let dummy_time = SyncCell::new(TearableAtomicTime::new(MonotonicTime::EPOCH)).reader(); - let dummy_context = - Context::new(dummy_address, dummy_priority_queue, dummy_time); + let dummy_context = Context::new( + String::new(), + dummy_address, + dummy_priority_queue, + dummy_time, + ); block_on(mailbox.recv(&mut counter, &dummy_context)).unwrap(); } }) @@ -665,8 +669,12 @@ mod tests { let dummy_priority_queue = Arc::new(Mutex::new(PriorityQueue::new())); let dummy_time = SyncCell::new(TearableAtomicTime::new(MonotonicTime::EPOCH)).reader(); - let dummy_context = - Context::new(dummy_address, dummy_priority_queue, dummy_time); + let dummy_context = Context::new( + String::new(), + dummy_address, + dummy_priority_queue, + dummy_time, + ); block_on(mailbox.recv(&mut counter, &dummy_context)).unwrap(); thread::sleep(std::time::Duration::from_millis(100)); } diff --git a/asynchronix/src/ports/source/broadcaster.rs b/asynchronix/src/ports/source/broadcaster.rs index cff1d50..95a07aa 100644 --- a/asynchronix/src/ports/source/broadcaster.rs +++ b/asynchronix/src/ports/source/broadcaster.rs @@ -497,8 +497,12 @@ mod tests { let dummy_priority_queue = Arc::new(Mutex::new(PriorityQueue::new())); let dummy_time = SyncCell::new(TearableAtomicTime::new(MonotonicTime::EPOCH)).reader(); - let dummy_context = - Context::new(dummy_address, dummy_priority_queue, dummy_time); + let dummy_context = Context::new( + String::new(), + dummy_address, + dummy_priority_queue, + dummy_time, + ); block_on(mailbox.recv(&mut counter, &dummy_context)).unwrap(); } }) @@ -548,8 +552,12 @@ mod tests { let dummy_priority_queue = Arc::new(Mutex::new(PriorityQueue::new())); let dummy_time = SyncCell::new(TearableAtomicTime::new(MonotonicTime::EPOCH)).reader(); - let dummy_context = - Context::new(dummy_address, dummy_priority_queue, dummy_time); + let dummy_context = Context::new( + String::new(), + dummy_address, + dummy_priority_queue, + dummy_time, + ); block_on(mailbox.recv(&mut counter, &dummy_context)).unwrap(); thread::sleep(std::time::Duration::from_millis(100)); } diff --git a/asynchronix/src/simulation.rs b/asynchronix/src/simulation.rs index 1d8d5f4..6be841e 100644 --- a/asynchronix/src/simulation.rs +++ b/asynchronix/src/simulation.rs @@ -666,13 +666,14 @@ impl Error for QueryError {} pub(crate) fn add_model( mut model: M, mailbox: Mailbox, + name: String, scheduler_queue: Arc>, time: SyncCellReader, executor: &Executor, ) { let sender = mailbox.0.sender(); - let context = Context::new(sender, scheduler_queue, time); + let context = Context::new(name, sender, scheduler_queue, time); let setup_context = SetupContext::new(&mailbox, &context, executor); model.setup(&setup_context); diff --git a/asynchronix/src/simulation/sim_init.rs b/asynchronix/src/simulation/sim_init.rs index ae22589..a8527ca 100644 --- a/asynchronix/src/simulation/sim_init.rs +++ b/asynchronix/src/simulation/sim_init.rs @@ -41,11 +41,27 @@ impl SimInit { } /// Adds a model and its mailbox to the simulation bench. - pub fn add_model(self, model: M, mailbox: Mailbox) -> Self { + /// + /// The `name` argument needs not be unique (it can be the empty string) and + /// is used for convenience for the model instance identification (e.g. for + /// logging purposes). + pub fn add_model( + self, + model: M, + mailbox: Mailbox, + name: impl Into, + ) -> Self { let scheduler_queue = self.scheduler_queue.clone(); let time = self.time.reader(); - add_model(model, mailbox, scheduler_queue, time, &self.executor); + add_model( + model, + mailbox, + name.into(), + scheduler_queue, + time, + &self.executor, + ); self } diff --git a/asynchronix/tests/model_scheduling.rs b/asynchronix/tests/model_scheduling.rs index 3f4afce..2a96408 100644 --- a/asynchronix/tests/model_scheduling.rs +++ b/asynchronix/tests/model_scheduling.rs @@ -33,7 +33,7 @@ fn model_schedule_event() { let addr = mbox.address(); let t0 = MonotonicTime::EPOCH; - let mut simu = SimInit::new().add_model(model, mbox).init(t0); + let mut simu = SimInit::new().add_model(model, mbox, "").init(t0); simu.process_event(TestModel::trigger, (), addr); simu.step(); @@ -78,7 +78,7 @@ fn model_cancel_future_keyed_event() { let addr = mbox.address(); let t0 = MonotonicTime::EPOCH; - let mut simu = SimInit::new().add_model(model, mbox).init(t0); + let mut simu = SimInit::new().add_model(model, mbox, "").init(t0); simu.process_event(TestModel::trigger, (), addr); simu.step(); @@ -124,7 +124,7 @@ fn model_cancel_same_time_keyed_event() { let addr = mbox.address(); let t0 = MonotonicTime::EPOCH; - let mut simu = SimInit::new().add_model(model, mbox).init(t0); + let mut simu = SimInit::new().add_model(model, mbox, "").init(t0); simu.process_event(TestModel::trigger, (), addr); simu.step(); @@ -166,7 +166,7 @@ fn model_schedule_periodic_event() { let addr = mbox.address(); let t0 = MonotonicTime::EPOCH; - let mut simu = SimInit::new().add_model(model, mbox).init(t0); + let mut simu = SimInit::new().add_model(model, mbox, "").init(t0); simu.process_event(TestModel::trigger, (), addr); @@ -216,7 +216,7 @@ fn model_cancel_periodic_event() { let addr = mbox.address(); let t0 = MonotonicTime::EPOCH; - let mut simu = SimInit::new().add_model(model, mbox).init(t0); + let mut simu = SimInit::new().add_model(model, mbox, "").init(t0); simu.process_event(TestModel::trigger, (), addr); diff --git a/asynchronix/tests/simulation_scheduling.rs b/asynchronix/tests/simulation_scheduling.rs index 6919091..3076931 100644 --- a/asynchronix/tests/simulation_scheduling.rs +++ b/asynchronix/tests/simulation_scheduling.rs @@ -38,7 +38,7 @@ fn passthrough_bench( model.output.connect_sink(&out_stream); let addr = mbox.address(); - let simu = SimInit::new().add_model(model, mbox).init(t0); + let simu = SimInit::new().add_model(model, mbox, "").init(t0); (simu, addr, out_stream) } @@ -246,7 +246,7 @@ fn timestamp_bench( let addr = mbox.address(); let simu = SimInit::new() - .add_model(model, mbox) + .add_model(model, mbox, "") .set_clock(clock) .init(t0);