DScale
This project provides a fast & deterministic simulation framework for testing and benchmarking distributed systems. It simulates network latency, bandwidth constraints, and process execution in a single-threaded, event-driven environment.
Usage
To use the DScale, you need to implement the ProcessHandle trait for your distributed system and the Message trait for the data exchanged between processes.
1. Define Messages
Messages must implement the Message trait, which allows defining a VirtualSize for bandwidth simulation.
use Message;
2. Implement Process Logic
Implement ProcessHandle to define how your process reacts to initialization, messages, and timers.
use ;
use ;
use configuration;
;
3. Run the Simulation
Use SimulationBuilder to configure the topology, network constraints, and start the simulation.
use ;
Public API
Simulation Control
SimulationBuilder: Configures the simulation environment.NewDefault(): Creates simulation with no processes and default parameters.Seed(u64): Sets the random seed for deterministic execution.TimeBudget(Jiffies): Sets the maximum duration of the simulation.AddPool<P: ProcessHandle + Default + 'static>(&str, usize): Creates a pool of processes.LatencyTopology(&[LatencyDescription]): Configures network latency between pools or within them.NICBandwidth(BandwidthDescription): Configures network bandwidth limits (per process).Bounded(usize): Limits bandwidth (bytes per jiffy).Unbounded: No bandwidth limits.
Build() -> Simulation: Finalizes configuration and builds the simulation engine.
Simulation: The engine driving the event loop.Run(): Starts the simulation loop.
Network Topology
LatencyDescription:WithinPool(&str, Distributions): Latency for messages between processes in the same pool.BetweenPools(&str, &str, Distributions): Latency for messages between processes in different pools.
Distributions:Uniform(Jiffies, Jiffies)Bernoulli(f64, Jiffies)Normal(Jiffies, Jiffies)
Process Interaction (Context-Aware)
These functions are available globally but must be called within the context of a running process step.
Broadcast(impl Message): Sends a message to all other processes.BroadcastWithinPool(&str, impl Message): Sends a message to all other processes within a specific pool.SendTo(ProcessId, impl Message): Sends a message to a specific process.SendRandomFromPool(&str, impl Message): Sends a message to random process whithin pool.ScheduleTimerAfter(Jiffies) -> TimerId: Schedules a timer interrupt for the current process.Rank() -> ProcessId: Returns the ID of the currently executing process.Now() -> Jiffies: Returns current simulation time.ListPool(&str) -> Vec<ProcessId>: List all processes in a pool.ChooseFromPool(&str) -> ProcessId: Choose random process id from specified pool.GlobalUniqueId() -> usize: Generates a globally unique ID.
Configuration (dscale::global::configuration)
Seed() -> u64: Returns the specific seed for the current process.ProcessNumber() -> usize: Returns total number of processes in the simulation.
Any Key-Value (dscale::global::anykv)
Useful for passing shared state, metrics, or configuration between processes or back to the host.
Get<T>(&str) -> TSet<T>(&str, T)Modify<T>(&str, impl FnOnce(&mut T)): Modify in-place.
Logging & Debugging
Debug!(fmt, ...): A macro that automatically prepends current simulation time and process ID.
Logging Configuration (RUST_LOG)
DScale output is controlled via the RUST_LOG environment variable.
-
RUST_LOG=info: Shows high-level simulation status and a progress bar. -
RUST_LOG=debug: Enables theDebug!macro output and internal simulation events. -
RUST_LOG=your_crate=debug: Filter events only for your specific crate. -
Note
RUST_LOG=debug or RUST_LOG=any=debugwill work only without the--releaseflag.