Skip to content

Commit

Permalink
Merge pull request #4 from iscar-ucm/dev
Browse files Browse the repository at this point in the history
Faster and parallel
  • Loading branch information
romancardenas authored Jan 31, 2023
2 parents 9105a2e + 05cebf6 commit 9126160
Show file tree
Hide file tree
Showing 18 changed files with 727 additions and 693 deletions.
12 changes: 12 additions & 0 deletions .github/workflows/clippy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
on: push
name: Clippy check
jobs:
clippy_check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- run: rustup component add clippy
- uses: actions-rs/clippy-check@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
args: --all-features
24 changes: 24 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "(Windows) Launch",
"type": "cppvsdbg",
"request": "launch",
"program": "${workspaceRoot}/target/debug/foo.exe",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceRoot}",
"environment": [],
"externalConsole": true
},
{
"name": "(OSX) Launch",
"type": "lldb",
"request": "launch",
"program": "${workspaceRoot}/target/debug/xdevs",
"args": ["HO", "400", "400"],
"cwd": "${workspaceRoot}",
}
]
}
6 changes: 6 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"[rust]": {
"editor.defaultFormatter": "rust-lang.rust-analyzer",
"editor.formatOnSave": true
},
}
21 changes: 20 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "xdevs"
version = "0.1.1"
version = "0.2.0"
authors = ["Román Cárdenas <[email protected]>"]
edition = "2021"
description = "An open source DEVS M&S framework."
Expand All @@ -13,3 +13,22 @@ categories = ["simulation"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
rayon = { version = "1.6", optional = true }

[features]
par_any = ["rayon"]
par_start = ["par_any"]
par_collection = ["par_any"]
par_eoc = ["par_any"]
par_xic = ["par_any"]
par_transition = ["par_any"]
par_stop = ["par_any"]
par_xxc = ["par_eoc", "par_xic"]
par_sim_no_xxc = ["par_collection", "par_transition"]
par_sim = ["par_sim_no_xxc", "par_xxc"]
par_all_no_xxc = ["par_start", "par_sim_no_xxc", "par_stop"]
par_all = ["par_all_no_xxc", "par_xxc"]

[profile.release]
lto = true
panic = "unwind"
41 changes: 39 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,39 @@
# xdevs-rs
Version of the xDEVS simulator for Rust projects
# xDEVS.rs

Version of the xDEVS simulator for Rust projects.
It allows you to build and simulate computational models following the DEVS formalism.
Its API is easy to use for DEVS practitioners.
Currently, their main features are speed and parallelism.

## Blazingly fast 🚀

The Rust version of xDEVS is one of the fastests APIs currently available.
We will shortly publish some preliminary results to illustrate this.

## Fully configurable parallelism 🧶

We rely on the [`rayon`](https://github.com/rayon-rs/rayon) crate to provide parallelism for your simulations.
By default, all the simulation process is done sequentially. However, you can activate different features to
select where you want to take advantage of parallelism:

- `par_start`: it runs in parallel the start methods of your model before starting to simulate.
- `par_collection`: it executes the lambdas of your models in parallel.
- `par_eoc`: it propagates the EOCs in parallel (we do not recommend this feature, it is likely to be removed).
- `par_xic`: it propagates the EICs and ICs in parallel (we do not recommend this feature, it is likely to be removed).
- `par_transition`: it executes the deltas of your models in parallel (we **DO** recommend this feature).
- `par_stop`: it runs in parallel the stop methods of your model after the simulation.

### Useful combined features

We provide additional features to select handy combinations of features:

- `par_xxc`: alias for `par_eoc` and `par_xic` (we do not recommend this feature, it is likely to be removed).
- `par_sim_no_xcc`: alias for `par_collection` and `par_transition`.
- `par_sim`: alias for `par_xxc` and `par_sim_no_xcc` (we do not recommend this feature, it is likely to be removed).
- `par_all_no_xcc`: alias for `par_start`, `par_sim_no_xcc`, and `par_stop` (**this is our favourite**).
- `par_all`: alias for `par_xxc` and `par_all_no_xcc` (we do not recommend this feature, it is likely to be removed).

## Work in progress 👷‍♀️👷👷‍♂️

We are still working on this crate, and hope to add a plethora of cool features in the near future. Stay tuned!
If you want to contribute, feel free to open an issue on GitHub, we will reply ASAP.
19 changes: 8 additions & 11 deletions examples/gpt_efp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@ use std::env;
use xdevs::modeling::*;
use xdevs::simulation::*;

#[derive(Debug)]
struct Generator {
component: Component,
sigma: f64,
period: f64,
count: usize,
input: Port<Input, bool>,
output: Port<Output, usize>,
input: InPort<bool>,
output: OutPort<usize>,
}
impl Generator {
fn new(name: &str, period: f64) -> Self {
Expand Down Expand Up @@ -53,14 +52,13 @@ impl Atomic for Generator {
}
}

#[derive(Debug)]
struct Processor {
component: Component,
sigma: f64,
time: f64,
job: Option<usize>,
input: Port<Input, usize>,
output: Port<Output, (usize, f64)>,
input: InPort<usize>,
output: OutPort<(usize, f64)>,
}
impl Processor {
fn new(name: &str, time: f64) -> Self {
Expand Down Expand Up @@ -110,14 +108,14 @@ impl Atomic for Processor {
}
}

#[derive(Debug)]
struct Transducer {
component: Component,
sigma: f64,
input_g: Port<Input, usize>,
input_p: Port<Input, (usize, f64)>,
output: Port<Output, bool>,
input_g: InPort<usize>,
input_p: InPort<(usize, f64)>,
output: OutPort<bool>,
}

impl Transducer {
fn new(name: &str, time: f64) -> Self {
let mut component = Component::new(name);
Expand Down Expand Up @@ -171,7 +169,6 @@ impl Atomic for Transducer {
}
}

#[derive(Debug)]
struct ExperimentalFrame {
coupled: Coupled,
}
Expand Down
37 changes: 24 additions & 13 deletions src/devstone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ pub mod homod;
pub mod li;

use crate::modeling::*;
use std::cell::RefCell;
use std::rc::Rc;
use std::sync::{Arc, Mutex};

pub use hi::HI;
pub use ho::HO;
Expand All @@ -23,25 +22,24 @@ struct TestProbe {
n_events: usize,
}

#[derive(Debug)]
struct DEVStoneAtomic {
component: Component,
sigma: f64,
n_internals: usize,
n_externals: usize,
n_events: usize,
probe: Option<Rc<RefCell<TestProbe>>>,
input: Port<Input, usize>,
output: Port<Output, usize>,
probe: Option<Arc<Mutex<TestProbe>>>,
input: InPort<usize>,
output: OutPort<usize>,
}

impl DEVStoneAtomic {
pub fn new(name: &str, probe: Option<Rc<RefCell<TestProbe>>>) -> Self {
pub fn new(name: &str, probe: Option<Arc<Mutex<TestProbe>>>) -> Self {
let mut component = Component::new(name);
let input = component.add_in_port("input");
let output = component.add_out_port("output");
if let Some(p) = &probe {
p.borrow_mut().n_atomics += 1;
p.lock().unwrap().n_atomics += 1;
}
Self {
sigma: f64::INFINITY,
Expand All @@ -57,48 +55,55 @@ impl DEVStoneAtomic {
}

impl Atomic for DEVStoneAtomic {
#[inline]
fn get_component(&self) -> &Component {
&self.component
}

#[inline]
fn get_component_mut(&mut self) -> &mut Component {
&mut self.component
}

#[inline]
fn stop(&mut self) {
if let Some(t) = &self.probe {
let mut x = t.borrow_mut();
let mut x = t.lock().unwrap();
x.n_internals += self.n_internals;
x.n_externals += self.n_externals;
x.n_events += self.n_events;
}
}

#[inline]
fn lambda(&self) {
self.output.add_value(self.n_events);
}

#[inline]
fn delta_int(&mut self) {
self.n_internals += 1;
self.sigma = f64::INFINITY;
}

fn delta_ext(&mut self, _e: f64) {
self.n_externals += 1;
self.n_events += self.input.get_values().len();
if self.probe.is_some() {
self.n_externals += 1;
self.n_events += self.input.get_values().len();
}
self.sigma = 0.;
}

#[inline]
fn ta(&self) -> f64 {
self.sigma
}
}

#[derive(Debug)]
struct DEVStoneSeeder {
component: Component,
sigma: f64,
output: Port<Output, usize>,
output: OutPort<usize>,
}

impl DEVStoneSeeder {
Expand All @@ -114,26 +119,32 @@ impl DEVStoneSeeder {
}

impl Atomic for DEVStoneSeeder {
#[inline]
fn get_component(&self) -> &Component {
&self.component
}

#[inline]
fn get_component_mut(&mut self) -> &mut Component {
&mut self.component
}

#[inline]
fn lambda(&self) {
self.output.add_value(0);
}

#[inline]
fn delta_int(&mut self) {
self.sigma = f64::INFINITY;
}

#[inline]
fn delta_ext(&mut self, _e: f64) {
self.sigma = f64::INFINITY;
}

#[inline]
fn ta(&self) -> f64 {
self.sigma
}
Expand Down
37 changes: 21 additions & 16 deletions src/devstone/hi.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
use super::{DEVStoneAtomic, DEVStoneSeeder, TestProbe};
use crate::modeling::Coupled;
use crate::*;
use std::cell::RefCell;
use std::sync::{Arc, Mutex};

#[derive(Debug)]
pub struct HI {
pub coupled: Coupled,
}
Expand All @@ -20,7 +18,7 @@ impl HI {
coupled
}

fn _create_test(width: usize, depth: usize, probe: Rc<RefCell<TestProbe>>) -> Coupled {
fn _create_test(width: usize, depth: usize, probe: Arc<Mutex<TestProbe>>) -> Coupled {
let mut coupled = Coupled::new("HI");
let seeder = DEVStoneSeeder::new("seeder");
let hi = Self::new(width, depth, Some(probe));
Expand All @@ -31,7 +29,7 @@ impl HI {
coupled
}

fn new(width: usize, depth: usize, probe: Option<Rc<RefCell<TestProbe>>>) -> Self {
fn new(width: usize, depth: usize, probe: Option<Arc<Mutex<TestProbe>>>) -> Self {
// First we check the input parameters
if width < 1 {
panic!("width must be greater than 1")
Expand Down Expand Up @@ -70,9 +68,10 @@ impl HI {
}
// Before exiting, we update the probe if required
if let Some(p) = probe {
p.borrow_mut().n_eics += coupled.eic_vec.len();
p.borrow_mut().n_ics += coupled.ic_vec.len();
p.borrow_mut().n_eocs += coupled.eoc_vec.len()
let mut x = p.lock().unwrap();
x.n_eics += coupled.n_eics();
x.n_ics += coupled.n_ics();
x.n_eocs += coupled.n_eocs();
}
Self { coupled }
}
Expand Down Expand Up @@ -106,17 +105,23 @@ mod tests {
fn test_hi() {
for width in (1..50).step_by(5) {
for depth in (1..50).step_by(5) {
let probe = Rc::new(RefCell::new(TestProbe::default()));
let probe = Arc::new(Mutex::new(TestProbe::default()));
let coupled = HI::_create_test(width, depth, probe.clone());
assert_eq!(expected_atomics(width, depth), probe.borrow().n_atomics);
assert_eq!(expected_eics(width, depth), probe.borrow().n_eics);
assert_eq!(expected_ics(width, depth), probe.borrow().n_ics);
assert_eq!(depth, probe.borrow().n_eocs);
{
let x = probe.lock().unwrap();
assert_eq!(expected_atomics(width, depth), x.n_atomics);
assert_eq!(expected_eics(width, depth), x.n_eics);
assert_eq!(expected_ics(width, depth), x.n_ics);
assert_eq!(depth, x.n_eocs);
}
let mut simulator = RootCoordinator::new(coupled);
simulator.simulate_time(f64::INFINITY);
assert_eq!(expected_internals(width, depth), probe.borrow().n_internals);
assert_eq!(expected_internals(width, depth), probe.borrow().n_externals);
assert_eq!(expected_internals(width, depth), probe.borrow().n_events);
{
let x = probe.lock().unwrap();
assert_eq!(expected_internals(width, depth), x.n_internals);
assert_eq!(expected_internals(width, depth), x.n_externals);
assert_eq!(expected_internals(width, depth), x.n_events);
}
}
}
}
Expand Down
Loading

0 comments on commit 9126160

Please sign in to comment.