mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Add more profiling spans to Server startup related things in order to
visualize where time is being spent. Make `Lod::from_world` use the same rayon pool as other things during the server startup. Move parallel iteration up out of structure_gen.par_iter in order to slightly optimize Lod::from_world (saves a few hundred milliseconds on my machine)
This commit is contained in:
parent
92a42ced18
commit
c6f5e8dac2
@ -3,6 +3,7 @@ use super::{
|
|||||||
vec2_as_uniform_idx, TerrainChunkSize, NEIGHBOR_DELTA, TERRAIN_CHUNK_BLOCKS_LG,
|
vec2_as_uniform_idx, TerrainChunkSize, NEIGHBOR_DELTA, TERRAIN_CHUNK_BLOCKS_LG,
|
||||||
};
|
};
|
||||||
use crate::vol::RectVolSize;
|
use crate::vol::RectVolSize;
|
||||||
|
use common_base::prof_span;
|
||||||
use core::{f32, f64, iter, ops::RangeInclusive};
|
use core::{f32, f64, iter, ops::RangeInclusive};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
@ -451,6 +452,7 @@ impl<'a> MapConfig<'a> {
|
|||||||
sample_wpos: impl Fn(Vec2<i32>) -> f32,
|
sample_wpos: impl Fn(Vec2<i32>) -> f32,
|
||||||
mut write_pixel: impl FnMut(Vec2<usize>, (u8, u8, u8, u8)),
|
mut write_pixel: impl FnMut(Vec2<usize>, (u8, u8, u8, u8)),
|
||||||
) -> MapDebug {
|
) -> MapDebug {
|
||||||
|
prof_span!("MapConfig::generate");
|
||||||
let MapConfig {
|
let MapConfig {
|
||||||
map_size_lg,
|
map_size_lg,
|
||||||
dimensions,
|
dimensions,
|
||||||
|
@ -24,7 +24,7 @@ use common::{
|
|||||||
vol::{ReadVol, WriteVol},
|
vol::{ReadVol, WriteVol},
|
||||||
weather::{Weather, WeatherGrid},
|
weather::{Weather, WeatherGrid},
|
||||||
};
|
};
|
||||||
use common_base::span;
|
use common_base::{prof_span, span};
|
||||||
use common_ecs::{PhysicsMetrics, SysMetrics};
|
use common_ecs::{PhysicsMetrics, SysMetrics};
|
||||||
use common_net::sync::{interpolation as sync_interp, WorldSyncExt};
|
use common_net::sync::{interpolation as sync_interp, WorldSyncExt};
|
||||||
use core::{convert::identity, time::Duration};
|
use core::{convert::identity, time::Duration};
|
||||||
@ -179,6 +179,7 @@ impl State {
|
|||||||
map_size_lg: MapSizeLg,
|
map_size_lg: MapSizeLg,
|
||||||
default_chunk: Arc<TerrainChunk>,
|
default_chunk: Arc<TerrainChunk>,
|
||||||
) -> specs::World {
|
) -> specs::World {
|
||||||
|
prof_span!("State::setup_ecs_world");
|
||||||
let mut ecs = specs::World::new();
|
let mut ecs = specs::World::new();
|
||||||
// Uids for sync
|
// Uids for sync
|
||||||
ecs.register_sync_marker();
|
ecs.register_sync_marker();
|
||||||
|
@ -284,6 +284,8 @@ impl Server {
|
|||||||
default_chunk: Arc::new(world.generate_oob_chunk()),
|
default_chunk: Arc::new(world.generate_oob_chunk()),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let lod = lod::Lod::from_world(&world, index.as_index_ref(), &pools);
|
||||||
|
|
||||||
let mut state = State::server(
|
let mut state = State::server(
|
||||||
pools,
|
pools,
|
||||||
world.sim().map_size_lg(),
|
world.sim().map_size_lg(),
|
||||||
@ -455,7 +457,7 @@ impl Server {
|
|||||||
state.ecs_mut().insert(Arc::clone(&world));
|
state.ecs_mut().insert(Arc::clone(&world));
|
||||||
state
|
state
|
||||||
.ecs_mut()
|
.ecs_mut()
|
||||||
.insert(lod::Lod::from_world(&world, index.as_index_ref()));
|
.insert(lod);
|
||||||
state.ecs_mut().insert(index.clone());
|
state.ecs_mut().insert(index.clone());
|
||||||
|
|
||||||
// Set starting time for the server.
|
// Set starting time for the server.
|
||||||
|
@ -17,19 +17,23 @@ pub struct Lod {
|
|||||||
|
|
||||||
impl Lod {
|
impl Lod {
|
||||||
#[cfg(feature = "worldgen")]
|
#[cfg(feature = "worldgen")]
|
||||||
pub fn from_world(world: &World, index: IndexRef) -> Self {
|
pub fn from_world(world: &World, index: IndexRef, threadpool: &rayon::ThreadPool) -> Self {
|
||||||
let mut zones = HashMap::new();
|
common_base::prof_span!("Lod::from_world");
|
||||||
|
threadpool.install(|| {
|
||||||
|
let zone_sz = (world.sim().get_size() + lod::ZONE_SIZE - 1) / lod::ZONE_SIZE;
|
||||||
|
|
||||||
let zone_sz = (world.sim().get_size() + lod::ZONE_SIZE - 1) / lod::ZONE_SIZE;
|
use rayon::prelude::*;
|
||||||
|
let zones = (0..zone_sz.x)
|
||||||
|
.into_par_iter()
|
||||||
|
.flat_map(|i| (0..zone_sz.y).into_par_iter().map(move |j| (i, j)))
|
||||||
|
.map(|(i, j)| {
|
||||||
|
let zone_pos = Vec2::new(i, j).map(|e| e as i32);
|
||||||
|
(zone_pos, world.get_lod_zone(zone_pos, index))
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
for i in 0..zone_sz.x {
|
Self { zones }
|
||||||
for j in 0..zone_sz.y {
|
})
|
||||||
let zone_pos = Vec2::new(i, j).map(|e| e as i32);
|
|
||||||
zones.insert(zone_pos, world.get_lod_zone(zone_pos, index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Self { zones }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "worldgen"))]
|
#[cfg(not(feature = "worldgen"))]
|
||||||
|
@ -275,6 +275,7 @@ impl Civs {
|
|||||||
//=== old economy is gone
|
//=== old economy is gone
|
||||||
|
|
||||||
// Flatten ground around sites
|
// Flatten ground around sites
|
||||||
|
prof_span!(guard, "Flatten ground around sites");
|
||||||
for site in this.sites.values() {
|
for site in this.sites.values() {
|
||||||
let wpos = site.center * TerrainChunkSize::RECT_SIZE.map(|e: u32| e as i32);
|
let wpos = site.center * TerrainChunkSize::RECT_SIZE.map(|e: u32| e as i32);
|
||||||
|
|
||||||
@ -339,8 +340,10 @@ impl Civs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
drop(guard);
|
||||||
|
|
||||||
// Place sites in world
|
// Place sites in world
|
||||||
|
prof_span!(guard, "Place sites in world");
|
||||||
let mut cnt = 0;
|
let mut cnt = 0;
|
||||||
for sim_site in this.sites.values_mut() {
|
for sim_site in this.sites.values_mut() {
|
||||||
cnt += 1;
|
cnt += 1;
|
||||||
@ -436,6 +439,7 @@ impl Civs {
|
|||||||
}
|
}
|
||||||
debug!(?sim_site.center, "Placed site at location");
|
debug!(?sim_site.center, "Placed site at location");
|
||||||
}
|
}
|
||||||
|
drop(guard);
|
||||||
info!(?cnt, "all sites placed");
|
info!(?cnt, "all sites placed");
|
||||||
|
|
||||||
//this.display_info();
|
//this.display_info();
|
||||||
@ -465,23 +469,25 @@ impl Civs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: this looks optimizable
|
||||||
|
|
||||||
// collect natural resources
|
// collect natural resources
|
||||||
|
prof_span!(guard, "collect natural resources");
|
||||||
let sites = &mut index.sites;
|
let sites = &mut index.sites;
|
||||||
(0..ctx.sim.map_size_lg().chunks_len())
|
(0..ctx.sim.map_size_lg().chunks_len()).for_each(|posi| {
|
||||||
.into_iter()
|
let chpos = uniform_idx_as_vec2(ctx.sim.map_size_lg(), posi);
|
||||||
.for_each(|posi| {
|
let wpos = chpos.map(|e| e as i64) * TerrainChunkSize::RECT_SIZE.map(|e| e as i64);
|
||||||
let chpos = uniform_idx_as_vec2(ctx.sim.map_size_lg(), posi);
|
let closest_site = (*sites)
|
||||||
let wpos = chpos.map(|e| e as i64) * TerrainChunkSize::RECT_SIZE.map(|e| e as i64);
|
.iter_mut()
|
||||||
let closest_site = (*sites)
|
.filter(|s| !matches!(s.1.kind, crate::site::SiteKind::Dungeon(_)))
|
||||||
.iter_mut()
|
.min_by_key(|(_id, s)| s.get_origin().map(|e| e as i64).distance_squared(wpos));
|
||||||
.filter(|s| !matches!(s.1.kind, crate::site::SiteKind::Dungeon(_)))
|
if let Some((_id, s)) = closest_site {
|
||||||
.min_by_key(|(_id, s)| s.get_origin().map(|e| e as i64).distance_squared(wpos));
|
let distance_squared = s.get_origin().map(|e| e as i64).distance_squared(wpos);
|
||||||
if let Some((_id, s)) = closest_site {
|
s.economy
|
||||||
let distance_squared = s.get_origin().map(|e| e as i64).distance_squared(wpos);
|
.add_chunk(ctx.sim.get(chpos).unwrap(), distance_squared);
|
||||||
s.economy
|
}
|
||||||
.add_chunk(ctx.sim.get(chpos).unwrap(), distance_squared);
|
});
|
||||||
}
|
drop(guard);
|
||||||
});
|
|
||||||
sites
|
sites
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.for_each(|(_, s)| s.economy.cache_economy());
|
.for_each(|(_, s)| s.economy.cache_economy());
|
||||||
|
@ -60,7 +60,6 @@ use common_net::msg::{world_msg, WorldMapMsg};
|
|||||||
use enum_map::EnumMap;
|
use enum_map::EnumMap;
|
||||||
use rand::{prelude::*, Rng};
|
use rand::{prelude::*, Rng};
|
||||||
use rand_chacha::ChaCha8Rng;
|
use rand_chacha::ChaCha8Rng;
|
||||||
use rayon::iter::ParallelIterator;
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
@ -138,6 +137,7 @@ impl World {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_map_data(&self, index: IndexRef, threadpool: &rayon::ThreadPool) -> WorldMapMsg {
|
pub fn get_map_data(&self, index: IndexRef, threadpool: &rayon::ThreadPool) -> WorldMapMsg {
|
||||||
|
prof_span!("World::get_map_data");
|
||||||
threadpool.install(|| {
|
threadpool.install(|| {
|
||||||
// we need these numbers to create unique ids for cave ends
|
// we need these numbers to create unique ids for cave ends
|
||||||
let num_sites = self.civs().sites().count() as u64;
|
let num_sites = self.civs().sites().count() as u64;
|
||||||
@ -564,6 +564,7 @@ impl World {
|
|||||||
let mut objects = Vec::new();
|
let mut objects = Vec::new();
|
||||||
|
|
||||||
// Add trees
|
// Add trees
|
||||||
|
prof_span!(guard, "add trees");
|
||||||
objects.append(
|
objects.append(
|
||||||
&mut self
|
&mut self
|
||||||
.sim()
|
.sim()
|
||||||
@ -602,6 +603,7 @@ impl World {
|
|||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
);
|
);
|
||||||
|
drop(guard);
|
||||||
|
|
||||||
// Add buildings
|
// Add buildings
|
||||||
objects.extend(
|
objects.extend(
|
||||||
|
@ -51,6 +51,7 @@ use common::{
|
|||||||
},
|
},
|
||||||
vol::RectVolSize,
|
vol::RectVolSize,
|
||||||
};
|
};
|
||||||
|
use common_base::prof_span;
|
||||||
use common_net::msg::WorldMapMsg;
|
use common_net::msg::WorldMapMsg;
|
||||||
use noise::{
|
use noise::{
|
||||||
BasicMulti, Billow, Fbm, HybridMulti, MultiFractal, NoiseFn, RangeFunction, RidgedMulti,
|
BasicMulti, Billow, Fbm, HybridMulti, MultiFractal, NoiseFn, RangeFunction, RidgedMulti,
|
||||||
@ -668,6 +669,7 @@ pub struct WorldSim {
|
|||||||
|
|
||||||
impl WorldSim {
|
impl WorldSim {
|
||||||
pub fn generate(seed: u32, opts: WorldOpts, threadpool: &rayon::ThreadPool) -> Self {
|
pub fn generate(seed: u32, opts: WorldOpts, threadpool: &rayon::ThreadPool) -> Self {
|
||||||
|
prof_span!("WorldSim::generate");
|
||||||
let calendar = opts.calendar; // separate lifetime of elements
|
let calendar = opts.calendar; // separate lifetime of elements
|
||||||
let world_file = opts.world_file;
|
let world_file = opts.world_file;
|
||||||
|
|
||||||
@ -1586,6 +1588,7 @@ impl WorldSim {
|
|||||||
/// Draw a map of the world based on chunk information. Returns a buffer of
|
/// Draw a map of the world based on chunk information. Returns a buffer of
|
||||||
/// u32s.
|
/// u32s.
|
||||||
pub fn get_map(&self, index: IndexRef, calendar: Option<&Calendar>) -> WorldMapMsg {
|
pub fn get_map(&self, index: IndexRef, calendar: Option<&Calendar>) -> WorldMapMsg {
|
||||||
|
prof_span!("WorldSim::get_map");
|
||||||
let mut map_config = MapConfig::orthographic(
|
let mut map_config = MapConfig::orthographic(
|
||||||
self.map_size_lg(),
|
self.map_size_lg(),
|
||||||
core::ops::RangeInclusive::new(CONFIG.sea_level, CONFIG.sea_level + self.max_height),
|
core::ops::RangeInclusive::new(CONFIG.sea_level, CONFIG.sea_level + self.max_height),
|
||||||
@ -1603,6 +1606,7 @@ impl WorldSim {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let samples_data = {
|
let samples_data = {
|
||||||
|
prof_span!("samples data");
|
||||||
let column_sample = ColumnGen::new(self);
|
let column_sample = ColumnGen::new(self);
|
||||||
(0..self.map_size_lg().chunks_len())
|
(0..self.map_size_lg().chunks_len())
|
||||||
.into_par_iter()
|
.into_par_iter()
|
||||||
@ -2293,10 +2297,10 @@ impl WorldSim {
|
|||||||
&self,
|
&self,
|
||||||
wpos_min: Vec2<i32>,
|
wpos_min: Vec2<i32>,
|
||||||
wpos_max: Vec2<i32>,
|
wpos_max: Vec2<i32>,
|
||||||
) -> impl ParallelIterator<Item = TreeAttr> + '_ {
|
) -> impl Iterator<Item = TreeAttr> + '_ {
|
||||||
self.gen_ctx
|
self.gen_ctx
|
||||||
.structure_gen
|
.structure_gen
|
||||||
.par_iter(wpos_min, wpos_max)
|
.iter(wpos_min, wpos_max)
|
||||||
.filter_map(move |(wpos, seed)| {
|
.filter_map(move |(wpos, seed)| {
|
||||||
let lottery = self.make_forest_lottery(wpos);
|
let lottery = self.make_forest_lottery(wpos);
|
||||||
Some(TreeAttr {
|
Some(TreeAttr {
|
||||||
|
@ -3,6 +3,7 @@ use common::{
|
|||||||
terrain::{neighbors, uniform_idx_as_vec2, vec2_as_uniform_idx, MapSizeLg, TerrainChunkSize},
|
terrain::{neighbors, uniform_idx_as_vec2, vec2_as_uniform_idx, MapSizeLg, TerrainChunkSize},
|
||||||
vol::RectVolSize,
|
vol::RectVolSize,
|
||||||
};
|
};
|
||||||
|
use common_base::prof_span;
|
||||||
use noise::{MultiFractal, NoiseFn, Perlin, Seedable};
|
use noise::{MultiFractal, NoiseFn, Perlin, Seedable};
|
||||||
use num::Float;
|
use num::Float;
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
@ -374,6 +375,7 @@ pub fn get_horizon_map<F: Float + Sync, A: Send, H: Send>(
|
|||||||
to_angle: impl Fn(F) -> A + Sync,
|
to_angle: impl Fn(F) -> A + Sync,
|
||||||
to_height: impl Fn(F) -> H + Sync,
|
to_height: impl Fn(F) -> H + Sync,
|
||||||
) -> Result<[HorizonMap<A, H>; 2], ()> {
|
) -> Result<[HorizonMap<A, H>; 2], ()> {
|
||||||
|
prof_span!("get_horizon_map");
|
||||||
if maxh < minh {
|
if maxh < minh {
|
||||||
// maxh must be greater than minh
|
// maxh must be greater than minh
|
||||||
return Err(());
|
return Err(());
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
use crate::{sim::WorldSim, site::economy::simulate_economy, Index};
|
use crate::{sim::WorldSim, site::economy::simulate_economy, Index};
|
||||||
|
use common_base::prof_span;
|
||||||
|
|
||||||
pub fn simulate(index: &mut Index, _world: &mut WorldSim) { simulate_economy(index); }
|
pub fn simulate(index: &mut Index, _world: &mut WorldSim) {
|
||||||
|
prof_span!("sim2::simulate");
|
||||||
|
simulate_economy(index);
|
||||||
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use super::{RandomField, Sampler};
|
use super::{RandomField, Sampler};
|
||||||
use rayon::prelude::*;
|
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -69,11 +68,7 @@ impl StructureGen2d {
|
|||||||
|
|
||||||
/// Note: Generates all possible closest samples for elements in the range
|
/// Note: Generates all possible closest samples for elements in the range
|
||||||
/// of min to max, *exclusive.*
|
/// of min to max, *exclusive.*
|
||||||
pub fn par_iter(
|
pub fn iter(&self, min: Vec2<i32>, max: Vec2<i32>) -> impl Iterator<Item = StructureField> {
|
||||||
&self,
|
|
||||||
min: Vec2<i32>,
|
|
||||||
max: Vec2<i32>,
|
|
||||||
) -> impl ParallelIterator<Item = StructureField> {
|
|
||||||
let freq = self.freq;
|
let freq = self.freq;
|
||||||
let spread = self.spread;
|
let spread = self.spread;
|
||||||
let spread_mul = Self::spread_mul(spread);
|
let spread_mul = Self::spread_mul(spread);
|
||||||
@ -102,7 +97,7 @@ impl StructureGen2d {
|
|||||||
let x_field = self.x_field;
|
let x_field = self.x_field;
|
||||||
let y_field = self.y_field;
|
let y_field = self.y_field;
|
||||||
let seed_field = self.seed_field;
|
let seed_field = self.seed_field;
|
||||||
(0..len).into_par_iter().map(move |xy| {
|
(0..len).map(move |xy| {
|
||||||
let index = min_index + Vec2::new((xy % xlen as u64) as i32, (xy / xlen as u64) as i32);
|
let index = min_index + Vec2::new((xy % xlen as u64) as i32, (xy / xlen as u64) as i32);
|
||||||
Self::index_to_sample_internal(
|
Self::index_to_sample_internal(
|
||||||
freq,
|
freq,
|
||||||
|
Loading…
Reference in New Issue
Block a user