Add network data to runtime results (#43)

This commit is contained in:
gusto 2024-11-08 12:44:19 +02:00 committed by GitHub
parent 8147b7d718
commit f97136bda6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 87 additions and 30 deletions

View File

@ -25,12 +25,12 @@
"stream_settings": { "stream_settings": {
"path": "test.json" "path": "test.json"
}, },
"node_count": 100, "node_count": 10,
"seed": 0, "seed": 0,
"record_settings": {}, "record_settings": {},
"wards": [ "wards": [
{ {
"sum": 100 "sum":2
} }
], ],
"connected_peers_count": 4, "connected_peers_count": 4,

View File

@ -11,7 +11,7 @@ use clap::Parser;
use crossbeam::channel; use crossbeam::channel;
use netrunner::network::behaviour::create_behaviours; use netrunner::network::behaviour::create_behaviours;
use netrunner::network::regions::{create_regions, RegionsData}; use netrunner::network::regions::{create_regions, RegionsData};
use netrunner::network::{InMemoryNetworkInterface, Network}; use netrunner::network::{InMemoryNetworkInterface, Network, PayloadSize};
use netrunner::node::{NodeId, NodeIdExt}; use netrunner::node::{NodeId, NodeIdExt};
use netrunner::output_processors::Record; use netrunner::output_processors::Record;
use netrunner::runner::{BoxedNode, SimulationRunnerHandle}; use netrunner::runner::{BoxedNode, SimulationRunnerHandle};
@ -184,7 +184,7 @@ fn run<M, S, T>(
stream_type: Option<StreamType>, stream_type: Option<StreamType>,
) -> anyhow::Result<()> ) -> anyhow::Result<()>
where where
M: std::fmt::Debug + Clone + Send + Sync + 'static, M: std::fmt::Debug + PayloadSize + Clone + Send + Sync + 'static,
S: 'static, S: 'static,
T: Serialize + Clone + 'static, T: Serialize + Clone + 'static,
{ {
@ -244,10 +244,11 @@ fn load_json_from_file<T: DeserializeOwned>(path: &Path) -> anyhow::Result<T> {
fn main() -> anyhow::Result<()> { fn main() -> anyhow::Result<()> {
let app: SimulationApp = SimulationApp::parse(); let app: SimulationApp = SimulationApp::parse();
let _maybe_guard = log::config_tracing(app.log_format, &app.log_to, app.with_metrics); let maybe_guard = log::config_tracing(app.log_format, &app.log_to, app.with_metrics);
if let Err(e) = app.run() { if let Err(e) = app.run() {
tracing::error!("error: {}", e); tracing::error!("error: {}", e);
drop(maybe_guard);
std::process::exit(1); std::process::exit(1);
} }
Ok(()) Ok(())

View File

@ -133,6 +133,8 @@ impl NodeNetworkCapacity {
false false
} }
} else { } else {
let mut current_load = self.current_load.lock();
*current_load += load;
true true
} }
} }
@ -141,19 +143,20 @@ impl NodeNetworkCapacity {
self.load_to_flush.fetch_add(load, Ordering::Relaxed); self.load_to_flush.fetch_add(load, Ordering::Relaxed);
} }
fn flush_load(&self) { fn flush_load(&self) -> u32 {
if self.capacity_bps.is_none() {
return;
}
let mut s = self.current_load.lock(); let mut s = self.current_load.lock();
let previous_load = *s;
*s -= self.load_to_flush.load(Ordering::Relaxed); *s -= self.load_to_flush.load(Ordering::Relaxed);
self.load_to_flush.store(0, Ordering::Relaxed); self.load_to_flush.store(0, Ordering::Relaxed);
previous_load
} }
} }
#[derive(Debug)] #[derive(Debug)]
pub struct Network<M: std::fmt::Debug> { pub struct Network<M>
where
M: std::fmt::Debug + PayloadSize,
{
pub regions: regions::RegionsData, pub regions: regions::RegionsData,
network_time: NetworkTime, network_time: NetworkTime,
messages: Vec<(NetworkTime, NetworkMessage<M>)>, messages: Vec<(NetworkTime, NetworkMessage<M>)>,
@ -161,12 +164,19 @@ pub struct Network<M: std::fmt::Debug> {
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>>>,
state: NetworkState,
seed: u64, seed: u64,
} }
#[derive(Serialize, Deserialize, Default, Debug, Clone)]
pub struct NetworkState {
pub total_outbound_bandwidth: u64,
pub total_inbound_bandwidth: u64,
}
impl<M> Network<M> impl<M> Network<M>
where where
M: std::fmt::Debug + Send + Sync + Clone, M: std::fmt::Debug + PayloadSize + Send + Sync + Clone,
{ {
pub fn new(regions: regions::RegionsData, seed: u64) -> Self { pub fn new(regions: regions::RegionsData, seed: u64) -> Self {
Self { Self {
@ -177,10 +187,15 @@ where
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(),
state: NetworkState::default(),
seed, seed,
} }
} }
pub fn bandwidth_results(&self) -> NetworkState {
self.state.clone()
}
fn send_message_cost<R: Rng>( fn send_message_cost<R: Rng>(
&self, &self,
rng: &mut R, rng: &mut R,
@ -219,7 +234,9 @@ where
/// Receive and store all messages from nodes. /// Receive and store all messages from nodes.
pub fn collect_messages(&mut self) { pub fn collect_messages(&mut self) {
let mut adhoc_messages = self let mut total_step_outbound_bandwidth = 0u64;
let mut adhoc_messages: Vec<(Instant, NetworkMessage<M>)> = self
.from_node_receivers .from_node_receivers
.par_iter() .par_iter()
.flat_map(|(_, from_node)| { .flat_map(|(_, from_node)| {
@ -229,6 +246,10 @@ where
.collect::<Vec<_>>() .collect::<Vec<_>>()
}) })
.collect(); .collect();
total_step_outbound_bandwidth += adhoc_messages
.iter()
.map(|(_, m)| m.payload().size_bytes() as u64)
.sum::<u64>();
self.messages.append(&mut adhoc_messages); self.messages.append(&mut adhoc_messages);
let mut broadcast_messages = self let mut broadcast_messages = self
@ -245,7 +266,13 @@ where
}) })
.map(|m| (self.network_time, m)) .map(|m| (self.network_time, m))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
total_step_outbound_bandwidth += broadcast_messages
.iter()
.map(|(_, m)| m.payload().size_bytes() as u64)
.sum::<u64>();
self.messages.append(&mut broadcast_messages); self.messages.append(&mut broadcast_messages);
self.state.total_outbound_bandwidth += total_step_outbound_bandwidth;
} }
/// Reiterate all messages and send to appropriate nodes if simulated /// Reiterate all messages and send to appropriate nodes if simulated
@ -262,12 +289,14 @@ where
}) })
.cloned() .cloned()
.collect(); .collect();
self.messages = delayed;
let mut total_step_inbound_bandwidth = 0u64;
for (_, c) in self.node_network_capacity.iter() { for (_, c) in self.node_network_capacity.iter() {
c.flush_load(); total_step_inbound_bandwidth += c.flush_load() as u64;
} }
self.messages = delayed; self.state.total_inbound_bandwidth += total_step_inbound_bandwidth;
} }
/// Returns true if message needs to be delayed and be dispatched in future. /// Returns true if message needs to be delayed and be dispatched in future.
@ -325,6 +354,7 @@ where
} }
remaining remaining
} else { } else {
node_capacity.decrease_load(message.remaining_size());
0 0
} }
} }
@ -428,7 +458,7 @@ mod tests {
use super::{ use super::{
behaviour::NetworkBehaviour, behaviour::NetworkBehaviour,
regions::{Region, RegionsData}, regions::{Region, RegionsData},
Network, NetworkInterface, NetworkMessage, Network, NetworkInterface, NetworkMessage, PayloadSize,
}; };
use crate::{ use crate::{
network::NetworkBehaviourKey, network::NetworkBehaviourKey,
@ -463,6 +493,12 @@ mod tests {
} }
} }
impl PayloadSize for () {
fn size_bytes(&self) -> u32 {
todo!()
}
}
impl NetworkInterface for MockNetworkInterface { impl NetworkInterface for MockNetworkInterface {
type Payload = (); type Payload = ();

View File

@ -3,6 +3,7 @@ use std::time::Duration;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use serde::Serialize; use serde::Serialize;
use crate::network::NetworkState;
use crate::settings::SimulationSettings; use crate::settings::SimulationSettings;
use crate::warding::SimulationState; use crate::warding::SimulationState;
@ -36,23 +37,29 @@ pub trait Record: From<Runtime> + From<SimulationSettings> + Send + Sync + 'stat
pub type SerializedNodeState = serde_json::Value; pub type SerializedNodeState = serde_json::Value;
#[derive(Serialize)] #[derive(Serialize)]
pub struct Runtime { pub struct Simulation {
start: DateTime<Utc>, start: DateTime<Utc>,
end: DateTime<Utc>, end: DateTime<Utc>,
elapsed: Duration, elapsed: Duration,
} }
#[derive(Serialize)]
pub enum Runtime {
Simulation(Simulation),
Network(NetworkState),
}
impl Runtime { impl Runtime {
pub(crate) fn load() -> anyhow::Result<Self> { pub(crate) fn load() -> anyhow::Result<Self> {
let elapsed = crate::START_TIME.elapsed(); let elapsed = crate::START_TIME.elapsed();
let end = Utc::now(); let end = Utc::now();
Ok(Self { Ok(Self::Simulation(Simulation {
start: end start: end
.checked_sub_signed(chrono::Duration::from_std(elapsed)?) .checked_sub_signed(chrono::Duration::from_std(elapsed)?)
.unwrap(), .unwrap(),
end, end,
elapsed, elapsed,
}) }))
} }
} }

View File

@ -1,3 +1,4 @@
use crate::network::PayloadSize;
use crate::node::NodeId; use crate::node::NodeId;
use crate::output_processors::Record; use crate::output_processors::Record;
use crate::runner::SimulationRunner; use crate::runner::SimulationRunner;
@ -19,7 +20,7 @@ pub fn simulate<M, R, S, T>(
step_time: Duration, 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 + PayloadSize + Clone + Send + Sync + 'static,
R: Record R: Record
+ for<'a> TryFrom<&'a SimulationState<S, T>, Error = anyhow::Error> + for<'a> TryFrom<&'a SimulationState<S, T>, Error = anyhow::Error>
+ Send + Send

View File

@ -19,7 +19,7 @@ use rayon::prelude::*;
use serde::Serialize; use serde::Serialize;
// internal // internal
use crate::network::Network; use crate::network::{Network, PayloadSize};
use crate::node::Node; use crate::node::Node;
use crate::settings::{RunnerSettings, SimulationSettings}; use crate::settings::{RunnerSettings, SimulationSettings};
use crate::warding::{SimulationState, SimulationWard, Ward}; use crate::warding::{SimulationState, SimulationWard, Ward};
@ -66,7 +66,10 @@ impl<R: Record> SimulationRunnerHandle<R> {
} }
} }
pub(crate) struct SimulationRunnerInner<M: std::fmt::Debug> { pub(crate) struct SimulationRunnerInner<M>
where
M: std::fmt::Debug + PayloadSize,
{
network: Network<M>, network: Network<M>,
wards: Vec<Ward>, wards: Vec<Ward>,
rng: SmallRng, rng: SmallRng,
@ -74,7 +77,7 @@ pub(crate) struct SimulationRunnerInner<M: std::fmt::Debug> {
impl<M> SimulationRunnerInner<M> impl<M> SimulationRunnerInner<M>
where where
M: std::fmt::Debug + Send + Sync + Clone, M: std::fmt::Debug + PayloadSize + Send + Sync + Clone,
{ {
fn check_wards<S, T>(&mut self, state: &SimulationState<S, T>) -> bool { fn check_wards<S, T>(&mut self, state: &SimulationState<S, T>) -> bool {
self.wards self.wards
@ -94,7 +97,10 @@ where
/// Encapsulation solution for the simulations runner /// Encapsulation solution for the simulations runner
/// Holds the network state, the simulating nodes and the simulation settings. /// Holds the network state, the simulating nodes and the simulation settings.
pub struct SimulationRunner<M: std::fmt::Debug, R, S, T> { pub struct SimulationRunner<M, R, S, T>
where
M: std::fmt::Debug + PayloadSize,
{
inner: SimulationRunnerInner<M>, inner: SimulationRunnerInner<M>,
nodes: Arc<RwLock<Vec<BoxedNode<S, T>>>>, nodes: Arc<RwLock<Vec<BoxedNode<S, T>>>>,
runner_settings: RunnerSettings, runner_settings: RunnerSettings,
@ -104,7 +110,7 @@ pub struct SimulationRunner<M: std::fmt::Debug, R, S, T> {
impl<M, R, S, T> SimulationRunner<M, R, S, T> impl<M, R, S, T> SimulationRunner<M, R, S, T>
where where
M: std::fmt::Debug + Clone + Send + Sync + 'static, M: std::fmt::Debug + PayloadSize + Clone + Send + Sync + 'static,
R: Record R: Record
+ for<'a> TryFrom<&'a SimulationState<S, T>, Error = anyhow::Error> + for<'a> TryFrom<&'a SimulationState<S, T>, Error = anyhow::Error>
+ Send + Send
@ -170,7 +176,7 @@ where
impl<M, R, S, T> SimulationRunner<M, R, S, T> impl<M, R, S, T> SimulationRunner<M, R, S, T>
where where
M: std::fmt::Debug + Clone + Send + Sync + 'static, M: std::fmt::Debug + PayloadSize + Clone + Send + Sync + 'static,
R: Record R: Record
+ serde::Serialize + serde::Serialize
+ for<'a> TryFrom<&'a SimulationState<S, T>, Error = anyhow::Error> + for<'a> TryFrom<&'a SimulationState<S, T>, Error = anyhow::Error>

View File

@ -1,4 +1,5 @@
use super::{SimulationRunner, SimulationRunnerHandle}; use super::{SimulationRunner, SimulationRunnerHandle};
use crate::network::PayloadSize;
use crate::output_processors::Record; use crate::output_processors::Record;
use crate::warding::SimulationState; use crate::warding::SimulationState;
use crossbeam::channel::{bounded, select}; use crossbeam::channel::{bounded, select};
@ -11,7 +12,7 @@ pub fn simulate<M, R, S, T>(
step_time: Duration, 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 + PayloadSize + Send + Sync + Clone + 'static,
R: Record R: Record
+ for<'a> TryFrom<&'a SimulationState<S, T>, Error = anyhow::Error> + for<'a> TryFrom<&'a SimulationState<S, T>, Error = anyhow::Error>
+ Send + Send
@ -35,7 +36,7 @@ where
loop { loop {
select! { select! {
recv(stop_rx) -> _ => { recv(stop_rx) -> _ => {
return Ok(()); break;
} }
default => { default => {
// we must use a code block to make sure once the step call is finished then the write lock will be released, because in Record::try_from(&state), // we must use a code block to make sure once the step call is finished then the write lock will be released, because in Record::try_from(&state),
@ -49,11 +50,16 @@ where
p.send(R::try_from(&state)?)?; p.send(R::try_from(&state)?)?;
// check if any condition makes the simulation stop // check if any condition makes the simulation stop
if inner_runner.check_wards(&state) { if inner_runner.check_wards(&state) {
return Ok(()); break;
} }
} }
} }
} }
tracing::info!(
"Total bandwidth results: {:?}",
inner_runner.network.bandwidth_results()
);
Ok(())
}); });
Ok(SimulationRunnerHandle { Ok(SimulationRunnerHandle {
producer: p1, producer: p1,

View File

@ -95,7 +95,7 @@ where
} }
fn subscribe_data_type() -> RecordType { fn subscribe_data_type() -> RecordType {
RecordType::Data RecordType::Meta
} }
} }