Merge branch 'christof/parallel_economy' into 'master'

Parallel economic simulation, based on shredded_economy2

See merge request veloren/veloren!3288
This commit is contained in:
Marcel 2022-03-25 19:59:57 +00:00
commit a8a8ee181d
3 changed files with 69 additions and 53 deletions

View File

@ -1,3 +1,4 @@
use rayon::prelude::*;
use std::{
cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd},
fmt, hash,
@ -85,6 +86,15 @@ impl<T> Store<T> {
}
}
impl<T: Send + Sync> Store<T> {
pub fn par_iter_mut(&mut self) -> impl ParallelIterator<Item = (Id<T>, &mut T)> {
self.items
.par_iter_mut()
.enumerate()
.map(|(idx, obj)| (Id(idx as u64, PhantomData), obj))
}
}
impl<T> Index<Id<T>> for Store<T> {
type Output = T;

View File

@ -1,21 +1,21 @@
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 rayon::prelude::*;
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 +129,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()));
@ -236,22 +237,39 @@ 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::<Vec<_>>();
for site in site_ids {
tick_site_economy(index, site, dt, vc.context(&site.id().to_string()));
}
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);
}
}
index.sites.par_iter_mut().for_each(|(site_id, site)| {
if site.do_economic_simulation() {
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() {
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 +278,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<Site>, 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};

View File

@ -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
@ -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 {} }
}
}
@ -115,6 +117,8 @@ pub struct Economy {
/// outgoing trade, per provider
pub orders: DHashMap<Id<Site>, Vec<TradeOrder>>,
/// incoming trade - only towards this site
pub deliveries: Vec<TradeDelivery>,
}
impl Default for Economy {
@ -142,6 +146,7 @@ impl Default for Economy {
unconsumed_stock: Default::default(),
orders: Default::default(),
deliveries: Default::default(),
}
}
}
@ -652,7 +657,7 @@ impl Economy {
fn collect_deliveries(
// site: &mut Site,
&mut self,
deliveries: &mut Vec<TradeDelivery>,
// deliveries: &mut Vec<TradeDelivery>,
// ctx: &mut vergleich::Context,
) {
// collect all the goods we shipped
@ -664,7 +669,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 +690,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 +727,16 @@ impl Economy {
pub fn tick(
&mut self,
deliveries: Option<&mut Vec<TradeDelivery>>,
//deliveries: Option<&mut Vec<TradeDelivery>>,
site_id: Id<Site>,
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 +1073,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();