From 96c5d1746093d50778cc76fe4e036bcaacdc1a24 Mon Sep 17 00:00:00 2001 From: Christof Petig Date: Sat, 19 Mar 2022 12:06:13 +0100 Subject: [PATCH 1/2] Address xmac's comments and prepare for parallelization --- world/src/sim2/mod.rs | 74 +++++++++++++++++------------------ world/src/site/economy/mod.rs | 30 ++++++++------ 2 files changed, 53 insertions(+), 51 deletions(-) diff --git a/world/src/sim2/mod.rs b/world/src/sim2/mod.rs index 6c0494f987..7bcaa6b45c 100644 --- a/world/src/sim2/mod.rs +++ b/world/src/sim2/mod.rs @@ -1,21 +1,20 @@ use crate::{ sim::WorldSim, site::{ - economy::{good_list, vergleich, LaborIndex, COIN_INDEX, INTER_SITE_TRADE, MONTH, YEAR}, + economy::{ + good_list, vergleich, LaborIndex, COIN_INDEX, DAYS_PER_MONTH, DAYS_PER_YEAR, + INTER_SITE_TRADE, + }, Site, SiteKind, }, Index, }; -use common::store::Id; use tracing::{debug, info}; -// const MONTH: f32 = 30.0; -// const YEAR: f32 = 12.0 * MONTH; -const TICK_PERIOD: f32 = 3.0 * MONTH; // 3 months -const HISTORY_DAYS: f32 = 500.0 * YEAR; // 500 years +const TICK_PERIOD: f32 = 3.0 * DAYS_PER_MONTH; // 3 months +const HISTORY_DAYS: f32 = 500.0 * DAYS_PER_YEAR; // 500 years const GENERATE_CSV: bool = false; -// const INTER_SITE_TRADE: bool = true; /// Statistics collector (min, max, avg) #[derive(Debug)] @@ -129,8 +128,9 @@ fn simulate_return(index: &mut Index, world: &mut WorldSim) -> Result<(), std::i .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?; vr.set_epsilon(0.1); for i in 0..(HISTORY_DAYS / TICK_PERIOD) as i32 { - if (index.time / YEAR) as i32 % 50 == 0 && (index.time % YEAR) as i32 == 0 { - debug!("Year {}", (index.time / YEAR) as i32); + if (index.time / DAYS_PER_YEAR) as i32 % 50 == 0 && (index.time % DAYS_PER_YEAR) as i32 == 0 + { + debug!("Year {}", (index.time / DAYS_PER_YEAR) as i32); } tick(index, world, TICK_PERIOD, vr.context(&i.to_string())); @@ -237,21 +237,37 @@ fn check_money(index: &mut Index) { } pub fn tick(index: &mut Index, _world: &mut WorldSim, dt: f32, mut vc: vergleich::Context) { - let site_ids = index.sites.ids().collect::>(); - for site in site_ids { - tick_site_economy(index, site, dt, vc.context(&site.id().to_string())); + if INTER_SITE_TRADE { + // move deliverables to recipient cities + for (id, deliv) in index.trade.deliveries.drain() { + index.sites.get_mut(id).economy.deliveries.extend(deliv); + } + } + for (site_id, site) in index.sites.iter_mut() { + if site.do_economic_simulation() { + site.economy + .tick(site_id, dt, vc.context(&site_id.id().to_string())); + } } if INTER_SITE_TRADE { + // distribute orders (travelling merchants) + for (_id, site) in index.sites.iter_mut() { + for (i, mut v) in site.economy.orders.drain() { + index + .trade + .orders + .entry(i) + .or_insert(Vec::new()) + .append(&mut v); + } + } + // trade at sites for (&site, orders) in index.trade.orders.iter_mut() { let siteinfo = index.sites.get_mut(site); if siteinfo.do_economic_simulation() { - // let name: String = siteinfo.name().into(); - siteinfo.economy.trade_at_site( - site, - orders, - // &mut siteinfo.economy, - &mut index.trade.deliveries, - ); + siteinfo + .economy + .trade_at_site(site, orders, &mut index.trade.deliveries); } } } @@ -260,26 +276,6 @@ pub fn tick(index: &mut Index, _world: &mut WorldSim, dt: f32, mut vc: vergleich index.time += dt; } -pub fn tick_site_economy(index: &mut Index, site_id: Id, dt: f32, vc: vergleich::Context) { - let site = &mut index.sites[site_id]; - if !site.do_economic_simulation() { - return; - } - let deliveries = index.trade.deliveries.get_mut(&site_id); - - let economy = &mut site.economy; - economy.tick(deliveries, site_id, dt, vc); - - for (i, mut v) in economy.orders.drain() { - index - .trade - .orders - .entry(i) - .or_insert(Vec::new()) - .append(&mut v); - } -} - #[cfg(test)] mod tests { use crate::{sim, site::economy::GoodMap, util::seed_expan}; diff --git a/world/src/site/economy/mod.rs b/world/src/site/economy/mod.rs index 157efee99e..0df0540658 100644 --- a/world/src/site/economy/mod.rs +++ b/world/src/site/economy/mod.rs @@ -17,8 +17,8 @@ mod map_types; pub use map_types::{GoodIndex, GoodMap, Labor, LaborIndex, LaborMap, NaturalResources}; pub const INTER_SITE_TRADE: bool = true; -pub const MONTH: f32 = 30.0; -pub const YEAR: f32 = 12.0 * MONTH; +pub const DAYS_PER_MONTH: f32 = 30.0; +pub const DAYS_PER_YEAR: f32 = 12.0 * DAYS_PER_MONTH; // this is an empty replacement for https://github.com/cpetig/vergleich // which can be used to compare values acros runs @@ -115,6 +115,8 @@ pub struct Economy { /// outgoing trade, per provider pub orders: DHashMap, Vec>, + /// incoming trade - only towards this site + pub deliveries: Vec, } impl Default for Economy { @@ -142,6 +144,7 @@ impl Default for Economy { unconsumed_stock: Default::default(), orders: Default::default(), + deliveries: Default::default(), } } } @@ -652,7 +655,7 @@ impl Economy { fn collect_deliveries( // site: &mut Site, &mut self, - deliveries: &mut Vec, + // deliveries: &mut Vec, // ctx: &mut vergleich::Context, ) { // collect all the goods we shipped @@ -664,7 +667,7 @@ impl Economy { 0.0, ); // TODO: properly rate benefits created by merchants (done below?) - for mut d in deliveries.drain(..) { + for mut d in self.deliveries.drain(..) { // let mut ictx = ctx.context(&format!("suppl {}", d.supplier.id())); for i in d.amount.iter() { last_exports[i.0] -= *i.1; @@ -685,9 +688,9 @@ impl Economy { } } } - if !deliveries.is_empty() { - info!("non empty deliveries {:?}", deliveries); - deliveries.clear(); + if !self.deliveries.is_empty() { + info!("non empty deliveries {:?}", self.deliveries); + self.deliveries.clear(); } std::mem::swap(&mut last_exports, &mut self.last_exports); //self.active_exports.clear(); @@ -722,16 +725,16 @@ impl Economy { pub fn tick( &mut self, - deliveries: Option<&mut Vec>, + //deliveries: Option<&mut Vec>, site_id: Id, dt: f32, mut vc: vergleich::Context, ) { // collect goods from trading if INTER_SITE_TRADE { - if let Some(deliveries) = deliveries { - self.collect_deliveries(deliveries); - } + // if let Some(deliveries) = deliveries { + self.collect_deliveries(); + // } } let orders = self.get_orders(); @@ -1068,7 +1071,10 @@ impl Economy { } else { 0.0 }; - self.pop += vc.value("pop", dt / YEAR * self.pop * (birth_rate - DEATH_RATE)); + self.pop += vc.value( + "pop", + dt / DAYS_PER_YEAR * self.pop * (birth_rate - DEATH_RATE), + ); // calculate the new unclaimed stock //let next_orders = self.get_orders(); From aeac483bacd2ed6070a611631f9ee127e79f8018 Mon Sep 17 00:00:00 2001 From: Christof Petig Date: Sat, 19 Mar 2022 15:51:07 +0100 Subject: [PATCH 2/2] parallel simulation of economies --- common/src/store.rs | 10 ++++++++++ world/src/sim2/mod.rs | 12 +++++++----- world/src/site/economy/mod.rs | 2 ++ 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/common/src/store.rs b/common/src/store.rs index 7c03577d7d..99b2f37d36 100644 --- a/common/src/store.rs +++ b/common/src/store.rs @@ -1,3 +1,4 @@ +use rayon::prelude::*; use std::{ cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}, fmt, hash, @@ -85,6 +86,15 @@ impl Store { } } +impl Store { + pub fn par_iter_mut(&mut self) -> impl ParallelIterator, &mut T)> { + self.items + .par_iter_mut() + .enumerate() + .map(|(idx, obj)| (Id(idx as u64, PhantomData), obj)) + } +} + impl Index> for Store { type Output = T; diff --git a/world/src/sim2/mod.rs b/world/src/sim2/mod.rs index 7bcaa6b45c..1d8876564e 100644 --- a/world/src/sim2/mod.rs +++ b/world/src/sim2/mod.rs @@ -9,6 +9,7 @@ use crate::{ }, Index, }; +use rayon::prelude::*; use tracing::{debug, info}; const TICK_PERIOD: f32 = 3.0 * DAYS_PER_MONTH; // 3 months @@ -236,19 +237,20 @@ fn check_money(index: &mut Index) { ); } -pub fn tick(index: &mut Index, _world: &mut WorldSim, dt: f32, mut vc: vergleich::Context) { +pub fn tick(index: &mut Index, _world: &mut WorldSim, dt: f32, _vc: vergleich::Context) { if INTER_SITE_TRADE { // move deliverables to recipient cities for (id, deliv) in index.trade.deliveries.drain() { index.sites.get_mut(id).economy.deliveries.extend(deliv); } } - for (site_id, site) in index.sites.iter_mut() { + index.sites.par_iter_mut().for_each(|(site_id, site)| { if site.do_economic_simulation() { - site.economy - .tick(site_id, dt, vc.context(&site_id.id().to_string())); + site.economy.tick(site_id, dt, vergleich::Context::dummy()); + // helpful for debugging but not compatible with parallel execution + // vc.context(&site_id.id().to_string())); } - } + }); if INTER_SITE_TRADE { // distribute orders (travelling merchants) for (_id, site) in index.sites.iter_mut() { diff --git a/world/src/site/economy/mod.rs b/world/src/site/economy/mod.rs index 0df0540658..f747a55944 100644 --- a/world/src/site/economy/mod.rs +++ b/world/src/site/economy/mod.rs @@ -43,6 +43,8 @@ pub mod vergleich { pub fn context(&mut self, _: &str) -> Context { Context {} } pub fn value(&mut self, _: &str, val: f32) -> f32 { val } + + pub fn dummy() -> Self { Context {} } } }