Skip to content

Commit afb6af7

Browse files
committed
Seed tokio runtimes using the world rng
If the `tokio_unstable` flag is set, seed host and client runtimes using the world rng. This makes the simulation more deterministic. In particular, the order in which tokio polls `select!` branches is determined by this seed.
1 parent ca6adbb commit afb6af7

File tree

2 files changed

+28
-9
lines changed

2 files changed

+28
-9
lines changed

src/rt.rs

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::mem;
33
use std::pin::Pin;
44
use std::sync::Arc;
55

6+
use rand::rngs::SmallRng;
67
use tokio::runtime::Runtime;
78
use tokio::task::JoinHandle;
89
use tokio::task::LocalSet;
@@ -33,6 +34,11 @@ pub enum Kind<'a> {
3334
pub struct Config {
3435
/// Whether io is enabled on the runtime.
3536
pub enable_io: bool,
37+
38+
/// Rng used to seed the tokio runtime.
39+
///
40+
/// Only used if the `tokio_unstable` cfg flag is set.
41+
pub rng: Option<SmallRng>,
3642
}
3743

3844
/// Per host simulated runtime.
@@ -62,11 +68,11 @@ pub struct Rt<'a> {
6268
}
6369

6470
impl<'a> Rt<'a> {
65-
pub(crate) fn client<F>(nodename: Arc<str>, client: F, config: Config) -> Self
71+
pub(crate) fn client<F>(nodename: Arc<str>, client: F, mut config: Config) -> Self
6672
where
6773
F: Future<Output = Result> + 'static,
6874
{
69-
let (tokio, local) = init(&config);
75+
let (tokio, local) = init(&mut config);
7076

7177
let handle = with(&tokio, &local, || tokio::task::spawn_local(client));
7278

@@ -80,12 +86,12 @@ impl<'a> Rt<'a> {
8086
}
8187
}
8288

83-
pub(crate) fn host<F, Fut>(nodename: Arc<str>, software: F, config: Config) -> Self
89+
pub(crate) fn host<F, Fut>(nodename: Arc<str>, software: F, mut config: Config) -> Self
8490
where
8591
F: Fn() -> Fut + 'a,
8692
Fut: Future<Output = Result> + 'static,
8793
{
88-
let (tokio, local) = init(&config);
94+
let (tokio, local) = init(&mut config);
8995

9096
let software: Software = Box::new(move || Box::pin(software()));
9197
let handle = with(&tokio, &local, || tokio::task::spawn_local(software()));
@@ -101,8 +107,8 @@ impl<'a> Rt<'a> {
101107
}
102108

103109
pub(crate) fn no_software() -> Self {
104-
let config = Config::default();
105-
let (tokio, local) = init(&config);
110+
let mut config = Config::default();
111+
let (tokio, local) = init(&mut config);
106112

107113
Self {
108114
kind: Kind::NoSoftware,
@@ -215,14 +221,14 @@ impl<'a> Rt<'a> {
215221
///
216222
/// Both the [`Runtime`] and [`LocalSet`] are replaced with new instances.
217223
fn cancel_tasks(&mut self) {
218-
let (tokio, local) = init(&self.config);
224+
let (tokio, local) = init(&mut self.config);
219225

220226
_ = mem::replace(&mut self.tokio, tokio);
221227
drop(mem::replace(&mut self.local, local));
222228
}
223229
}
224230

225-
fn init(config: &Config) -> (Runtime, LocalSet) {
231+
fn init(config: &mut Config) -> (Runtime, LocalSet) {
226232
let mut tokio_builder = tokio::runtime::Builder::new_current_thread();
227233

228234
#[cfg(tokio_unstable)]
@@ -232,6 +238,13 @@ fn init(config: &Config) -> (Runtime, LocalSet) {
232238
tokio_builder.enable_io();
233239
}
234240

241+
#[cfg(tokio_unstable)]
242+
if let Some(rng) = &mut config.rng {
243+
let bytes: [u8; 32] = rand::Rng::gen(rng);
244+
let seed = tokio::runtime::RngSeed::from_bytes(&bytes);
245+
tokio_builder.rng_seed(seed);
246+
}
247+
235248
let tokio = tokio_builder
236249
.enable_time()
237250
.start_paused(true)

src/sim.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use rand::seq::SliceRandom;
1+
use rand::{rngs::SmallRng, seq::SliceRandom, Rng, SeedableRng};
22
use std::cell::RefCell;
33
use std::future::Future;
44
use std::net::IpAddr;
@@ -91,8 +91,11 @@ impl<'a> Sim<'a> {
9191
world.register(addr, &nodename, HostTimer::new(self.elapsed), &self.config);
9292
}
9393

94+
let seed = self.world.borrow_mut().rng.gen();
95+
let rng = SmallRng::from_seed(seed);
9496
let config = rt::Config {
9597
enable_io: self.config.enable_tokio_io,
98+
rng: Some(rng),
9699
};
97100

98101
let rt = World::enter(&self.world, || Rt::client(nodename, client, config));
@@ -128,8 +131,11 @@ impl<'a> Sim<'a> {
128131
world.register(addr, &nodename, HostTimer::new(self.elapsed), &self.config);
129132
}
130133

134+
let seed = self.world.borrow_mut().rng.gen();
135+
let rng = SmallRng::from_seed(seed);
131136
let config = rt::Config {
132137
enable_io: self.config.enable_tokio_io,
138+
rng: Some(rng),
133139
};
134140

135141
let rt = World::enter(&self.world, || Rt::host(nodename, host, config));

0 commit comments

Comments
 (0)