Add network data to runtime results (#43)
This commit is contained in:
parent
8147b7d718
commit
f97136bda6
|
@ -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,
|
||||||
|
|
|
@ -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(())
|
||||||
|
|
|
@ -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 = ();
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
})
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -95,7 +95,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subscribe_data_type() -> RecordType {
|
fn subscribe_data_type() -> RecordType {
|
||||||
RecordType::Data
|
RecordType::Meta
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue