DScale
A fast, deterministic simulation framework for testing and benchmarking distributed systems. It simulates network latency, bandwidth constraints, and process execution in an event-driven environment with support for both single-threaded and parallel execution modes.
Usage
1. Define Messages
Messages must implement the Message trait, which allows defining a virtual_size for bandwidth simulation.
use *;
// Or (if there is no need in bandwidth)
2. Implement Process Logic
Implement Process to define how your process reacts to initialization, messages, and timers.
use *;
;
3. Run the Simulation
Use SimulationBuilder to configure the topology, network constraints, and start the simulation.
use *;
Parallel Execution
For large simulations, enable parallel execution to distribute process steps across multiple threads:
let mut runner = new
.
.within_pool_latency
.time_budget
.par_sched // use 8 worker threads
.build;
runner.run_full_budget;
When is the parallel scheduler efficient?
- A lot of simulated processes (at least 200-300)
- on_message/on_timer execution takes most of the simulation time
- Independent work inside on_message/on_timer handlers (not so much synchronization)
Omtimizations
For faster simulations we advise you to use these settings in your Cargo.toml:
lto = "fat" # Link Time Optimization: enables cross-crate optimizations
codegen-units = 1 # Reduces parallelism in code generation for better optimization
panic = "abort" # Removes stack unwinding code, slightly smaller and faster binary
Distributing a Simulation Series over MPI
Enable the optional mpi feature:
= { = "0.8", = ["mpi"] }
To sweep parameters across an MPI cluster, hand mpi::distribute your argument
packs and a closure that builds and runs one simulation per pack. Launch the
binary with mpirun — each rank runs its own slice of the packs.
use *;
No MPI library linkage is needed — only the launcher, which sets the rank/size environment variables DScale reads (OpenMPI, MPICH/Hydra, and Slurm are supported). Without a launcher the program runs the full series in one process.
Fault Injection
DScale supports injecting network faults into simulations. Faults are scheduled as events — you specify when a fault starts and when it ends.
let mut runner = new
.
.within_pool_latency
.time_budget
// Break the link between pid 0 and pid 1 from time 100 to 500
.break_link
// Isolate pid 2 (all links broken) from time 200 to 800
.isolate
.seq_sched
.build;
runner.run_full_budget;
The full API reference — every SimulationBuilder method, process
interaction function, the key-value store, logging macros, and helpers — is
documented and published on docs.rs.
Logging Configuration (RUST_LOG)
DScale output is controlled via the RUST_LOG environment variable.
RUST_LOG=[some_level]: Enables alldscale_[level <= some_level]!macros output.RUST_LOG=full::path::to::your::file::or::crate=[level],another::path=[level]: Filter events only for your specific file or crate.
[!WARNING]
RUST_LOG=[level > info]only works without the--releaseflag.
Examples
You can find usage examples here
Paper
You can find paper describing algorithms behind dscale here