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": {
"path": "test.json"
},
"node_count": 100,
"node_count": 10,
"seed": 0,
"record_settings": {},
"wards": [
{
"sum": 100
"sum":2
}
],
"connected_peers_count": 4,

View File

@ -11,7 +11,7 @@ use clap::Parser;
use crossbeam::channel;
use netrunner::network::behaviour::create_behaviours;
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::output_processors::Record;
use netrunner::runner::{BoxedNode, SimulationRunnerHandle};
@ -184,7 +184,7 @@ fn run<M, S, T>(
stream_type: Option<StreamType>,
) -> anyhow::Result<()>
where
M: std::fmt::Debug + Clone + Send + Sync + 'static,
M: std::fmt::Debug + PayloadSize + Clone + Send + Sync + 'static,
S: '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<()> {
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() {
tracing::error!("error: {}", e);
drop(maybe_guard);
std::process::exit(1);
}
Ok(())

View File

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

View File

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

View File

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

View File

@ -19,7 +19,7 @@ use rayon::prelude::*;
use serde::Serialize;
// internal
use crate::network::Network;
use crate::network::{Network, PayloadSize};
use crate::node::Node;
use crate::settings::{RunnerSettings, SimulationSettings};
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>,
wards: Vec<Ward>,
rng: SmallRng,
@ -74,7 +77,7 @@ pub(crate) struct SimulationRunnerInner<M: std::fmt::Debug> {
impl<M> SimulationRunnerInner<M>
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 {
self.wards
@ -94,7 +97,10 @@ where
/// Encapsulation solution for the simulations runner
/// 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>,
nodes: Arc<RwLock<Vec<BoxedNode<S, T>>>>,
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>
where
M: std::fmt::Debug + Clone + Send + Sync + 'static,
M: std::fmt::Debug + PayloadSize + Clone + Send + Sync + 'static,
R: Record
+ for<'a> TryFrom<&'a SimulationState<S, T>, Error = anyhow::Error>
+ Send
@ -170,7 +176,7 @@ where
impl<M, R, S, T> SimulationRunner<M, R, S, T>
where
M: std::fmt::Debug + Clone + Send + Sync + 'static,
M: std::fmt::Debug + PayloadSize + Clone + Send + Sync + 'static,
R: Record
+ serde::Serialize
+ for<'a> TryFrom<&'a SimulationState<S, T>, Error = anyhow::Error>

View File

@ -1,4 +1,5 @@
use super::{SimulationRunner, SimulationRunnerHandle};
use crate::network::PayloadSize;
use crate::output_processors::Record;
use crate::warding::SimulationState;
use crossbeam::channel::{bounded, select};
@ -11,7 +12,7 @@ pub fn simulate<M, R, S, T>(
step_time: Duration,
) -> anyhow::Result<SimulationRunnerHandle<R>>
where
M: std::fmt::Debug + Send + Sync + Clone + 'static,
M: std::fmt::Debug + PayloadSize + Send + Sync + Clone + 'static,
R: Record
+ for<'a> TryFrom<&'a SimulationState<S, T>, Error = anyhow::Error>
+ Send
@ -35,7 +36,7 @@ where
loop {
select! {
recv(stop_rx) -> _ => {
return Ok(());
break;
}
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),
@ -49,11 +50,16 @@ where
p.send(R::try_from(&state)?)?;
// check if any condition makes the simulation stop
if inner_runner.check_wards(&state) {
return Ok(());
break;
}
}
}
}
tracing::info!(
"Total bandwidth results: {:?}",
inner_runner.network.bandwidth_results()
);
Ok(())
});
Ok(SimulationRunnerHandle {
producer: p1,

View File

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