Skip to content

Commit

Permalink
Integrate SimX (https://github.com/ndebuhr/simx) into the core sim re…
Browse files Browse the repository at this point in the history
…pository, as a workspace member
  • Loading branch information
ndebuhr committed Feb 21, 2022
1 parent 18da9f3 commit f9f9a6c
Show file tree
Hide file tree
Showing 25 changed files with 471 additions and 9 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
key: ${{ runner.os }}-cargo-${{ matrix.rust }}-${{ hashFiles('./sim/Cargo.lock') }}
- name: Run Tests
working-directory: ./sim
run: cargo test
run: cargo test --all-features -- --nocapture

wasm-pack:
name: Test (wasm)
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
/target
/sim/target
/sim_derive/target
/simx/target

**/*.rs.bk

Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
members = [
"sim",
"sim_derive",
"simx",
]
1 change: 1 addition & 0 deletions sim/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
serde_yaml = "0.8"
sim_derive = { version = "0.10", path = "../sim_derive" }
simx = { version = "0.10", path = "../simx", optional = true }
thiserror = "1.0"
wasm-bindgen = "0.2"
web-sys = { version = "0.3", features = [ "console" ] }
Expand Down
5 changes: 5 additions & 0 deletions sim/src/models/batcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ use crate::utils::errors::SimulationError;

use sim_derive::SerializableModel;

#[cfg(feature = "simx")]
use simx::event_rules;

/// The batching process begins when the batcher receives a job. It will
/// then accept additional jobs, adding them to a batch with the first job,
/// until a max batching time or max batch size is reached - whichever comes
Expand Down Expand Up @@ -70,6 +73,7 @@ enum Phase {
Release, // Releasing a batch
}

#[cfg_attr(feature = "simx", event_rules)]
impl Batcher {
pub fn new(
job_in_port: String,
Expand Down Expand Up @@ -209,6 +213,7 @@ impl Batcher {
}
}

#[cfg_attr(feature = "simx", event_rules)]
impl DevsModel for Batcher {
fn events_ext(
&mut self,
Expand Down
5 changes: 5 additions & 0 deletions sim/src/models/exclusive_gateway.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ use crate::utils::errors::SimulationError;

use sim_derive::SerializableModel;

#[cfg(feature = "simx")]
use simx::event_rules;

/// The exclusive gateway splits a process flow into a set of possible paths.
/// The process will only follow one of the possible paths. Path selection is
/// determined by Weighted Index distribution random variates, so this atomic
Expand Down Expand Up @@ -65,6 +68,7 @@ enum Phase {
Pass, // Passing a job from input to output
}

#[cfg_attr(feature = "simx", event_rules)]
impl ExclusiveGateway {
pub fn new(
flow_paths_in: Vec<String>,
Expand Down Expand Up @@ -145,6 +149,7 @@ impl ExclusiveGateway {
}
}

#[cfg_attr(feature = "simx", event_rules)]
impl DevsModel for ExclusiveGateway {
fn events_ext(
&mut self,
Expand Down
5 changes: 5 additions & 0 deletions sim/src/models/gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ use crate::utils::errors::SimulationError;

use sim_derive::SerializableModel;

#[cfg(feature = "simx")]
use simx::event_rules;

/// The gate model passes or blocks jobs, when it is in the open or closed
/// state, respectively. The gate can be opened and closed throughout the
/// course of a simulation. This model contains no stochastic behavior - job
Expand Down Expand Up @@ -73,6 +76,7 @@ enum Phase {
Pass,
}

#[cfg_attr(feature = "simx", event_rules)]
impl Gate {
pub fn new(
job_in_port: String,
Expand Down Expand Up @@ -193,6 +197,7 @@ impl Gate {
}
}

#[cfg_attr(feature = "simx", event_rules)]
impl DevsModel for Gate {
fn events_ext(
&mut self,
Expand Down
5 changes: 5 additions & 0 deletions sim/src/models/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ use crate::utils::errors::SimulationError;

use sim_derive::SerializableModel;

#[cfg(feature = "simx")]
use simx::event_rules;

/// The generator produces jobs based on a configured interarrival
/// distribution. A normalized thinning function is used to enable
/// non-stationary job generation. For non-stochastic generation of jobs, a
Expand Down Expand Up @@ -69,6 +72,7 @@ enum Phase {
Generating,
}

#[cfg_attr(feature = "simx", event_rules)]
impl Generator {
pub fn new(
message_interdeparture_time: ContinuousRandomVariable,
Expand Down Expand Up @@ -137,6 +141,7 @@ impl Generator {
}
}

#[cfg_attr(feature = "simx", event_rules)]
impl DevsModel for Generator {
fn events_ext(
&mut self,
Expand Down
12 changes: 8 additions & 4 deletions sim/src/models/load_balancer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ use crate::utils::errors::SimulationError;

use sim_derive::SerializableModel;

#[cfg(feature = "simx")]
use simx::event_rules;

/// The load balancer routes jobs to a set of possible process paths, using a
/// round robin strategy. There is no stochastic behavior in this model.
#[derive(Debug, Clone, Serialize, Deserialize, SerializableModel)]
Expand Down Expand Up @@ -61,6 +64,7 @@ enum Phase {
LoadBalancing,
}

#[cfg_attr(feature = "simx", event_rules)]
impl LoadBalancer {
pub fn new(job_port: String, flow_path_ports: Vec<String>, store_records: bool) -> Self {
Self {
Expand Down Expand Up @@ -124,6 +128,7 @@ impl LoadBalancer {
}
}

#[cfg_attr(feature = "simx", event_rules)]
impl DevsModel for LoadBalancer {
fn events_ext(
&mut self,
Expand All @@ -137,10 +142,9 @@ impl DevsModel for LoadBalancer {
&mut self,
services: &mut Services,
) -> Result<Vec<ModelMessage>, SimulationError> {
if self.state.jobs.is_empty() {
self.passivate()
} else {
self.send_job(services)
match self.state.jobs.len() {
0 => self.passivate(),
_ => self.send_job(services),
}
}

Expand Down
10 changes: 10 additions & 0 deletions sim/src/models/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,16 @@ impl DevsModel for Model {
fn until_next_event(&self) -> f64 {
self.inner.until_next_event()
}

#[cfg(feature = "simx")]
fn event_rules_scheduling(&self) -> &str {
self.inner.event_rules_scheduling()
}

#[cfg(feature = "simx")]
fn event_rules(&self) -> String {
self.inner.event_rules()
}
}

impl Reportable for Model {
Expand Down
4 changes: 4 additions & 0 deletions sim/src/models/model_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ pub trait DevsModel: ModelClone + SerializableModel {
-> Result<Vec<ModelMessage>, SimulationError>;
fn time_advance(&mut self, time_delta: f64);
fn until_next_event(&self) -> f64;
#[cfg(feature = "simx")]
fn event_rules_scheduling(&self) -> &str;
#[cfg(feature = "simx")]
fn event_rules(&self) -> String;
}

/// The additional status and record-keeping methods of `Reportable` provide
Expand Down
12 changes: 8 additions & 4 deletions sim/src/models/parallel_gateway.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ use crate::utils::errors::SimulationError;

use sim_derive::SerializableModel;

#[cfg(feature = "simx")]
use simx::event_rules;

/// The parallel gateway splits a job across multiple processing paths. The
/// job is duplicated across every one of the processing paths. In addition
/// to splitting the process, a second parallel gateway can be used to join
Expand Down Expand Up @@ -61,6 +64,7 @@ impl Default for State {
}
}

#[cfg_attr(feature = "simx", event_rules)]
impl ParallelGateway {
pub fn new(
flow_paths_in: Vec<String>,
Expand Down Expand Up @@ -160,6 +164,7 @@ impl ParallelGateway {
}
}

#[cfg_attr(feature = "simx", event_rules)]
impl DevsModel for ParallelGateway {
fn events_ext(
&mut self,
Expand All @@ -176,10 +181,9 @@ impl DevsModel for ParallelGateway {
&mut self,
services: &mut Services,
) -> Result<Vec<ModelMessage>, SimulationError> {
if self.full_collection().is_some() {
self.send_job(services)
} else {
self.passivate()
match self.full_collection() {
Some(_) => self.send_job(services),
None => self.passivate(),
}
}

Expand Down
5 changes: 5 additions & 0 deletions sim/src/models/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ use crate::utils::errors::SimulationError;

use sim_derive::SerializableModel;

#[cfg(feature = "simx")]
use simx::event_rules;

/// The processor accepts jobs, processes them for a period of time, and then
/// outputs a processed job. The processor can have a configurable queue, of
/// size 0 to infinity, inclusive. The default queue size is infinite. The
Expand Down Expand Up @@ -81,6 +84,7 @@ enum Phase {
Passive,
}

#[cfg_attr(feature = "simx", event_rules)]
impl Processor {
pub fn new(
service_time: ContinuousRandomVariable,
Expand Down Expand Up @@ -206,6 +210,7 @@ impl Processor {
}
}

#[cfg_attr(feature = "simx", event_rules)]
impl DevsModel for Processor {
fn events_ext(
&mut self,
Expand Down
5 changes: 5 additions & 0 deletions sim/src/models/stochastic_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ use crate::utils::errors::SimulationError;

use sim_derive::SerializableModel;

#[cfg(feature = "simx")]
use simx::event_rules;

/// The stochastic gate blocks (drops) or passes jobs, based on a specified
/// Bernoulli distribution. If the Bernoulli random variate is a 0, the job
/// will be dropped. If the Bernoulli random variate is a 1, the job will be
Expand Down Expand Up @@ -67,6 +70,7 @@ pub struct Job {
pub pass: bool,
}

#[cfg_attr(feature = "simx", event_rules)]
impl StochasticGate {
pub fn new(
pass_distribution: BooleanRandomVariable,
Expand Down Expand Up @@ -148,6 +152,7 @@ impl StochasticGate {
}
}

#[cfg_attr(feature = "simx", event_rules)]
impl DevsModel for StochasticGate {
fn events_ext(
&mut self,
Expand Down
5 changes: 5 additions & 0 deletions sim/src/models/stopwatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ use crate::utils::errors::SimulationError;

use sim_derive::SerializableModel;

#[cfg(feature = "simx")]
use simx::event_rules;

/// The stopwatch calculates durations by matching messages on the start and
/// stop ports. For example, a "job 1" message arrives at the start port at
/// time 0.1, and then a "job 1" message arrives at the stop port at time
Expand Down Expand Up @@ -95,6 +98,7 @@ pub struct Job {
stop: Option<f64>,
}

#[cfg_attr(feature = "simx", event_rules)]
impl Stopwatch {
pub fn new(
start_port: String,
Expand Down Expand Up @@ -279,6 +283,7 @@ impl Stopwatch {
}
}

#[cfg_attr(feature = "simx", event_rules)]
impl DevsModel for Stopwatch {
fn events_ext(
&mut self,
Expand Down
5 changes: 5 additions & 0 deletions sim/src/models/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ use crate::utils::errors::SimulationError;

use sim_derive::SerializableModel;

#[cfg(feature = "simx")]
use simx::event_rules;

/// The storage model stores a value, and responds with it upon request.
/// Values are stored and value requests are handled instantantaneously.
#[derive(Debug, Clone, Serialize, Deserialize, SerializableModel)]
Expand Down Expand Up @@ -66,6 +69,7 @@ enum Phase {
JobFetch,
}

#[cfg_attr(feature = "simx", event_rules)]
impl Storage {
pub fn new(
put_port: String,
Expand Down Expand Up @@ -153,6 +157,7 @@ impl Storage {
}
}

#[cfg_attr(feature = "simx", event_rules)]
impl DevsModel for Storage {
fn events_ext(
&mut self,
Expand Down
1 change: 1 addition & 0 deletions sim/tests/batcher_event_rules.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{"event_expression":"new","event_parameters":["job_in_port","job_out_port","max_batch_time","max_batch_size","store_records"],"event_routine":{"state_transitions":[],"scheduling":[{"event_expression_target":"events_int","parameters":[],"condition":null,"delay":"\\sigma"}],"cancelling":[]}},{"event_expression":"add_to_batch","event_parameters":["incoming_message","services"],"event_routine":{"state_transitions":[["self.state.phase","Phase :: Batching"]],"scheduling":[{"event_expression_target":"events_int","parameters":[],"condition":null,"delay":"\\sigma"}],"cancelling":[]}},{"event_expression":"start_batch","event_parameters":["incoming_message","services"],"event_routine":{"state_transitions":[["self.state.phase","Phase :: Batching"],["self.state.until_next_event","self.max_batch_time"]],"scheduling":[{"event_expression_target":"events_int","parameters":[],"condition":null,"delay":"\\sigma"}],"cancelling":[]}},{"event_expression":"fill_batch","event_parameters":["incoming_message","services"],"event_routine":{"state_transitions":[["self.state.phase","Phase :: Release"],["self.state.until_next_event","0.0"]],"scheduling":[{"event_expression_target":"events_int","parameters":[],"condition":null,"delay":"\\sigma"}],"cancelling":[]}},{"event_expression":"release_full_queue","event_parameters":["services"],"event_routine":{"state_transitions":[["self.state.phase","Phase :: Passive"],["self.state.until_next_event","INFINITY"]],"scheduling":[{"event_expression_target":"events_int","parameters":[],"condition":null,"delay":"\\sigma"}],"cancelling":[]}},{"event_expression":"release_partial_queue","event_parameters":["services"],"event_routine":{"state_transitions":[["self.state.phase","Phase :: Batching"],["self.state.until_next_event","self.max_batch_time"]],"scheduling":[{"event_expression_target":"events_int","parameters":[],"condition":null,"delay":"\\sigma"}],"cancelling":[]}},{"event_expression":"release_multiple","event_parameters":["services"],"event_routine":{"state_transitions":[["self.state.phase","Phase :: Release"],["self.state.until_next_event","0.0"]],"scheduling":[{"event_expression_target":"events_int","parameters":[],"condition":null,"delay":"\\sigma"}],"cancelling":[]}},{"event_expression":"record","event_parameters":["time","action","subject"],"event_routine":{"state_transitions":[],"scheduling":[{"event_expression_target":"events_int","parameters":[],"condition":null,"delay":"\\sigma"}],"cancelling":[]}},{"event_expression":"events_ext","event_parameters":["incoming_message","services"],"event_routine":{"state_transitions":[],"scheduling":[{"event_expression_target":"add_to_batch","parameters":[],"condition":"(& self.state.phase, self.state.jobs.len() + 1 < self.max_batch_size,) = (Phase :: Batching, true)","delay":null},{"event_expression_target":"start_batch","parameters":[],"condition":"(& self.state.phase, self.state.jobs.len() + 1 < self.max_batch_size,) = (Phase :: Passive, true)","delay":null},{"event_expression_target":"fill_batch","parameters":[],"condition":"(& self.state.phase, self.state.jobs.len() + 1 < self.max_batch_size,) = (_, false)","delay":null}],"cancelling":[{"event_expression_target":"events_int","parameters":[],"condition":null,"delay":null}]}},{"event_expression":"events_int","event_parameters":["services"],"event_routine":{"state_transitions":[],"scheduling":[{"event_expression_target":"release_full_queue","parameters":[],"condition":"(self.state.jobs.len() <= self.max_batch_size, self.state.jobs.len() >= 2 *\n self.max_batch_size,) = (true, false)","delay":null},{"event_expression_target":"release_multiple","parameters":[],"condition":"(self.state.jobs.len() <= self.max_batch_size, self.state.jobs.len() >= 2 *\n self.max_batch_size,) = (false, true)","delay":null},{"event_expression_target":"release_partial_queue","parameters":[],"condition":"(self.state.jobs.len() <= self.max_batch_size, self.state.jobs.len() >= 2 *\n self.max_batch_size,) = (false, false)","delay":null}],"cancelling":[]}}]
5 changes: 5 additions & 0 deletions sim/tests/custom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ use sim::utils::errors::SimulationError;
use sim_derive::{register, SerializableModel};
use wasm_bindgen_test::*;

#[cfg(feature = "simx")]
use simx::event_rules;

wasm_bindgen_test_configure!(run_in_browser);

/// The passive model does nothing
Expand All @@ -30,6 +33,7 @@ struct State {
records: Vec<ModelRecord>,
}

#[cfg_attr(feature = "simx", event_rules)]
impl Passive {
pub fn new(job_port: String) -> Self {
Self {
Expand All @@ -41,6 +45,7 @@ impl Passive {
}
}

#[cfg_attr(feature = "simx", event_rules)]
impl DevsModel for Passive {
fn events_ext(
&mut self,
Expand Down
Loading

0 comments on commit f9f9a6c

Please sign in to comment.