Simulatios network throughput (#270)
* Use step time from configuration * PayloadSize trait for inmemory network interface * Per node network capacity * Initial carnot message sizes * Divide provided kbps by step time * Use std::mem::size_of for msg sizes
This commit is contained in:
parent
7d64915dd7
commit
df97ea2543
|
@ -80,8 +80,14 @@ impl SimulationApp {
|
||||||
let (node_message_broadcast_sender, node_message_broadcast_receiver) =
|
let (node_message_broadcast_sender, node_message_broadcast_receiver) =
|
||||||
channel::unbounded();
|
channel::unbounded();
|
||||||
let (node_message_sender, node_message_receiver) = channel::unbounded();
|
let (node_message_sender, node_message_receiver) = channel::unbounded();
|
||||||
|
// Dividing milliseconds in second by milliseconds in the step.
|
||||||
|
let step_time_as_second_fraction =
|
||||||
|
1_000_000 / simulation_settings.step_time.subsec_millis();
|
||||||
|
let capacity_bps = simulation_settings.node_settings.network_capacity_kbps * 1024
|
||||||
|
/ step_time_as_second_fraction;
|
||||||
let network_message_receiver = network.connect(
|
let network_message_receiver = network.connect(
|
||||||
node_id,
|
node_id,
|
||||||
|
capacity_bps,
|
||||||
node_message_receiver,
|
node_message_receiver,
|
||||||
node_message_broadcast_receiver,
|
node_message_broadcast_receiver,
|
||||||
);
|
);
|
||||||
|
|
|
@ -3,10 +3,12 @@ use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
ops::Add,
|
ops::Add,
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
|
sync::atomic::{AtomicU32, Ordering},
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
// crates
|
// crates
|
||||||
use crossbeam::channel::{self, Receiver, Sender};
|
use crossbeam::channel::{self, Receiver, Sender};
|
||||||
|
use parking_lot::Mutex;
|
||||||
use rand::{rngs::SmallRng, Rng, SeedableRng};
|
use rand::{rngs::SmallRng, Rng, SeedableRng};
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -101,10 +103,48 @@ mod network_behaviors_serde {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents node network capacity and current load in bytes.
|
||||||
|
struct NodeNetworkCapacity {
|
||||||
|
capacity_bps: u32,
|
||||||
|
current_load: Mutex<u32>,
|
||||||
|
load_to_flush: AtomicU32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NodeNetworkCapacity {
|
||||||
|
fn new(capacity_bps: u32) -> Self {
|
||||||
|
Self {
|
||||||
|
capacity_bps,
|
||||||
|
current_load: Mutex::new(0),
|
||||||
|
load_to_flush: AtomicU32::new(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn increase_load(&self, load: u32) -> bool {
|
||||||
|
let mut current_load = self.current_load.lock();
|
||||||
|
if *current_load + load <= self.capacity_bps {
|
||||||
|
*current_load += load;
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decrease_load(&self, load: u32) {
|
||||||
|
self.load_to_flush.fetch_add(load, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush_load(&self) {
|
||||||
|
let mut s = self.current_load.lock();
|
||||||
|
*s -= self.load_to_flush.load(Ordering::Relaxed);
|
||||||
|
self.load_to_flush.store(0, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Network<M: std::fmt::Debug> {
|
pub struct Network<M: std::fmt::Debug> {
|
||||||
pub regions: regions::RegionsData,
|
pub regions: regions::RegionsData,
|
||||||
network_time: NetworkTime,
|
network_time: NetworkTime,
|
||||||
messages: Vec<(NetworkTime, NetworkMessage<M>)>,
|
messages: Vec<(NetworkTime, NetworkMessage<M>)>,
|
||||||
|
node_network_capacity: HashMap<NodeId, NodeNetworkCapacity>,
|
||||||
from_node_receivers: HashMap<NodeId, Receiver<NetworkMessage<M>>>,
|
from_node_receivers: HashMap<NodeId, Receiver<NetworkMessage<M>>>,
|
||||||
from_node_broadcast_receivers: HashMap<NodeId, Receiver<NetworkMessage<M>>>,
|
from_node_broadcast_receivers: HashMap<NodeId, Receiver<NetworkMessage<M>>>,
|
||||||
to_node_senders: HashMap<NodeId, Sender<NetworkMessage<M>>>,
|
to_node_senders: HashMap<NodeId, Sender<NetworkMessage<M>>>,
|
||||||
|
@ -120,6 +160,7 @@ where
|
||||||
regions,
|
regions,
|
||||||
network_time: Instant::now(),
|
network_time: Instant::now(),
|
||||||
messages: Vec::new(),
|
messages: Vec::new(),
|
||||||
|
node_network_capacity: HashMap::new(),
|
||||||
from_node_receivers: HashMap::new(),
|
from_node_receivers: HashMap::new(),
|
||||||
from_node_broadcast_receivers: HashMap::new(),
|
from_node_broadcast_receivers: HashMap::new(),
|
||||||
to_node_senders: HashMap::new(),
|
to_node_senders: HashMap::new(),
|
||||||
|
@ -142,9 +183,12 @@ where
|
||||||
pub fn connect(
|
pub fn connect(
|
||||||
&mut self,
|
&mut self,
|
||||||
node_id: NodeId,
|
node_id: NodeId,
|
||||||
|
capacity_bps: u32,
|
||||||
node_message_receiver: Receiver<NetworkMessage<M>>,
|
node_message_receiver: Receiver<NetworkMessage<M>>,
|
||||||
node_message_broadcast_receiver: Receiver<NetworkMessage<M>>,
|
node_message_broadcast_receiver: Receiver<NetworkMessage<M>>,
|
||||||
) -> Receiver<NetworkMessage<M>> {
|
) -> Receiver<NetworkMessage<M>> {
|
||||||
|
self.node_network_capacity
|
||||||
|
.insert(node_id, NodeNetworkCapacity::new(capacity_bps));
|
||||||
let (to_node_sender, from_network_receiver) = channel::unbounded();
|
let (to_node_sender, from_network_receiver) = channel::unbounded();
|
||||||
self.from_node_receivers
|
self.from_node_receivers
|
||||||
.insert(node_id, node_message_receiver);
|
.insert(node_id, node_message_receiver);
|
||||||
|
@ -206,6 +250,10 @@ where
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
for (_, c) in self.node_network_capacity.iter() {
|
||||||
|
c.flush_load();
|
||||||
|
}
|
||||||
|
|
||||||
self.messages = delayed;
|
self.messages = delayed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,11 +266,15 @@ where
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let to = message.to.expect("adhoc message has recipient");
|
let to = message.to.expect("adhoc message has recipient");
|
||||||
if let Some(delay) = self.send_message_cost(rng, message.from, to) {
|
if let Some(delay) = self.send_message_cost(rng, message.from, to) {
|
||||||
if network_time.add(delay) <= self.network_time {
|
let node_capacity = self.node_network_capacity.get(&to).unwrap();
|
||||||
|
if network_time.add(delay) <= self.network_time
|
||||||
|
&& node_capacity.increase_load(message.size_bytes)
|
||||||
|
{
|
||||||
let to_node = self.to_node_senders.get(&to).unwrap();
|
let to_node = self.to_node_senders.get(&to).unwrap();
|
||||||
to_node
|
to_node
|
||||||
.send(message.clone())
|
.send(message.clone())
|
||||||
.expect("Node should have connection");
|
.expect("node should have connection");
|
||||||
|
node_capacity.decrease_load(message.size_bytes);
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
|
@ -237,11 +289,17 @@ pub struct NetworkMessage<M> {
|
||||||
pub from: NodeId,
|
pub from: NodeId,
|
||||||
pub to: Option<NodeId>,
|
pub to: Option<NodeId>,
|
||||||
pub payload: M,
|
pub payload: M,
|
||||||
|
pub size_bytes: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M> NetworkMessage<M> {
|
impl<M> NetworkMessage<M> {
|
||||||
pub fn new(from: NodeId, to: Option<NodeId>, payload: M) -> Self {
|
pub fn new(from: NodeId, to: Option<NodeId>, payload: M, size_bytes: u32) -> Self {
|
||||||
Self { from, to, payload }
|
Self {
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
payload,
|
||||||
|
size_bytes,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_payload(self) -> M {
|
pub fn get_payload(self) -> M {
|
||||||
|
@ -249,6 +307,10 @@ impl<M> NetworkMessage<M> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait PayloadSize {
|
||||||
|
fn size_bytes(&self) -> u32;
|
||||||
|
}
|
||||||
|
|
||||||
pub trait NetworkInterface {
|
pub trait NetworkInterface {
|
||||||
type Payload;
|
type Payload;
|
||||||
|
|
||||||
|
@ -280,16 +342,18 @@ impl<M> InMemoryNetworkInterface<M> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M> NetworkInterface for InMemoryNetworkInterface<M> {
|
impl<M: PayloadSize> NetworkInterface for InMemoryNetworkInterface<M> {
|
||||||
type Payload = M;
|
type Payload = M;
|
||||||
|
|
||||||
fn broadcast(&self, message: Self::Payload) {
|
fn broadcast(&self, message: Self::Payload) {
|
||||||
let message = NetworkMessage::new(self.id, None, message);
|
let size = message.size_bytes();
|
||||||
|
let message = NetworkMessage::new(self.id, None, message, size);
|
||||||
self.broadcast.send(message).unwrap();
|
self.broadcast.send(message).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_message(&self, address: NodeId, message: Self::Payload) {
|
fn send_message(&self, address: NodeId, message: Self::Payload) {
|
||||||
let message = NetworkMessage::new(self.id, Some(address), message);
|
let size = message.size_bytes();
|
||||||
|
let message = NetworkMessage::new(self.id, Some(address), message, size);
|
||||||
self.sender.send(message).unwrap();
|
self.sender.send(message).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,12 +403,12 @@ mod tests {
|
||||||
type Payload = ();
|
type Payload = ();
|
||||||
|
|
||||||
fn broadcast(&self, message: Self::Payload) {
|
fn broadcast(&self, message: Self::Payload) {
|
||||||
let message = NetworkMessage::new(self.id, None, message);
|
let message = NetworkMessage::new(self.id, None, message, 1);
|
||||||
self.broadcast.send(message).unwrap();
|
self.broadcast.send(message).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_message(&self, address: NodeId, message: Self::Payload) {
|
fn send_message(&self, address: NodeId, message: Self::Payload) {
|
||||||
let message = NetworkMessage::new(self.id, Some(address), message);
|
let message = NetworkMessage::new(self.id, Some(address), message, 1);
|
||||||
self.sender.send(message).unwrap();
|
self.sender.send(message).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -368,7 +432,7 @@ mod tests {
|
||||||
|
|
||||||
let (from_a_sender, from_a_receiver) = channel::unbounded();
|
let (from_a_sender, from_a_receiver) = channel::unbounded();
|
||||||
let (from_a_broadcast_sender, from_a_broadcast_receiver) = channel::unbounded();
|
let (from_a_broadcast_sender, from_a_broadcast_receiver) = channel::unbounded();
|
||||||
let to_a_receiver = network.connect(node_a, from_a_receiver, from_a_broadcast_receiver);
|
let to_a_receiver = network.connect(node_a, 3, from_a_receiver, from_a_broadcast_receiver);
|
||||||
let a = MockNetworkInterface::new(
|
let a = MockNetworkInterface::new(
|
||||||
node_a,
|
node_a,
|
||||||
from_a_broadcast_sender,
|
from_a_broadcast_sender,
|
||||||
|
@ -378,7 +442,7 @@ mod tests {
|
||||||
|
|
||||||
let (from_b_sender, from_b_receiver) = channel::unbounded();
|
let (from_b_sender, from_b_receiver) = channel::unbounded();
|
||||||
let (from_b_broadcast_sender, from_b_broadcast_receiver) = channel::unbounded();
|
let (from_b_broadcast_sender, from_b_broadcast_receiver) = channel::unbounded();
|
||||||
let to_b_receiver = network.connect(node_b, from_b_receiver, from_b_broadcast_receiver);
|
let to_b_receiver = network.connect(node_b, 3, from_b_receiver, from_b_broadcast_receiver);
|
||||||
let b = MockNetworkInterface::new(
|
let b = MockNetworkInterface::new(
|
||||||
node_b,
|
node_b,
|
||||||
from_b_broadcast_sender,
|
from_b_broadcast_sender,
|
||||||
|
@ -443,7 +507,7 @@ mod tests {
|
||||||
|
|
||||||
let (from_a_sender, from_a_receiver) = channel::unbounded();
|
let (from_a_sender, from_a_receiver) = channel::unbounded();
|
||||||
let (from_a_broadcast_sender, from_a_broadcast_receiver) = channel::unbounded();
|
let (from_a_broadcast_sender, from_a_broadcast_receiver) = channel::unbounded();
|
||||||
let to_a_receiver = network.connect(node_a, from_a_receiver, from_a_broadcast_receiver);
|
let to_a_receiver = network.connect(node_a, 2, from_a_receiver, from_a_broadcast_receiver);
|
||||||
let a = MockNetworkInterface::new(
|
let a = MockNetworkInterface::new(
|
||||||
node_a,
|
node_a,
|
||||||
from_a_broadcast_sender,
|
from_a_broadcast_sender,
|
||||||
|
@ -453,7 +517,7 @@ mod tests {
|
||||||
|
|
||||||
let (from_b_sender, from_b_receiver) = channel::unbounded();
|
let (from_b_sender, from_b_receiver) = channel::unbounded();
|
||||||
let (from_b_broadcast_sender, from_b_broadcast_receiver) = channel::unbounded();
|
let (from_b_broadcast_sender, from_b_broadcast_receiver) = channel::unbounded();
|
||||||
let to_b_receiver = network.connect(node_b, from_b_receiver, from_b_broadcast_receiver);
|
let to_b_receiver = network.connect(node_b, 2, from_b_receiver, from_b_broadcast_receiver);
|
||||||
let b = MockNetworkInterface::new(
|
let b = MockNetworkInterface::new(
|
||||||
node_b,
|
node_b,
|
||||||
from_b_broadcast_sender,
|
from_b_broadcast_sender,
|
||||||
|
@ -463,7 +527,7 @@ mod tests {
|
||||||
|
|
||||||
let (from_c_sender, from_c_receiver) = channel::unbounded();
|
let (from_c_sender, from_c_receiver) = channel::unbounded();
|
||||||
let (from_c_broadcast_sender, from_c_broadcast_receiver) = channel::unbounded();
|
let (from_c_broadcast_sender, from_c_broadcast_receiver) = channel::unbounded();
|
||||||
let to_c_receiver = network.connect(node_c, from_c_receiver, from_c_broadcast_receiver);
|
let to_c_receiver = network.connect(node_c, 2, from_c_receiver, from_c_broadcast_receiver);
|
||||||
let c = MockNetworkInterface::new(
|
let c = MockNetworkInterface::new(
|
||||||
node_c,
|
node_c,
|
||||||
from_c_broadcast_sender,
|
from_c_broadcast_sender,
|
||||||
|
@ -502,4 +566,55 @@ mod tests {
|
||||||
assert_eq!(b.receive_messages().len(), 0);
|
assert_eq!(b.receive_messages().len(), 0);
|
||||||
assert_eq!(c.receive_messages().len(), 1); // b to c
|
assert_eq!(c.receive_messages().len(), 1); // b to c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn node_network_capacity_limit() {
|
||||||
|
let node_a = NodeId::from_index(0);
|
||||||
|
let node_b = NodeId::from_index(1);
|
||||||
|
|
||||||
|
let regions = HashMap::from([(Region::Europe, vec![node_a, node_b])]);
|
||||||
|
let behaviour = HashMap::from([(
|
||||||
|
NetworkBehaviourKey::new(Region::Europe, Region::Europe),
|
||||||
|
NetworkBehaviour::new(Duration::from_millis(100), 0.0),
|
||||||
|
)]);
|
||||||
|
let regions_data = RegionsData::new(regions, behaviour);
|
||||||
|
let mut network = Network::new(regions_data, 0);
|
||||||
|
|
||||||
|
let (from_a_sender, from_a_receiver) = channel::unbounded();
|
||||||
|
let (from_a_broadcast_sender, from_a_broadcast_receiver) = channel::unbounded();
|
||||||
|
let to_a_receiver = network.connect(node_a, 3, from_a_receiver, from_a_broadcast_receiver);
|
||||||
|
let a = MockNetworkInterface::new(
|
||||||
|
node_a,
|
||||||
|
from_a_broadcast_sender,
|
||||||
|
from_a_sender,
|
||||||
|
to_a_receiver,
|
||||||
|
);
|
||||||
|
|
||||||
|
let (from_b_sender, from_b_receiver) = channel::unbounded();
|
||||||
|
let (from_b_broadcast_sender, from_b_broadcast_receiver) = channel::unbounded();
|
||||||
|
let to_b_receiver = network.connect(node_b, 2, from_b_receiver, from_b_broadcast_receiver);
|
||||||
|
let b = MockNetworkInterface::new(
|
||||||
|
node_b,
|
||||||
|
from_b_broadcast_sender,
|
||||||
|
from_b_sender,
|
||||||
|
to_b_receiver,
|
||||||
|
);
|
||||||
|
|
||||||
|
for _ in 0..6 {
|
||||||
|
a.send_message(node_b, ());
|
||||||
|
b.send_message(node_a, ());
|
||||||
|
}
|
||||||
|
|
||||||
|
network.step(Duration::from_millis(100));
|
||||||
|
assert_eq!(a.receive_messages().len(), 3);
|
||||||
|
assert_eq!(b.receive_messages().len(), 2);
|
||||||
|
|
||||||
|
network.step(Duration::from_millis(100));
|
||||||
|
assert_eq!(a.receive_messages().len(), 3);
|
||||||
|
assert_eq!(b.receive_messages().len(), 2);
|
||||||
|
|
||||||
|
network.step(Duration::from_millis(100));
|
||||||
|
assert_eq!(a.receive_messages().len(), 0);
|
||||||
|
assert_eq!(b.receive_messages().len(), 2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@ use nomos_consensus::network::messages::{
|
||||||
NewViewMsg, ProposalChunkMsg, TimeoutMsg, TimeoutQcMsg, VoteMsg,
|
NewViewMsg, ProposalChunkMsg, TimeoutMsg, TimeoutQcMsg, VoteMsg,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::network::PayloadSize;
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
|
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
|
||||||
pub enum CarnotMessage {
|
pub enum CarnotMessage {
|
||||||
Proposal(ProposalChunkMsg),
|
Proposal(ProposalChunkMsg),
|
||||||
|
@ -23,3 +25,17 @@ impl CarnotMessage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PayloadSize for CarnotMessage {
|
||||||
|
fn size_bytes(&self) -> u32 {
|
||||||
|
match self {
|
||||||
|
CarnotMessage::Proposal(p) => {
|
||||||
|
(std::mem::size_of::<ProposalChunkMsg>() + p.chunk.len()) as u32
|
||||||
|
}
|
||||||
|
CarnotMessage::Vote(_) => std::mem::size_of::<VoteMsg>() as u32,
|
||||||
|
CarnotMessage::TimeoutQc(_) => std::mem::size_of::<TimeoutQcMsg>() as u32,
|
||||||
|
CarnotMessage::Timeout(_) => std::mem::size_of::<TimeoutMsg>() as u32,
|
||||||
|
CarnotMessage::NewView(_) => std::mem::size_of::<NewViewMsg>() as u32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ use consensus_engine::View;
|
||||||
use std::collections::{BTreeMap, BTreeSet};
|
use std::collections::{BTreeMap, BTreeSet};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
// crates
|
// crates
|
||||||
|
use crate::network::PayloadSize;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
// internal
|
// internal
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -90,6 +91,12 @@ pub enum DummyMessage {
|
||||||
Proposal(Block),
|
Proposal(Block),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PayloadSize for DummyMessage {
|
||||||
|
fn size_bytes(&self) -> u32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct LocalView {
|
struct LocalView {
|
||||||
pub next_view_leaders: Vec<NodeId>,
|
pub next_view_leaders: Vec<NodeId>,
|
||||||
pub current_roots: Option<BTreeSet<NodeId>>,
|
pub current_roots: Option<BTreeSet<NodeId>>,
|
||||||
|
@ -475,6 +482,7 @@ mod tests {
|
||||||
channel::unbounded();
|
channel::unbounded();
|
||||||
let network_message_receiver = network.connect(
|
let network_message_receiver = network.connect(
|
||||||
*node_id,
|
*node_id,
|
||||||
|
0,
|
||||||
node_message_receiver,
|
node_message_receiver,
|
||||||
node_message_broadcast_receiver,
|
node_message_broadcast_receiver,
|
||||||
);
|
);
|
||||||
|
|
|
@ -16,6 +16,7 @@ use super::SimulationRunnerHandle;
|
||||||
pub fn simulate<M, R, S, T>(
|
pub fn simulate<M, R, S, T>(
|
||||||
runner: SimulationRunner<M, R, S, T>,
|
runner: SimulationRunner<M, R, S, T>,
|
||||||
chunk_size: usize,
|
chunk_size: usize,
|
||||||
|
step_time: Duration,
|
||||||
) -> anyhow::Result<SimulationRunnerHandle<R>>
|
) -> anyhow::Result<SimulationRunnerHandle<R>>
|
||||||
where
|
where
|
||||||
M: std::fmt::Debug + Clone + Send + Sync + 'static,
|
M: std::fmt::Debug + Clone + Send + Sync + 'static,
|
||||||
|
@ -38,7 +39,6 @@ where
|
||||||
let (stop_tx, stop_rx) = bounded(1);
|
let (stop_tx, stop_rx) = bounded(1);
|
||||||
let p = runner.producer.clone();
|
let p = runner.producer.clone();
|
||||||
let p1 = runner.producer;
|
let p1 = runner.producer;
|
||||||
let elapsed = Duration::from_millis(100);
|
|
||||||
let handle = std::thread::spawn(move || {
|
let handle = std::thread::spawn(move || {
|
||||||
loop {
|
loop {
|
||||||
select! {
|
select! {
|
||||||
|
@ -53,7 +53,7 @@ where
|
||||||
.write()
|
.write()
|
||||||
.par_iter_mut()
|
.par_iter_mut()
|
||||||
.filter(|n| ids.contains(&n.id()))
|
.filter(|n| ids.contains(&n.id()))
|
||||||
.for_each(|node|node.step(elapsed));
|
.for_each(|node|node.step(step_time));
|
||||||
|
|
||||||
p.send(R::try_from(
|
p.send(R::try_from(
|
||||||
&simulation_state,
|
&simulation_state,
|
||||||
|
|
|
@ -19,6 +19,7 @@ pub fn simulate<M, R, S, T>(
|
||||||
runner: SimulationRunner<M, R, S, T>,
|
runner: SimulationRunner<M, R, S, T>,
|
||||||
update_rate: usize,
|
update_rate: usize,
|
||||||
maximum_iterations: usize,
|
maximum_iterations: usize,
|
||||||
|
step_time: Duration,
|
||||||
) -> anyhow::Result<SimulationRunnerHandle<R>>
|
) -> anyhow::Result<SimulationRunnerHandle<R>>
|
||||||
where
|
where
|
||||||
M: std::fmt::Debug + Send + Sync + Clone + 'static,
|
M: std::fmt::Debug + Send + Sync + Clone + 'static,
|
||||||
|
@ -42,7 +43,6 @@ where
|
||||||
let (stop_tx, stop_rx) = bounded(1);
|
let (stop_tx, stop_rx) = bounded(1);
|
||||||
let p = runner.producer.clone();
|
let p = runner.producer.clone();
|
||||||
let p1 = runner.producer;
|
let p1 = runner.producer;
|
||||||
let elapsed = Duration::from_millis(100);
|
|
||||||
let handle = std::thread::spawn(move || {
|
let handle = std::thread::spawn(move || {
|
||||||
'main: for chunk in iterations.chunks(update_rate) {
|
'main: for chunk in iterations.chunks(update_rate) {
|
||||||
select! {
|
select! {
|
||||||
|
@ -62,7 +62,7 @@ where
|
||||||
let node: &mut dyn Node<Settings = S, State = T> = &mut **shared_nodes
|
let node: &mut dyn Node<Settings = S, State = T> = &mut **shared_nodes
|
||||||
.get_mut(node_id.index())
|
.get_mut(node_id.index())
|
||||||
.expect("Node should be present");
|
.expect("Node should be present");
|
||||||
node.step(elapsed);
|
node.step(step_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if any condition makes the simulation stop
|
// check if any condition makes the simulation stop
|
||||||
|
|
|
@ -52,6 +52,7 @@ pub fn simulate<M, R, S, T>(
|
||||||
runner: SimulationRunner<M, R, S, T>,
|
runner: SimulationRunner<M, R, S, T>,
|
||||||
gap: usize,
|
gap: usize,
|
||||||
distribution: Option<Vec<f32>>,
|
distribution: Option<Vec<f32>>,
|
||||||
|
step_time: Duration,
|
||||||
) -> anyhow::Result<SimulationRunnerHandle<R>>
|
) -> anyhow::Result<SimulationRunnerHandle<R>>
|
||||||
where
|
where
|
||||||
M: std::fmt::Debug + Send + Sync + Clone + 'static,
|
M: std::fmt::Debug + Send + Sync + Clone + 'static,
|
||||||
|
@ -79,7 +80,6 @@ where
|
||||||
let (stop_tx, stop_rx) = bounded(1);
|
let (stop_tx, stop_rx) = bounded(1);
|
||||||
let p = runner.producer.clone();
|
let p = runner.producer.clone();
|
||||||
let p1 = runner.producer;
|
let p1 = runner.producer;
|
||||||
let elapsed = Duration::from_millis(100);
|
|
||||||
let handle = std::thread::spawn(move || {
|
let handle = std::thread::spawn(move || {
|
||||||
loop {
|
loop {
|
||||||
select! {
|
select! {
|
||||||
|
@ -99,7 +99,7 @@ where
|
||||||
.get_mut(node_id.index())
|
.get_mut(node_id.index())
|
||||||
.expect("Node should be present");
|
.expect("Node should be present");
|
||||||
let prev_view = node.current_view();
|
let prev_view = node.current_view();
|
||||||
node.step(elapsed);
|
node.step(step_time);
|
||||||
let after_view = node.current_view();
|
let after_view = node.current_view();
|
||||||
if after_view > prev_view {
|
if after_view > prev_view {
|
||||||
// pass node to next step group
|
// pass node to next step group
|
||||||
|
|
|
@ -93,6 +93,7 @@ pub struct SimulationRunner<M: std::fmt::Debug, R, S, T> {
|
||||||
nodes: Arc<RwLock<Vec<BoxedNode<S, T>>>>,
|
nodes: Arc<RwLock<Vec<BoxedNode<S, T>>>>,
|
||||||
runner_settings: RunnerSettings,
|
runner_settings: RunnerSettings,
|
||||||
producer: StreamProducer<R>,
|
producer: StreamProducer<R>,
|
||||||
|
step_time: Duration,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M, R, S, T> SimulationRunner<M, R, S, T>
|
impl<M, R, S, T> SimulationRunner<M, R, S, T>
|
||||||
|
@ -136,7 +137,7 @@ where
|
||||||
views_count: _,
|
views_count: _,
|
||||||
leaders_count: _,
|
leaders_count: _,
|
||||||
network_settings: _,
|
network_settings: _,
|
||||||
step_time: _,
|
step_time,
|
||||||
record_settings: _,
|
record_settings: _,
|
||||||
} = settings;
|
} = settings;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
@ -148,24 +149,26 @@ where
|
||||||
},
|
},
|
||||||
nodes,
|
nodes,
|
||||||
producer,
|
producer,
|
||||||
|
step_time,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn simulate(self) -> anyhow::Result<SimulationRunnerHandle<R>> {
|
pub fn simulate(self) -> anyhow::Result<SimulationRunnerHandle<R>> {
|
||||||
// init the start time
|
// init the start time
|
||||||
let _ = *crate::START_TIME;
|
let _ = *crate::START_TIME;
|
||||||
|
let step_time = self.step_time;
|
||||||
|
|
||||||
match self.runner_settings.clone() {
|
match self.runner_settings.clone() {
|
||||||
RunnerSettings::Sync => sync_runner::simulate(self),
|
RunnerSettings::Sync => sync_runner::simulate(self, step_time),
|
||||||
RunnerSettings::Async { chunks } => async_runner::simulate(self, chunks),
|
RunnerSettings::Async { chunks } => async_runner::simulate(self, chunks, step_time),
|
||||||
RunnerSettings::Glauber {
|
RunnerSettings::Glauber {
|
||||||
maximum_iterations,
|
maximum_iterations,
|
||||||
update_rate,
|
update_rate,
|
||||||
} => glauber_runner::simulate(self, update_rate, maximum_iterations),
|
} => glauber_runner::simulate(self, update_rate, maximum_iterations, step_time),
|
||||||
RunnerSettings::Layered {
|
RunnerSettings::Layered {
|
||||||
rounds_gap,
|
rounds_gap,
|
||||||
distribution,
|
distribution,
|
||||||
} => layered_runner::simulate(self, rounds_gap, distribution),
|
} => layered_runner::simulate(self, rounds_gap, distribution, step_time),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ use std::time::Duration;
|
||||||
/// Simulate with sending the network state to any subscriber
|
/// Simulate with sending the network state to any subscriber
|
||||||
pub fn simulate<M, R, S, T>(
|
pub fn simulate<M, R, S, T>(
|
||||||
runner: SimulationRunner<M, R, S, T>,
|
runner: SimulationRunner<M, R, S, T>,
|
||||||
|
step_time: Duration,
|
||||||
) -> anyhow::Result<SimulationRunnerHandle<R>>
|
) -> anyhow::Result<SimulationRunnerHandle<R>>
|
||||||
where
|
where
|
||||||
M: std::fmt::Debug + Send + Sync + Clone + 'static,
|
M: std::fmt::Debug + Send + Sync + Clone + 'static,
|
||||||
|
@ -29,7 +30,6 @@ where
|
||||||
let (stop_tx, stop_rx) = bounded(1);
|
let (stop_tx, stop_rx) = bounded(1);
|
||||||
let p = runner.producer.clone();
|
let p = runner.producer.clone();
|
||||||
let p1 = runner.producer;
|
let p1 = runner.producer;
|
||||||
let elapsed = Duration::from_millis(100);
|
|
||||||
let handle = std::thread::spawn(move || {
|
let handle = std::thread::spawn(move || {
|
||||||
p.send(R::try_from(&state)?)?;
|
p.send(R::try_from(&state)?)?;
|
||||||
loop {
|
loop {
|
||||||
|
@ -43,7 +43,7 @@ where
|
||||||
// then dead lock will occur
|
// then dead lock will occur
|
||||||
{
|
{
|
||||||
let mut nodes = nodes.write();
|
let mut nodes = nodes.write();
|
||||||
inner_runner.step(&mut nodes, elapsed);
|
inner_runner.step(&mut nodes, step_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
p.send(R::try_from(&state)?)?;
|
p.send(R::try_from(&state)?)?;
|
||||||
|
@ -116,6 +116,7 @@ mod tests {
|
||||||
channel::unbounded();
|
channel::unbounded();
|
||||||
let network_message_receiver = network.connect(
|
let network_message_receiver = network.connect(
|
||||||
*node_id,
|
*node_id,
|
||||||
|
1,
|
||||||
node_message_receiver,
|
node_message_receiver,
|
||||||
node_message_broadcast_receiver,
|
node_message_broadcast_receiver,
|
||||||
);
|
);
|
||||||
|
|
|
@ -37,6 +37,7 @@ pub struct TreeSettings {
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, Default)]
|
#[derive(Clone, Debug, Serialize, Deserialize, Default)]
|
||||||
pub struct NodeSettings {
|
pub struct NodeSettings {
|
||||||
|
pub network_capacity_kbps: u32,
|
||||||
#[serde(with = "humantime_serde")]
|
#[serde(with = "humantime_serde")]
|
||||||
pub timeout: std::time::Duration,
|
pub timeout: std::time::Duration,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue