Implement a VSystem trait that can be implemented by Systems.

It will autodo some things, like track start and time and export those in system metrics
Add a origin and implement it for all Systems in Veloren
This commit is contained in:
Marcel Märtens 2021-03-04 15:00:16 +01:00
parent b7079b454c
commit c515fece28
41 changed files with 871 additions and 218 deletions

12
Cargo.lock generated
View File

@ -1643,6 +1643,15 @@ dependencies = [
"miniz_oxide 0.4.3", "miniz_oxide 0.4.3",
] ]
[[package]]
name = "float-cmp"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1267f4ac4f343772758f7b1bdcbe767c218bbab93bb432acbf5162bbf85a6c4"
dependencies = [
"num-traits",
]
[[package]] [[package]]
name = "fnv" name = "fnv"
version = "1.0.7" version = "1.0.7"
@ -5598,6 +5607,7 @@ dependencies = [
"directories-next", "directories-next",
"dot_vox", "dot_vox",
"enum-iterator", "enum-iterator",
"float-cmp",
"hashbrown 0.9.1", "hashbrown 0.9.1",
"image", "image",
"indexmap", "indexmap",
@ -6681,4 +6691,4 @@ dependencies = [
name = "xml-rs" name = "xml-rs"
version = "0.8.3" version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b07db065a5cf61a7e4ba64f29e67db906fb1787316516c4e6e5ff0fea1efcd8a" checksum = "b07db065a5cf61a7e4ba64f29e67db906fb1787316516c4e6e5ff0fea1efcd8a"

View File

@ -68,6 +68,7 @@ specs-idvs = { git = "https://gitlab.com/veloren/specs-idvs.git", rev = "9fab7b3
[dev-dependencies] [dev-dependencies]
#bench #bench
criterion = "0.3" criterion = "0.3"
float-cmp = "0.8.0"
[[bench]] [[bench]]
name = "chonk_benchmark" name = "chonk_benchmark"

View File

@ -71,6 +71,7 @@ pub mod uid;
#[cfg(not(target_arch = "wasm32"))] pub mod vol; #[cfg(not(target_arch = "wasm32"))] pub mod vol;
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
pub mod volumes; pub mod volumes;
pub mod vsystem;
pub use combat::DamageSource; pub use combat::DamageSource;
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]

View File

@ -1,7 +1,12 @@
use std::sync::atomic::AtomicU64; use crate::vsystem::CpuTimeline;
use std::{
collections::HashMap,
sync::{atomic::AtomicU64, Mutex},
};
#[derive(Default)] #[derive(Default)]
pub struct SysMetrics { pub struct SysMetrics {
pub stats: Mutex<HashMap<String, CpuTimeline>>,
pub agent_ns: AtomicU64, pub agent_ns: AtomicU64,
pub mount_ns: AtomicU64, pub mount_ns: AtomicU64,
pub controller_ns: AtomicU64, pub controller_ns: AtomicU64,

458
common/src/vsystem.rs Normal file
View File

@ -0,0 +1,458 @@
use crate::metrics::SysMetrics;
use specs::{ReadExpect, RunNow, System};
use std::{collections::HashMap, time::Instant};
/// measuring the level of threads a unit of code ran on. Use Rayon when it ran
/// on their threadpool. Use Exact when you know on how many threads your code
/// ran on exactly.
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ParMode {
None, /* Job is not running at all */
Single,
Rayon,
Exact(u16),
}
//TODO: make use of the phase of a system for advanced scheduling and logging
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum Phase {
Create,
Review,
Apply,
}
//TODO: make use of the origin of the system for better logging
#[derive(Clone, PartialEq, Debug)]
pub enum Origin {
Common,
Client,
Server,
Frontend(&'static str),
}
#[derive(Default, Debug, Clone)]
pub struct CpuTimeline {
///
/// - The first entry will always be ParMode::Single, as when the
/// System::run is executed, we run
/// single threaded until we start a Rayon::ParIter or similar
/// - The last entry will contain the end time of the System. To mark the
/// End it will always contain
/// ParMode::None, which means from that point on 0 CPU threads work in this
/// system
measures: Vec<(Instant, ParMode)>,
}
#[derive(Default)]
pub struct CpuTimeStats {
/// the first entry will always be 0, the last entry will always be `dt`
/// `usage` starting from `ns`
measures: Vec<(/* ns */ u64, /* usage */ f32)>,
}
/// Parallel Mode tells us how much you are scaling. `None` means your code
/// isn't running. `Single` means you are running single threaded.
/// `Rayon` means you are running on the rayon threadpool.
impl ParMode {
fn threads(&self, rayon_threads: u16) -> u16 {
match self {
ParMode::None => 0,
ParMode::Single => 1,
ParMode::Rayon => rayon_threads,
ParMode::Exact(u) => *u,
}
}
}
impl CpuTimeline {
fn reset(&mut self) {
self.measures.clear();
self.measures.push((Instant::now(), ParMode::Single));
}
/// Start a new measurement. par will be covering the parallelisation AFTER
/// this statement, till the next / end of the VSystem.
pub fn measure(&mut self, par: ParMode) { self.measures.push((Instant::now(), par)); }
fn end(&mut self) { self.measures.push((Instant::now(), ParMode::None)); }
fn get(&self, time: Instant) -> ParMode {
match self.measures.binary_search_by_key(&time, |&(a, _)| a) {
Ok(id) => self.measures[id].1,
Err(0) => ParMode::None, /* not yet started */
Err(id) => self.measures[id - 1].1,
}
}
}
impl CpuTimeStats {
pub fn length_ns(&self) -> u64 { self.end_ns() - self.start_ns() }
pub fn start_ns(&self) -> u64 {
self.measures
.iter()
.find(|e| e.1 > 0.001)
.unwrap_or(&(0, 0.0))
.0
}
pub fn end_ns(&self) -> u64 { self.measures.last().unwrap_or(&(0, 0.0)).0 }
pub fn avg_threads(&self) -> f32 {
let mut sum = 0.0;
for w in self.measures.windows(2) {
let len = w[1].0 - w[0].0;
let h = w[0].1;
sum += len as f32 * h;
}
sum / (self.length_ns() as f32)
}
}
/// The Idea is to transform individual timelines per system to a map of all
/// cores and what they (prob) are working on.
///
/// # Example
///
/// - Input: 3 services, 0 and 1 are 100% parallel and 2 is single threaded. `-`
/// means no work for *0.5s*. `#` means full work for *0.5s*. We see the first
/// service starts after 1s and runs for 3s The second one starts a sec later
/// and runs for 4s. The last service runs 2.5s after the tick start and runs
/// for 1s. Read left to right.
/// ```ignore
/// [--######------]
/// [----########--]
/// [-----##-------]
/// ```
///
/// - Output: a Map that calculates where our 6 cores are spending their time.
/// Here each number means 50% of a core is working on it. A '-' represents an
/// idling core. We start with all 6 cores idling. Then all cores start to
/// work on task 0. 2s in, task1 starts and we have to split cores. 2.5s in
/// task2 starts. We have 6 physical threads but work to fill 13. Later task 2
/// and task 0 will finish their work and give more threads for task 1 to work
/// on. Read top to bottom
/// ```ignore
/// 0-1s [------------]
/// 1-2s [000000000000]
/// 2-2.5s [000000111111]
/// 2.5-3.5s [000001111122]
/// 3.5-4s [000000111111]
/// 4-6s [111111111111]
/// 6s.. [------------]
/// ```
pub fn gen_stats(
timelines: &HashMap<String, CpuTimeline>,
tick_work_start: Instant,
rayon_threads: u16,
physical_threads: u16,
) -> HashMap<String, CpuTimeStats> {
let mut result = HashMap::new();
let mut all = timelines
.iter()
.map(|(s, t)| {
let mut stat = CpuTimeStats::default();
stat.measures.push((0, 0.0));
result.insert(s.clone(), stat);
t.measures.iter().map(|e| &e.0)
})
.flatten()
.collect::<Vec<_>>();
all.sort();
all.dedup();
for time in all {
let relative_time = time.duration_since(tick_work_start).as_nanos() as u64;
// get all parallelisation at this particular time
let individual_cores_wanted = timelines
.iter()
.map(|(k, t)| (k, t.get(*time).threads(rayon_threads)))
.collect::<Vec<_>>();
let total = individual_cores_wanted
.iter()
.map(|(_, a)| a)
.sum::<u16>()
.max(1) as f32;
let total_or_max = total.max(physical_threads as f32);
// update ALL states
for individual in individual_cores_wanted.iter() {
let actual = (individual.1 as f32 / total_or_max) * physical_threads as f32;
let p = result.get_mut(individual.0).unwrap();
if (p.measures.last().unwrap().1 - actual).abs() > 0.0001 {
p.measures.push((relative_time, actual));
}
}
}
result
}
/// This trait wraps around specs::System and does additional veloren tasks like
/// metrics collection
///
/// ```
/// use specs::Read;
/// pub use veloren_common::vsystem::{Origin, ParMode, Phase, VJob, VSystem};
/// # use std::time::Duration;
/// pub struct Sys;
/// impl<'a> VSystem<'a> for Sys {
/// type SystemData = (Read<'a, ()>, Read<'a, ()>);
///
/// const NAME: &'static str = "example";
/// const ORIGIN: Origin = Origin::Frontend("voxygen");
/// const PHASE: Phase = Phase::Create;
///
/// fn run(job: &mut VJob<Self>, (_read, _read2): Self::SystemData) {
/// std::thread::sleep(Duration::from_millis(100));
/// job.cpu_stats.measure(ParMode::Rayon);
/// std::thread::sleep(Duration::from_millis(500));
/// job.cpu_stats.measure(ParMode::Single);
/// std::thread::sleep(Duration::from_millis(40));
/// }
/// }
/// ```
pub trait VSystem<'a> {
const NAME: &'static str;
const PHASE: Phase;
const ORIGIN: Origin;
type SystemData: specs::SystemData<'a>;
fn run(job: &mut VJob<Self>, data: Self::SystemData);
fn sys_name() -> String { format!("{}_sys", Self::NAME) }
}
pub fn dispatch<'a, 'b, T>(builder: &mut specs::DispatcherBuilder<'a, 'b>, dep: &[&str])
where
T: for<'c> VSystem<'c> + Send + 'a + Default,
{
builder.add(VJob::<T>::default(), &T::sys_name(), dep);
}
pub fn run_now<'a, 'b, T>(world: &'a specs::World)
where
T: for<'c> VSystem<'c> + Send + 'a + Default,
{
VJob::<T>::default().run_now(world);
}
/// This Struct will wrap the System in order to avoid the can only impl trait
/// for local defined structs error It also contains the cpu measurements
pub struct VJob<T>
where
T: ?Sized,
{
pub own: Box<T>,
pub cpu_stats: CpuTimeline,
}
impl<'a, T> System<'a> for VJob<T>
where
T: VSystem<'a>,
{
type SystemData = (T::SystemData, ReadExpect<'a, SysMetrics>);
fn run(&mut self, data: Self::SystemData) {
crate::span!(_guard, "run", &format!("{}::Sys::run", T::NAME));
self.cpu_stats.reset();
T::run(self, data.0);
self.cpu_stats.end();
data.1
.stats
.lock()
.unwrap()
.insert(T::NAME.to_string(), self.cpu_stats.clone());
}
}
impl<'a, T> Default for VJob<T>
where
T: VSystem<'a> + Default,
{
fn default() -> Self {
Self {
own: Box::new(T::default()),
cpu_stats: CpuTimeline::default(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use float_cmp::approx_eq;
use std::time::Duration;
fn mock_timelines(
tick_start: Instant,
durations: Vec<(u64, u64, ParMode)>,
) -> HashMap<String, CpuTimeline> {
let job = durations
.iter()
.enumerate()
.map(|(i, (s, e, p))| {
(
i,
tick_start + Duration::from_millis(*s),
tick_start + Duration::from_millis(*e),
*p,
)
})
.collect::<Vec<_>>();
job.iter()
.map(|(i, f, s, p)| {
(i.to_string(), CpuTimeline {
measures: vec![(*f, *p), (*s, ParMode::None)],
})
})
.collect()
}
#[test]
fn single() {
const RAYON_THREADS: u16 = 4;
const PHYSICAL_THREADS: u16 = RAYON_THREADS;
let tick_start = Instant::now();
let job_d = vec![(500, 1500, ParMode::Rayon)];
let timelines = mock_timelines(tick_start, job_d);
let stats = gen_stats(&timelines, tick_start, RAYON_THREADS, PHYSICAL_THREADS);
const THREADS: f32 = PHYSICAL_THREADS as f32;
let s = &stats["0"];
let measures = &s.measures;
assert_eq!(measures.len(), 3);
assert_eq!(measures[0].0, 0);
assert!(approx_eq!(f32, measures[0].1, 0.0));
assert_eq!(measures[1].0, 500000000);
assert!(approx_eq!(f32, measures[1].1, THREADS));
assert_eq!(measures[2].0, 1500000000);
assert!(approx_eq!(f32, measures[2].1, 0.0));
assert_eq!(s.start_ns(), 500000000);
assert_eq!(s.end_ns(), 1500000000);
assert_eq!(s.length_ns(), 1000000000);
assert!(approx_eq!(f32, s.avg_threads(), THREADS));
}
#[test]
fn two_jobs() {
const RAYON_THREADS: u16 = 8;
const PHYSICAL_THREADS: u16 = RAYON_THREADS;
let tick_start = Instant::now();
let job_d = vec![(2000, 3000, ParMode::Single), (5000, 6500, ParMode::Single)];
let timelines = mock_timelines(tick_start, job_d);
let stats = gen_stats(&timelines, tick_start, RAYON_THREADS, PHYSICAL_THREADS);
let s = &stats["0"];
let measures = &s.measures;
assert_eq!(measures.len(), 3);
assert_eq!(measures[0].0, 0);
assert!(approx_eq!(f32, measures[0].1, 0.0));
assert_eq!(measures[1].0, 2000000000);
assert!(approx_eq!(f32, measures[1].1, 1.0));
assert_eq!(measures[2].0, 3000000000);
assert!(approx_eq!(f32, measures[2].1, 0.0));
assert_eq!(s.start_ns(), 2000000000);
assert_eq!(s.end_ns(), 3000000000);
assert_eq!(s.length_ns(), 1000000000);
assert!(approx_eq!(f32, s.avg_threads(), 1.0));
let s = &stats["1"];
let measures = &s.measures;
assert_eq!(measures.len(), 3);
assert_eq!(measures[0].0, 0);
assert!(approx_eq!(f32, measures[0].1, 0.0));
assert_eq!(measures[1].0, 5000000000);
assert!(approx_eq!(f32, measures[1].1, 1.0));
assert_eq!(measures[2].0, 6500000000);
assert!(approx_eq!(f32, measures[2].1, 0.0));
assert_eq!(s.start_ns(), 5000000000);
assert_eq!(s.end_ns(), 6500000000);
assert_eq!(s.length_ns(), 1500000000);
assert!(approx_eq!(f32, s.avg_threads(), 1.0));
}
#[test]
fn generate_stats() {
const RAYON_THREADS: u16 = 6;
const PHYSICAL_THREADS: u16 = RAYON_THREADS;
let tick_start = Instant::now();
let job_d = vec![
(2000, 5000, ParMode::Rayon),
(3000, 7000, ParMode::Rayon),
(3500, 4500, ParMode::Single),
];
let timelines = mock_timelines(tick_start, job_d);
let stats = gen_stats(&timelines, tick_start, RAYON_THREADS, PHYSICAL_THREADS);
const THREADS: f32 = PHYSICAL_THREADS as f32;
let s = &stats["0"];
let measures = &s.measures;
assert_eq!(measures.len(), 6);
assert_eq!(measures[0].0, 0);
assert!(approx_eq!(f32, measures[0].1, 0.0));
assert_eq!(measures[1].0, 2000000000);
assert!(approx_eq!(f32, measures[1].1, THREADS));
assert_eq!(measures[2].0, 3000000000);
assert!(approx_eq!(f32, measures[2].1, THREADS / 2.0));
assert_eq!(measures[3].0, 3500000000);
assert!(approx_eq!(
f32,
measures[3].1,
THREADS * THREADS / (THREADS * 2.0 + 1.0)
));
assert_eq!(measures[4].0, 4500000000);
assert!(approx_eq!(f32, measures[4].1, THREADS / 2.0));
assert_eq!(measures[5].0, 5000000000);
assert!(approx_eq!(f32, measures[5].1, 0.0));
assert_eq!(s.start_ns(), 2000000000);
assert_eq!(s.end_ns(), 5000000000);
assert_eq!(s.length_ns(), 3000000000);
assert!(approx_eq!(f32, s.avg_threads(), 3.923077));
let s = &stats["1"];
let measures = &s.measures;
assert_eq!(measures.len(), 6);
assert_eq!(measures[0].0, 0);
assert!(approx_eq!(f32, measures[0].1, 0.0));
assert_eq!(measures[1].0, 3000000000);
assert!(approx_eq!(f32, measures[1].1, THREADS / 2.0));
assert_eq!(measures[2].0, 3500000000);
assert!(approx_eq!(
f32,
measures[2].1,
THREADS * THREADS / (THREADS * 2.0 + 1.0)
));
assert_eq!(measures[3].0, 4500000000);
assert!(approx_eq!(f32, measures[3].1, THREADS / 2.0));
assert_eq!(measures[4].0, 5000000000);
assert!(approx_eq!(f32, measures[4].1, THREADS));
assert_eq!(measures[5].0, 7000000000);
assert!(approx_eq!(f32, measures[5].1, 0.0));
assert_eq!(s.start_ns(), 3000000000);
assert_eq!(s.end_ns(), 7000000000);
assert_eq!(s.length_ns(), 4000000000);
assert!(approx_eq!(f32, s.avg_threads(), 4.4423075));
let s = &stats["2"];
let measures = &s.measures;
assert_eq!(measures.len(), 3);
assert_eq!(measures[0].0, 0);
assert!(approx_eq!(f32, measures[0].1, 0.0));
assert_eq!(measures[1].0, 3500000000);
assert!(approx_eq!(
f32,
measures[1].1,
THREADS / (THREADS * 2.0 + 1.0)
));
assert_eq!(measures[2].0, 4500000000);
assert!(approx_eq!(f32, measures[2].1, 0.0));
assert_eq!(s.start_ns(), 3500000000);
assert_eq!(s.end_ns(), 4500000000);
assert_eq!(s.length_ns(), 1000000000);
assert!(approx_eq!(f32, s.avg_threads(), 0.4615385));
}
}

View File

@ -8,10 +8,11 @@ use common::{
event::{EventBus, ServerEvent}, event::{EventBus, ServerEvent},
resources::DeltaTime, resources::DeltaTime,
uid::UidAllocator, uid::UidAllocator,
vsystem::{Origin, Phase, VJob, VSystem},
}; };
use specs::{ use specs::{
saveload::MarkerAllocator, shred::ResourceId, Entities, Join, Read, ReadStorage, System, saveload::MarkerAllocator, shred::ResourceId, Entities, Join, Read, ReadStorage, SystemData,
SystemData, World, WriteStorage, World, WriteStorage,
}; };
use std::time::Duration; use std::time::Duration;
@ -27,15 +28,20 @@ pub struct ReadData<'a> {
groups: ReadStorage<'a, Group>, groups: ReadStorage<'a, Group>,
} }
#[derive(Default)]
pub struct Sys; pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> VSystem<'a> for Sys {
type SystemData = ( type SystemData = (
ReadData<'a>, ReadData<'a>,
WriteStorage<'a, Auras>, WriteStorage<'a, Auras>,
WriteStorage<'a, Buffs>, WriteStorage<'a, Buffs>,
); );
fn run(&mut self, (read_data, mut auras, mut buffs): Self::SystemData) { const NAME: &'static str = "aura";
const ORIGIN: Origin = Origin::Common;
const PHASE: Phase = Phase::Create;
fn run(_job: &mut VJob<Self>, (read_data, mut auras, mut buffs): Self::SystemData) {
let mut server_emitter = read_data.server_bus.emitter(); let mut server_emitter = read_data.server_bus.emitter();
let dt = read_data.dt.0; let dt = read_data.dt.0;

View File

@ -7,11 +7,12 @@ use common::{
event::{EventBus, ServerEvent}, event::{EventBus, ServerEvent},
resources::{DeltaTime, Time}, resources::{DeltaTime, Time},
uid::{Uid, UidAllocator}, uid::{Uid, UidAllocator},
vsystem::{Origin, Phase, VJob, VSystem},
GroupTarget, GroupTarget,
}; };
use specs::{ use specs::{
saveload::MarkerAllocator, shred::ResourceId, Entities, Join, Read, ReadStorage, System, saveload::MarkerAllocator, shred::ResourceId, Entities, Join, Read, ReadStorage, SystemData,
SystemData, World, WriteStorage, World, WriteStorage,
}; };
use std::time::Duration; use std::time::Duration;
use vek::*; use vek::*;
@ -37,15 +38,20 @@ pub struct ReadData<'a> {
} }
/// This system is responsible for handling beams that heal or do damage /// This system is responsible for handling beams that heal or do damage
#[derive(Default)]
pub struct Sys; pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> VSystem<'a> for Sys {
type SystemData = ( type SystemData = (
ReadData<'a>, ReadData<'a>,
WriteStorage<'a, BeamSegment>, WriteStorage<'a, BeamSegment>,
WriteStorage<'a, Beam>, WriteStorage<'a, Beam>,
); );
fn run(&mut self, (read_data, mut beam_segments, mut beams): Self::SystemData) { const NAME: &'static str = "beam";
const ORIGIN: Origin = Origin::Common;
const PHASE: Phase = Phase::Create;
fn run(_job: &mut VJob<Self>, (read_data, mut beam_segments, mut beams): Self::SystemData) {
let mut server_emitter = read_data.server_bus.emitter(); let mut server_emitter = read_data.server_bus.emitter();
let time = read_data.time.0; let time = read_data.time.0;

View File

@ -5,10 +5,11 @@ use common::{
}, },
event::{EventBus, ServerEvent}, event::{EventBus, ServerEvent},
resources::DeltaTime, resources::DeltaTime,
vsystem::{Origin, Phase, VJob, VSystem},
Damage, DamageSource, Damage, DamageSource,
}; };
use specs::{ use specs::{
shred::ResourceId, Entities, Join, Read, ReadStorage, System, SystemData, World, WriteStorage, shred::ResourceId, Entities, Join, Read, ReadStorage, SystemData, World, WriteStorage,
}; };
use std::time::Duration; use std::time::Duration;
@ -20,8 +21,9 @@ pub struct ReadData<'a> {
inventories: ReadStorage<'a, Inventory>, inventories: ReadStorage<'a, Inventory>,
} }
#[derive(Default)]
pub struct Sys; pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> VSystem<'a> for Sys {
type SystemData = ( type SystemData = (
ReadData<'a>, ReadData<'a>,
WriteStorage<'a, Health>, WriteStorage<'a, Health>,
@ -30,8 +32,12 @@ impl<'a> System<'a> for Sys {
WriteStorage<'a, Stats>, WriteStorage<'a, Stats>,
); );
const NAME: &'static str = "buff";
const ORIGIN: Origin = Origin::Common;
const PHASE: Phase = Phase::Create;
fn run( fn run(
&mut self, _job: &mut VJob<Self>,
(read_data, mut healths, mut energies, mut buffs, mut stats): Self::SystemData, (read_data, mut healths, mut energies, mut buffs, mut stats): Self::SystemData,
) { ) {
let mut server_emitter = read_data.server_bus.emitter(); let mut server_emitter = read_data.server_bus.emitter();

View File

@ -1,6 +1,6 @@
use specs::{ use specs::{
shred::ResourceId, Entities, Join, LazyUpdate, Read, ReadExpect, ReadStorage, System, shred::ResourceId, Entities, Join, LazyUpdate, Read, ReadExpect, ReadStorage, SystemData,
SystemData, World, WriteStorage, World, WriteStorage,
}; };
use common::{ use common::{
@ -15,12 +15,12 @@ use common::{
event::{EventBus, LocalEvent, ServerEvent}, event::{EventBus, LocalEvent, ServerEvent},
metrics::SysMetrics, metrics::SysMetrics,
resources::DeltaTime, resources::DeltaTime,
span,
states::{ states::{
self, self,
behavior::{CharacterBehavior, JoinData, JoinStruct}, behavior::{CharacterBehavior, JoinData, JoinStruct},
}, },
uid::Uid, uid::Uid,
vsystem::{Origin, Phase, VJob, VSystem},
}; };
use std::time::Duration; use std::time::Duration;
@ -72,9 +72,10 @@ pub struct ReadData<'a> {
/// ## Character Behavior System /// ## Character Behavior System
/// Passes `JoinData` to `CharacterState`'s `behavior` handler fn's. Receives a /// Passes `JoinData` to `CharacterState`'s `behavior` handler fn's. Receives a
/// `StateUpdate` in return and performs updates to ECS Components from that. /// `StateUpdate` in return and performs updates to ECS Components from that.
#[derive(Default)]
pub struct Sys; pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> VSystem<'a> for Sys {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
type SystemData = ( type SystemData = (
ReadData<'a>, ReadData<'a>,
@ -88,9 +89,13 @@ impl<'a> System<'a> for Sys {
WriteStorage<'a, Poise>, WriteStorage<'a, Poise>,
); );
const NAME: &'static str = "character_behavior";
const ORIGIN: Origin = Origin::Common;
const PHASE: Phase = Phase::Create;
#[allow(clippy::while_let_on_iterator)] // TODO: Pending review in #587 #[allow(clippy::while_let_on_iterator)] // TODO: Pending review in #587
fn run( fn run(
&mut self, _job: &mut VJob<Self>,
( (
read_data, read_data,
mut character_states, mut character_states,
@ -104,7 +109,6 @@ impl<'a> System<'a> for Sys {
): Self::SystemData, ): Self::SystemData,
) { ) {
let start_time = std::time::Instant::now(); let start_time = std::time::Instant::now();
span!(_guard, "run", "character_behavior::Sys::run");
let mut server_emitter = read_data.server_bus.emitter(); let mut server_emitter = read_data.server_bus.emitter();
let mut local_emitter = read_data.local_bus.emitter(); let mut local_emitter = read_data.local_bus.emitter();

View File

@ -2,13 +2,13 @@ use common::{
comp::{BuffChange, ControlEvent, Controller}, comp::{BuffChange, ControlEvent, Controller},
event::{EventBus, ServerEvent}, event::{EventBus, ServerEvent},
metrics::SysMetrics, metrics::SysMetrics,
span,
uid::UidAllocator, uid::UidAllocator,
vsystem::{Origin, Phase, VJob, VSystem},
}; };
use specs::{ use specs::{
saveload::{Marker, MarkerAllocator}, saveload::{Marker, MarkerAllocator},
shred::ResourceId, shred::ResourceId,
Entities, Join, Read, ReadExpect, System, SystemData, World, WriteStorage, Entities, Join, Read, ReadExpect, SystemData, World, WriteStorage,
}; };
use vek::*; use vek::*;
@ -20,14 +20,18 @@ pub struct ReadData<'a> {
metrics: ReadExpect<'a, SysMetrics>, metrics: ReadExpect<'a, SysMetrics>,
} }
#[derive(Default)]
pub struct Sys; pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> VSystem<'a> for Sys {
type SystemData = (ReadData<'a>, WriteStorage<'a, Controller>); type SystemData = (ReadData<'a>, WriteStorage<'a, Controller>);
fn run(&mut self, (read_data, mut controllers): Self::SystemData) { const NAME: &'static str = "controller";
const ORIGIN: Origin = Origin::Common;
const PHASE: Phase = Phase::Create;
fn run(_job: &mut VJob<Self>, (read_data, mut controllers): Self::SystemData) {
let start_time = std::time::Instant::now(); let start_time = std::time::Instant::now();
span!(_guard, "run", "controller::Sys::run");
let mut server_emitter = read_data.server_bus.emitter(); let mut server_emitter = read_data.server_bus.emitter();
for (entity, controller) in (&read_data.entities, &mut controllers).join() { for (entity, controller) in (&read_data.entities, &mut controllers).join() {

View File

@ -15,33 +15,23 @@ pub mod state;
mod stats; mod stats;
// External // External
use common::vsystem::{dispatch, VSystem};
use specs::DispatcherBuilder; use specs::DispatcherBuilder;
// System names
pub const CHARACTER_BEHAVIOR_SYS: &str = "character_behavior_sys";
pub const MELEE_SYS: &str = "melee_sys";
pub const BEAM_SYS: &str = "beam_sys";
pub const CONTROLLER_SYS: &str = "controller_sys";
pub const MOUNT_SYS: &str = "mount_sys";
pub const PHYS_SYS: &str = "phys_sys";
pub const PROJECTILE_SYS: &str = "projectile_sys";
pub const SHOCKWAVE_SYS: &str = "shockwave_sys";
pub const STATS_SYS: &str = "stats_sys";
pub const BUFFS_SYS: &str = "buffs_sys";
pub const AURAS_SYS: &str = "auras_sys";
pub fn add_local_systems(dispatch_builder: &mut DispatcherBuilder) { pub fn add_local_systems(dispatch_builder: &mut DispatcherBuilder) {
dispatch_builder.add(mount::Sys, MOUNT_SYS, &[]); dispatch::<mount::Sys>(dispatch_builder, &[]);
dispatch_builder.add(controller::Sys, CONTROLLER_SYS, &[MOUNT_SYS]); dispatch::<controller::Sys>(dispatch_builder, &[&mount::Sys::sys_name()]);
dispatch_builder.add(character_behavior::Sys, CHARACTER_BEHAVIOR_SYS, &[ dispatch::<character_behavior::Sys>(dispatch_builder, &[&controller::Sys::sys_name()]);
CONTROLLER_SYS, dispatch::<stats::Sys>(dispatch_builder, &[]);
dispatch::<buff::Sys>(dispatch_builder, &[]);
dispatch::<phys::Sys>(dispatch_builder, &[
&controller::Sys::sys_name(),
&mount::Sys::sys_name(),
&stats::Sys::sys_name(),
]); ]);
dispatch_builder.add(stats::Sys, STATS_SYS, &[]); dispatch::<projectile::Sys>(dispatch_builder, &[&phys::Sys::sys_name()]);
dispatch_builder.add(buff::Sys, BUFFS_SYS, &[]); dispatch::<shockwave::Sys>(dispatch_builder, &[&phys::Sys::sys_name()]);
dispatch_builder.add(phys::Sys, PHYS_SYS, &[CONTROLLER_SYS, MOUNT_SYS, STATS_SYS]); dispatch::<beam::Sys>(dispatch_builder, &[&phys::Sys::sys_name()]);
dispatch_builder.add(projectile::Sys, PROJECTILE_SYS, &[PHYS_SYS]); dispatch::<melee::Sys>(dispatch_builder, &[&projectile::Sys::sys_name()]);
dispatch_builder.add(shockwave::Sys, SHOCKWAVE_SYS, &[PHYS_SYS]); dispatch::<aura::Sys>(dispatch_builder, &[]);
dispatch_builder.add(beam::Sys, BEAM_SYS, &[PHYS_SYS]);
dispatch_builder.add(melee::Sys, MELEE_SYS, &[PROJECTILE_SYS]);
dispatch_builder.add(aura::Sys, AURAS_SYS, &[]);
} }

View File

@ -3,13 +3,13 @@ use common::{
comp::{Body, CharacterState, Energy, Group, Health, Inventory, Melee, Ori, Pos, Scale, Stats}, comp::{Body, CharacterState, Energy, Group, Health, Inventory, Melee, Ori, Pos, Scale, Stats},
event::{EventBus, ServerEvent}, event::{EventBus, ServerEvent},
metrics::SysMetrics, metrics::SysMetrics,
span,
uid::Uid, uid::Uid,
util::Dir, util::Dir,
vsystem::{Origin, Phase, VJob, VSystem},
GroupTarget, GroupTarget,
}; };
use specs::{ use specs::{
shred::ResourceId, Entities, Join, Read, ReadExpect, ReadStorage, System, SystemData, World, shred::ResourceId, Entities, Join, Read, ReadExpect, ReadStorage, SystemData, World,
WriteStorage, WriteStorage,
}; };
use vek::*; use vek::*;
@ -34,14 +34,18 @@ pub struct ReadData<'a> {
/// This system is responsible for handling accepted inputs like moving or /// This system is responsible for handling accepted inputs like moving or
/// attacking /// attacking
#[derive(Default)]
pub struct Sys; pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> VSystem<'a> for Sys {
type SystemData = (ReadData<'a>, WriteStorage<'a, Melee>); type SystemData = (ReadData<'a>, WriteStorage<'a, Melee>);
fn run(&mut self, (read_data, mut melee_attacks): Self::SystemData) { const NAME: &'static str = "melee";
const ORIGIN: Origin = Origin::Common;
const PHASE: Phase = Phase::Create;
fn run(_job: &mut VJob<Self>, (read_data, mut melee_attacks): Self::SystemData) {
let start_time = std::time::Instant::now(); let start_time = std::time::Instant::now();
span!(_guard, "run", "melee::Sys::run");
let mut server_emitter = read_data.server_bus.emitter(); let mut server_emitter = read_data.server_bus.emitter();
// Attacks // Attacks
for (attacker, uid, pos, ori, melee_attack, body) in ( for (attacker, uid, pos, ori, melee_attack, body) in (

View File

@ -1,18 +1,19 @@
use common::{ use common::{
comp::{Controller, MountState, Mounting, Ori, Pos, Vel}, comp::{Controller, MountState, Mounting, Ori, Pos, Vel},
metrics::SysMetrics, metrics::SysMetrics,
span,
uid::UidAllocator, uid::UidAllocator,
vsystem::{Origin, Phase, VJob, VSystem},
}; };
use specs::{ use specs::{
saveload::{Marker, MarkerAllocator}, saveload::{Marker, MarkerAllocator},
Entities, Join, Read, ReadExpect, System, WriteStorage, Entities, Join, Read, ReadExpect, WriteStorage,
}; };
use vek::*; use vek::*;
/// This system is responsible for controlling mounts /// This system is responsible for controlling mounts
#[derive(Default)]
pub struct Sys; pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> VSystem<'a> for Sys {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
type SystemData = ( type SystemData = (
Read<'a, UidAllocator>, Read<'a, UidAllocator>,
@ -26,8 +27,12 @@ impl<'a> System<'a> for Sys {
WriteStorage<'a, Ori>, WriteStorage<'a, Ori>,
); );
const NAME: &'static str = "mount";
const ORIGIN: Origin = Origin::Common;
const PHASE: Phase = Phase::Create;
fn run( fn run(
&mut self, _job: &mut VJob<Self>,
( (
uid_allocator, uid_allocator,
sys_metrics, sys_metrics,
@ -41,7 +46,6 @@ impl<'a> System<'a> for Sys {
): Self::SystemData, ): Self::SystemData,
) { ) {
let start_time = std::time::Instant::now(); let start_time = std::time::Instant::now();
span!(_guard, "run", "mount::Sys::run");
// Mounted entities. // Mounted entities.
for (entity, mut mount_states) in (&entities, &mut mount_state.restrict_mut()).join() { for (entity, mut mount_states) in (&entities, &mut mount_state.restrict_mut()).join() {
match mount_states.get_unchecked() { match mount_states.get_unchecked() {

View File

@ -11,11 +11,10 @@ use common::{
terrain::{Block, TerrainGrid}, terrain::{Block, TerrainGrid},
uid::Uid, uid::Uid,
vol::ReadVol, vol::ReadVol,
vsystem::{Origin, ParMode, Phase, VJob, VSystem},
}; };
use rayon::iter::ParallelIterator; use rayon::iter::ParallelIterator;
use specs::{ use specs::{Entities, Join, ParJoin, Read, ReadExpect, ReadStorage, WriteExpect, WriteStorage};
Entities, Join, ParJoin, Read, ReadExpect, ReadStorage, System, WriteExpect, WriteStorage,
};
use std::ops::Range; use std::ops::Range;
use vek::*; use vek::*;
@ -61,9 +60,10 @@ fn calc_z_limit(
} }
/// This system applies forces and calculates new positions and velocities. /// This system applies forces and calculates new positions and velocities.
#[derive(Default)]
pub struct Sys; pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> VSystem<'a> for Sys {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
type SystemData = ( type SystemData = (
Entities<'a>, Entities<'a>,
@ -90,10 +90,14 @@ impl<'a> System<'a> for Sys {
ReadStorage<'a, CharacterState>, ReadStorage<'a, CharacterState>,
); );
const NAME: &'static str = "phys";
const ORIGIN: Origin = Origin::Common;
const PHASE: Phase = Phase::Create;
#[allow(clippy::or_fun_call)] // TODO: Pending review in #587 #[allow(clippy::or_fun_call)] // TODO: Pending review in #587
#[allow(clippy::blocks_in_if_conditions)] // TODO: Pending review in #587 #[allow(clippy::blocks_in_if_conditions)] // TODO: Pending review in #587
fn run( fn run(
&mut self, job: &mut VJob<Self>,
( (
entities, entities,
uids, uids,
@ -120,7 +124,6 @@ impl<'a> System<'a> for Sys {
): Self::SystemData, ): Self::SystemData,
) { ) {
let start_time = std::time::Instant::now(); let start_time = std::time::Instant::now();
span!(_guard, "run", "phys::Sys::run");
let mut event_emitter = event_bus.emitter(); let mut event_emitter = event_bus.emitter();
// Add/reset physics state components // Add/reset physics state components
@ -212,6 +215,7 @@ impl<'a> System<'a> for Sys {
drop(guard); drop(guard);
span!(guard, "Apply pushback"); span!(guard, "Apply pushback");
job.cpu_stats.measure(ParMode::Rayon);
let metrics = ( let metrics = (
&entities, &entities,
&positions, &positions,
@ -776,6 +780,7 @@ impl<'a> System<'a> for Sys {
land_on_grounds_a land_on_grounds_a
}); });
drop(guard); drop(guard);
job.cpu_stats.measure(ParMode::Single);
land_on_grounds.into_iter().for_each(|(entity, vel)| { land_on_grounds.into_iter().for_each(|(entity, vel)| {
event_emitter.emit(ServerEvent::LandOnGround { entity, vel: vel.0 }); event_emitter.emit(ServerEvent::LandOnGround { entity, vel: vel.0 });

View File

@ -7,14 +7,14 @@ use common::{
event::{EventBus, ServerEvent}, event::{EventBus, ServerEvent},
metrics::SysMetrics, metrics::SysMetrics,
resources::DeltaTime, resources::DeltaTime,
span,
uid::UidAllocator, uid::UidAllocator,
util::Dir, util::Dir,
vsystem::{Origin, Phase, VJob, VSystem},
GroupTarget, GroupTarget,
}; };
use specs::{ use specs::{
saveload::MarkerAllocator, shred::ResourceId, Entities, Join, Read, ReadExpect, ReadStorage, saveload::MarkerAllocator, shred::ResourceId, Entities, Join, Read, ReadExpect, ReadStorage,
System, SystemData, World, WriteStorage, SystemData, World, WriteStorage,
}; };
use std::time::Duration; use std::time::Duration;
@ -35,17 +35,24 @@ pub struct ReadData<'a> {
} }
/// This system is responsible for handling projectile effect triggers /// This system is responsible for handling projectile effect triggers
#[derive(Default)]
pub struct Sys; pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> VSystem<'a> for Sys {
type SystemData = ( type SystemData = (
ReadData<'a>, ReadData<'a>,
WriteStorage<'a, Ori>, WriteStorage<'a, Ori>,
WriteStorage<'a, Projectile>, WriteStorage<'a, Projectile>,
); );
fn run(&mut self, (read_data, mut orientations, mut projectiles): Self::SystemData) { const NAME: &'static str = "projectile";
const ORIGIN: Origin = Origin::Common;
const PHASE: Phase = Phase::Create;
fn run(
_job: &mut VJob<Self>,
(read_data, mut orientations, mut projectiles): Self::SystemData,
) {
let start_time = std::time::Instant::now(); let start_time = std::time::Instant::now();
span!(_guard, "run", "projectile::Sys::run");
let mut server_emitter = read_data.server_bus.emitter(); let mut server_emitter = read_data.server_bus.emitter();
// Attacks // Attacks

View File

@ -8,11 +8,12 @@ use common::{
resources::{DeltaTime, Time}, resources::{DeltaTime, Time},
uid::{Uid, UidAllocator}, uid::{Uid, UidAllocator},
util::Dir, util::Dir,
vsystem::{Origin, Phase, VJob, VSystem},
GroupTarget, GroupTarget,
}; };
use specs::{ use specs::{
saveload::MarkerAllocator, shred::ResourceId, Entities, Join, Read, ReadStorage, System, saveload::MarkerAllocator, shred::ResourceId, Entities, Join, Read, ReadStorage, SystemData,
SystemData, World, WriteStorage, World, WriteStorage,
}; };
use vek::*; use vek::*;
@ -39,15 +40,23 @@ pub struct ReadData<'a> {
/// This system is responsible for handling accepted inputs like moving or /// This system is responsible for handling accepted inputs like moving or
/// attacking /// attacking
#[derive(Default)]
pub struct Sys; pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> VSystem<'a> for Sys {
type SystemData = ( type SystemData = (
ReadData<'a>, ReadData<'a>,
WriteStorage<'a, Shockwave>, WriteStorage<'a, Shockwave>,
WriteStorage<'a, ShockwaveHitEntities>, WriteStorage<'a, ShockwaveHitEntities>,
); );
fn run(&mut self, (read_data, mut shockwaves, mut shockwave_hit_lists): Self::SystemData) { const NAME: &'static str = "shockwave";
const ORIGIN: Origin = Origin::Common;
const PHASE: Phase = Phase::Create;
fn run(
_job: &mut VJob<Self>,
(read_data, mut shockwaves, mut shockwave_hit_lists): Self::SystemData,
) {
let mut server_emitter = read_data.server_bus.emitter(); let mut server_emitter = read_data.server_bus.emitter();
let time = read_data.time.0; let time = read_data.time.0;

View File

@ -8,13 +8,13 @@ use common::{
metrics::SysMetrics, metrics::SysMetrics,
outcome::Outcome, outcome::Outcome,
resources::{DeltaTime, Time}, resources::{DeltaTime, Time},
span,
uid::Uid, uid::Uid,
vsystem::{Origin, Phase, VJob, VSystem},
}; };
use hashbrown::HashSet; use hashbrown::HashSet;
use specs::{ use specs::{
shred::ResourceId, Entities, Join, Read, ReadExpect, ReadStorage, System, SystemData, World, shred::ResourceId, Entities, Join, Read, ReadExpect, ReadStorage, SystemData, World, Write,
Write, WriteStorage, WriteStorage,
}; };
use vek::Vec3; use vek::Vec3;
@ -36,8 +36,9 @@ pub struct ReadData<'a> {
} }
/// This system kills players, levels them up, and regenerates energy. /// This system kills players, levels them up, and regenerates energy.
#[derive(Default)]
pub struct Sys; pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> VSystem<'a> for Sys {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
type SystemData = ( type SystemData = (
ReadData<'a>, ReadData<'a>,
@ -49,8 +50,12 @@ impl<'a> System<'a> for Sys {
Write<'a, Vec<Outcome>>, Write<'a, Vec<Outcome>>,
); );
const NAME: &'static str = "stats";
const ORIGIN: Origin = Origin::Common;
const PHASE: Phase = Phase::Create;
fn run( fn run(
&mut self, _job: &mut VJob<Self>,
( (
read_data, read_data,
mut stats, mut stats,
@ -62,7 +67,6 @@ impl<'a> System<'a> for Sys {
): Self::SystemData, ): Self::SystemData,
) { ) {
let start_time = std::time::Instant::now(); let start_time = std::time::Instant::now();
span!(_guard, "run", "stats::Sys::run");
let mut server_event_emitter = read_data.server_bus.emitter(); let mut server_event_emitter = read_data.server_bus.emitter();
let dt = read_data.dt.0; let dt = read_data.dt.0;

View File

@ -66,6 +66,7 @@ use common::{
rtsim::RtSimEntity, rtsim::RtSimEntity,
terrain::TerrainChunkSize, terrain::TerrainChunkSize,
vol::{ReadVol, RectVolSize}, vol::{ReadVol, RectVolSize},
vsystem::run_now,
}; };
use common_net::{ use common_net::{
msg::{ msg::{
@ -87,11 +88,11 @@ use persistence::{
use plugin_api::Uid; use plugin_api::Uid;
use prometheus::Registry; use prometheus::Registry;
use prometheus_hyper::Server as PrometheusServer; use prometheus_hyper::Server as PrometheusServer;
use specs::{join::Join, Builder, Entity as EcsEntity, RunNow, SystemData, WorldExt}; use specs::{join::Join, Builder, Entity as EcsEntity, SystemData, WorldExt};
use std::{ use std::{
i32, i32,
ops::{Deref, DerefMut}, ops::{Deref, DerefMut},
sync::{atomic::Ordering, Arc}, sync::Arc,
time::{Duration, Instant}, time::{Duration, Instant},
}; };
#[cfg(not(feature = "worldgen"))] #[cfg(not(feature = "worldgen"))]
@ -510,12 +511,12 @@ impl Server {
// Run message receiving sys before the systems in common for decreased latency // Run message receiving sys before the systems in common for decreased latency
// (e.g. run before controller system) // (e.g. run before controller system)
//TODO: run in parallel //TODO: run in parallel
sys::msg::general::Sys.run_now(&self.state.ecs()); run_now::<sys::msg::general::Sys>(&self.state.ecs());
self.register_run(); self.register_run();
sys::msg::character_screen::Sys.run_now(&self.state.ecs()); run_now::<sys::msg::character_screen::Sys>(&self.state.ecs());
sys::msg::in_game::Sys.run_now(&self.state.ecs()); run_now::<sys::msg::in_game::Sys>(&self.state.ecs());
sys::msg::ping::Sys.run_now(&self.state.ecs()); run_now::<sys::msg::ping::Sys>(&self.state.ecs());
sys::agent::Sys.run_now(&self.state.ecs()); run_now::<sys::agent::Sys>(&self.state.ecs());
let before_state_tick = Instant::now(); let before_state_tick = Instant::now();
@ -705,6 +706,29 @@ impl Server {
// 8) Update Metrics // 8) Update Metrics
// Get system timing info // Get system timing info
{
let lock = self
.state
.ecs()
.read_resource::<common::metrics::SysMetrics>();
let state = lock.stats.lock().unwrap();
for (name, stat) in common::vsystem::gen_stats(&state, before_new_connections, 8, 8) {
self.tick_metrics
.system_start_time
.with_label_values(&[&name])
.set(stat.start_ns() as i64);
self.tick_metrics
.system_length_time
.with_label_values(&[&name])
.set(stat.length_ns() as i64);
self.tick_metrics
.system_thread_avg
.with_label_values(&[&name])
.set(stat.avg_threads() as f64);
}
}
let agent_nanos = self.state.ecs().read_resource::<sys::AgentTimer>().nanos as i64; let agent_nanos = self.state.ecs().read_resource::<sys::AgentTimer>().nanos as i64;
let entity_sync_nanos = self let entity_sync_nanos = self
.state .state
@ -819,6 +843,7 @@ impl Server {
//detailed state metrics //detailed state metrics
{ {
/*
let res = self let res = self
.state .state
.ecs() .ecs()
@ -834,7 +859,7 @@ impl Server {
let melee_ns = res.melee_ns.load(Ordering::Relaxed); let melee_ns = res.melee_ns.load(Ordering::Relaxed);
c.with_label_values(&[sys::AGENT_SYS]).inc_by(agent_ns); c.with_label_values(&[sys::AGENT_SYS]).inc_by(agent_ns);
c.with_label_values(&[common_sys::MOUNT_SYS]) c.with_label_values(&[common_sys::])
.inc_by(mount_ns); .inc_by(mount_ns);
c.with_label_values(&[common_sys::CONTROLLER_SYS]) c.with_label_values(&[common_sys::CONTROLLER_SYS])
.inc_by(controller_ns); .inc_by(controller_ns);
@ -866,6 +891,7 @@ impl Server {
.observe(projectile_ns as f64 / NANOSEC_PER_SEC); .observe(projectile_ns as f64 / NANOSEC_PER_SEC);
h.with_label_values(&[common_sys::MELEE_SYS]) h.with_label_values(&[common_sys::MELEE_SYS])
.observe(melee_ns as f64 / NANOSEC_PER_SEC); .observe(melee_ns as f64 / NANOSEC_PER_SEC);
*/
} }
//detailed physics metrics //detailed physics metrics

View File

@ -1,6 +1,6 @@
use prometheus::{ use prometheus::{
Gauge, HistogramOpts, HistogramVec, IntCounter, IntCounterVec, IntGauge, IntGaugeVec, Opts, Gauge, GaugeVec, HistogramOpts, HistogramVec, IntCounter, IntCounterVec, IntGauge, IntGaugeVec,
Registry, Opts, Registry,
}; };
use std::{ use std::{
convert::TryInto, convert::TryInto,
@ -54,6 +54,9 @@ pub struct TickMetrics {
pub start_time: IntGauge, pub start_time: IntGauge,
pub time_of_day: Gauge, pub time_of_day: Gauge,
pub light_count: IntGauge, pub light_count: IntGauge,
pub system_start_time: IntGaugeVec,
pub system_length_time: IntGaugeVec,
pub system_thread_avg: GaugeVec,
tick: Arc<AtomicU64>, tick: Arc<AtomicU64>,
} }
@ -290,6 +293,24 @@ impl TickMetrics {
Opts::new("tick_time", "time in ns required for a tick of the server"), Opts::new("tick_time", "time in ns required for a tick of the server"),
&["period"], &["period"],
)?; )?;
let system_start_time = IntGaugeVec::new(
Opts::new(
"system_start_time",
"start relative to tick start in ns required per ECS system",
),
&["system"],
)?;
let system_length_time = IntGaugeVec::new(
Opts::new("system_length_time", "time in ns required per ECS system"),
&["system"],
)?;
let system_thread_avg = GaugeVec::new(
Opts::new(
"system_thread_avg",
"average threads used by the ECS system",
),
&["system"],
)?;
let since_the_epoch = SystemTime::now() let since_the_epoch = SystemTime::now()
.duration_since(UNIX_EPOCH) .duration_since(UNIX_EPOCH)
@ -306,6 +327,9 @@ impl TickMetrics {
let light_count_clone = light_count.clone(); let light_count_clone = light_count.clone();
let tick_time_clone = tick_time.clone(); let tick_time_clone = tick_time.clone();
let tick = Arc::new(AtomicU64::new(0)); let tick = Arc::new(AtomicU64::new(0));
let system_start_time_clone = system_start_time.clone();
let system_length_time_clone = system_length_time.clone();
let system_thread_avg_clone = system_thread_avg.clone();
let f = |registry: &Registry| { let f = |registry: &Registry| {
registry.register(Box::new(chonks_count_clone))?; registry.register(Box::new(chonks_count_clone))?;
@ -317,6 +341,9 @@ impl TickMetrics {
registry.register(Box::new(time_of_day_clone))?; registry.register(Box::new(time_of_day_clone))?;
registry.register(Box::new(light_count_clone))?; registry.register(Box::new(light_count_clone))?;
registry.register(Box::new(tick_time_clone))?; registry.register(Box::new(tick_time_clone))?;
registry.register(Box::new(system_start_time_clone))?;
registry.register(Box::new(system_length_time_clone))?;
registry.register(Box::new(system_thread_avg_clone))?;
Ok(()) Ok(())
}; };
@ -331,6 +358,9 @@ impl TickMetrics {
start_time, start_time,
time_of_day, time_of_day,
light_count, light_count,
system_start_time,
system_length_time,
system_thread_avg,
tick, tick,
}, },
Box::new(f), Box::new(f),

View File

@ -1,13 +1,21 @@
use super::*; use super::*;
use common::event::{EventBus, ServerEvent}; use common::{
use specs::{Read, System, WriteExpect}; event::{EventBus, ServerEvent},
vsystem::{Origin, Phase, VJob, VSystem},
};
use specs::{Read, WriteExpect};
#[derive(Default)]
pub struct Sys; pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> VSystem<'a> for Sys {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
type SystemData = (Read<'a, EventBus<ServerEvent>>, WriteExpect<'a, RtSim>); type SystemData = (Read<'a, EventBus<ServerEvent>>, WriteExpect<'a, RtSim>);
fn run(&mut self, (_server_event_bus, mut rtsim): Self::SystemData) { const NAME: &'static str = "rtsim::load_chunks";
const ORIGIN: Origin = Origin::Server;
const PHASE: Phase = Phase::Create;
fn run(_job: &mut VJob<Self>, (_server_event_bus, mut rtsim): Self::SystemData) {
for _chunk in std::mem::take(&mut rtsim.chunks.chunks_to_load) { for _chunk in std::mem::take(&mut rtsim.chunks.chunks_to_load) {
// TODO // TODO
} }

View File

@ -12,6 +12,7 @@ use common::{
rtsim::{RtSimController, RtSimEntity, RtSimId}, rtsim::{RtSimController, RtSimEntity, RtSimId},
terrain::TerrainChunk, terrain::TerrainChunk,
vol::RectRasterableVol, vol::RectRasterableVol,
vsystem::{dispatch, VSystem},
}; };
use common_sys::state::State; use common_sys::state::State;
use rand::prelude::*; use rand::prelude::*;
@ -72,14 +73,13 @@ impl RtSim {
} }
} }
const LOAD_CHUNK_SYS: &str = "rtsim_load_chunk_sys";
const UNLOAD_CHUNK_SYS: &str = "rtsim_unload_chunk_sys";
const TICK_SYS: &str = "rtsim_tick_sys";
pub fn add_server_systems(dispatch_builder: &mut DispatcherBuilder) { pub fn add_server_systems(dispatch_builder: &mut DispatcherBuilder) {
dispatch_builder.add(unload_chunks::Sys, UNLOAD_CHUNK_SYS, &[]); dispatch::<unload_chunks::Sys>(dispatch_builder, &[]);
dispatch_builder.add(load_chunks::Sys, LOAD_CHUNK_SYS, &[UNLOAD_CHUNK_SYS]); dispatch::<load_chunks::Sys>(dispatch_builder, &[&unload_chunks::Sys::sys_name()]);
dispatch_builder.add(tick::Sys, TICK_SYS, &[LOAD_CHUNK_SYS, UNLOAD_CHUNK_SYS]); dispatch::<tick::Sys>(dispatch_builder, &[
&load_chunks::Sys::sys_name(),
&unload_chunks::Sys::sys_name(),
]);
} }
pub fn init(state: &mut State, #[cfg(feature = "worldgen")] world: &world::World) { pub fn init(state: &mut State, #[cfg(feature = "worldgen")] world: &world::World) {

View File

@ -7,14 +7,16 @@ use common::{
event::{EventBus, ServerEvent}, event::{EventBus, ServerEvent},
resources::DeltaTime, resources::DeltaTime,
terrain::TerrainGrid, terrain::TerrainGrid,
vsystem::{Origin, Phase, VJob, VSystem},
}; };
use specs::{Join, Read, ReadExpect, ReadStorage, System, WriteExpect, WriteStorage}; use specs::{Join, Read, ReadExpect, ReadStorage, WriteExpect, WriteStorage};
use std::sync::Arc; use std::sync::Arc;
const ENTITY_TICK_PERIOD: u64 = 30; const ENTITY_TICK_PERIOD: u64 = 30;
#[derive(Default)]
pub struct Sys; pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> VSystem<'a> for Sys {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
type SystemData = ( type SystemData = (
Read<'a, DeltaTime>, Read<'a, DeltaTime>,
@ -28,8 +30,12 @@ impl<'a> System<'a> for Sys {
WriteStorage<'a, comp::Agent>, WriteStorage<'a, comp::Agent>,
); );
const NAME: &'static str = "rtsim::tick";
const ORIGIN: Origin = Origin::Server;
const PHASE: Phase = Phase::Create;
fn run( fn run(
&mut self, _job: &mut VJob<Self>,
( (
dt, dt,
server_event_bus, server_event_bus,

View File

@ -3,11 +3,13 @@ use common::{
comp::Pos, comp::Pos,
event::{EventBus, ServerEvent}, event::{EventBus, ServerEvent},
terrain::TerrainGrid, terrain::TerrainGrid,
vsystem::{Origin, Phase, VJob, VSystem},
}; };
use specs::{Entities, Read, ReadExpect, ReadStorage, System, WriteExpect}; use specs::{Entities, Read, ReadExpect, ReadStorage, WriteExpect};
#[derive(Default)]
pub struct Sys; pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> VSystem<'a> for Sys {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
type SystemData = ( type SystemData = (
Read<'a, EventBus<ServerEvent>>, Read<'a, EventBus<ServerEvent>>,
@ -18,8 +20,12 @@ impl<'a> System<'a> for Sys {
ReadStorage<'a, Pos>, ReadStorage<'a, Pos>,
); );
const NAME: &'static str = "rtsim::unload_chunks";
const ORIGIN: Origin = Origin::Server;
const PHASE: Phase = Phase::Create;
fn run( fn run(
&mut self, _job: &mut VJob<Self>,
( (
_server_event_bus, _server_event_bus,
mut rtsim, mut rtsim,

View File

@ -19,20 +19,20 @@ use common::{
metrics::SysMetrics, metrics::SysMetrics,
path::TraversalConfig, path::TraversalConfig,
resources::{DeltaTime, TimeOfDay}, resources::{DeltaTime, TimeOfDay},
span,
terrain::{Block, TerrainGrid}, terrain::{Block, TerrainGrid},
time::DayPeriod, time::DayPeriod,
uid::{Uid, UidAllocator}, uid::{Uid, UidAllocator},
util::Dir, util::Dir,
vol::ReadVol, vol::ReadVol,
vsystem::{Origin, Phase, VJob, VSystem},
}; };
use rand::{thread_rng, Rng}; use rand::{thread_rng, Rng};
use rayon::iter::ParallelIterator; use rayon::iter::ParallelIterator;
use specs::{ use specs::{
saveload::{Marker, MarkerAllocator}, saveload::{Marker, MarkerAllocator},
shred::ResourceId, shred::ResourceId,
Entities, Entity as EcsEntity, Join, ParJoin, Read, ReadExpect, ReadStorage, System, Entities, Entity as EcsEntity, Join, ParJoin, Read, ReadExpect, ReadStorage, SystemData, World,
SystemData, World, Write, WriteStorage, Write, WriteStorage,
}; };
use std::f32::consts::PI; use std::f32::consts::PI;
use vek::*; use vek::*;
@ -99,8 +99,9 @@ const SNEAK_COEFFICIENT: f32 = 0.25;
const AVG_FOLLOW_DIST: f32 = 6.0; const AVG_FOLLOW_DIST: f32 = 6.0;
/// This system will allow NPCs to modify their controller /// This system will allow NPCs to modify their controller
#[derive(Default)]
pub struct Sys; pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> VSystem<'a> for Sys {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
type SystemData = ( type SystemData = (
ReadData<'a>, ReadData<'a>,
@ -110,13 +111,16 @@ impl<'a> System<'a> for Sys {
WriteStorage<'a, Controller>, WriteStorage<'a, Controller>,
); );
const NAME: &'static str = "agent";
const ORIGIN: Origin = Origin::Server;
const PHASE: Phase = Phase::Create;
#[allow(clippy::or_fun_call)] // TODO: Pending review in #587 #[allow(clippy::or_fun_call)] // TODO: Pending review in #587
fn run( fn run(
&mut self, _job: &mut VJob<Self>,
(read_data, mut sys_timer, event_bus, mut agents, mut controllers): Self::SystemData, (read_data, mut sys_timer, event_bus, mut agents, mut controllers): Self::SystemData,
) { ) {
let start_time = std::time::Instant::now(); let start_time = std::time::Instant::now();
span!(_guard, "run", "agent::Sys::run");
sys_timer.start(); sys_timer.start();
( (

View File

@ -12,20 +12,21 @@ use common::{
outcome::Outcome, outcome::Outcome,
region::{Event as RegionEvent, RegionMap}, region::{Event as RegionEvent, RegionMap},
resources::TimeOfDay, resources::TimeOfDay,
span,
terrain::TerrainChunkSize, terrain::TerrainChunkSize,
uid::Uid, uid::Uid,
vol::RectVolSize, vol::RectVolSize,
vsystem::{Origin, Phase, VJob, VSystem},
}; };
use common_net::{msg::ServerGeneral, sync::CompSyncPackage}; use common_net::{msg::ServerGeneral, sync::CompSyncPackage};
use specs::{ use specs::{
Entities, Entity as EcsEntity, Join, Read, ReadExpect, ReadStorage, System, Write, WriteStorage, Entities, Entity as EcsEntity, Join, Read, ReadExpect, ReadStorage, Write, WriteStorage,
}; };
use vek::*; use vek::*;
/// This system will send physics updates to the client /// This system will send physics updates to the client
#[derive(Default)]
pub struct Sys; pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> VSystem<'a> for Sys {
#[allow(clippy::type_complexity)] // TODO: Pending review in #587 #[allow(clippy::type_complexity)] // TODO: Pending review in #587
type SystemData = ( type SystemData = (
Entities<'a>, Entities<'a>,
@ -52,8 +53,12 @@ impl<'a> System<'a> for Sys {
ReadTrackers<'a>, ReadTrackers<'a>,
); );
const NAME: &'static str = "entity_sync";
const ORIGIN: Origin = Origin::Server;
const PHASE: Phase = Phase::Create;
fn run( fn run(
&mut self, _job: &mut VJob<Self>,
( (
entities, entities,
tick, tick,
@ -79,7 +84,6 @@ impl<'a> System<'a> for Sys {
trackers, trackers,
): Self::SystemData, ): Self::SystemData,
) { ) {
span!(_guard, "run", "entity_sync::Sys::run");
timer.start(); timer.start();
let tick = tick.0; let tick = tick.0;

View File

@ -2,15 +2,16 @@ use super::SysTimer;
use crate::client::Client; use crate::client::Client;
use common::{ use common::{
comp::invite::{Invite, PendingInvites}, comp::invite::{Invite, PendingInvites},
span,
uid::Uid, uid::Uid,
vsystem::{Origin, Phase, VJob, VSystem},
}; };
use common_net::msg::{InviteAnswer, ServerGeneral}; use common_net::msg::{InviteAnswer, ServerGeneral};
use specs::{Entities, Join, ReadStorage, System, Write, WriteStorage}; use specs::{Entities, Join, ReadStorage, Write, WriteStorage};
/// This system removes timed out invites /// This system removes timed out invites
#[derive(Default)]
pub struct Sys; pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> VSystem<'a> for Sys {
#[allow(clippy::type_complexity)] // TODO: Pending review in #587 #[allow(clippy::type_complexity)] // TODO: Pending review in #587
type SystemData = ( type SystemData = (
Entities<'a>, Entities<'a>,
@ -21,11 +22,14 @@ impl<'a> System<'a> for Sys {
Write<'a, SysTimer<Self>>, Write<'a, SysTimer<Self>>,
); );
const NAME: &'static str = "invite_timeout";
const ORIGIN: Origin = Origin::Server;
const PHASE: Phase = Phase::Create;
fn run( fn run(
&mut self, _job: &mut VJob<Self>,
(entities, mut invites, mut pending_invites, clients, uids, mut timer): Self::SystemData, (entities, mut invites, mut pending_invites, clients, uids, mut timer): Self::SystemData,
) { ) {
span!(_guard, "run", "invite_timeout::Sys::run");
timer.start(); timer.start();
let now = std::time::Instant::now(); let now = std::time::Instant::now();

View File

@ -10,6 +10,7 @@ pub mod terrain;
pub mod terrain_sync; pub mod terrain_sync;
pub mod waypoint; pub mod waypoint;
use common::vsystem::{dispatch, run_now};
use specs::DispatcherBuilder; use specs::DispatcherBuilder;
use std::{ use std::{
marker::PhantomData, marker::PhantomData,
@ -31,38 +32,23 @@ pub type PersistenceTimer = SysTimer<persistence::Sys>;
pub type PersistenceScheduler = SysScheduler<persistence::Sys>; pub type PersistenceScheduler = SysScheduler<persistence::Sys>;
pub type AgentTimer = SysTimer<agent::Sys>; pub type AgentTimer = SysTimer<agent::Sys>;
// System names
// Note: commented names may be useful in the future
//const ENTITY_SYNC_SYS: &str = "server_entity_sync_sys";
//const SENTINEL_SYS: &str = "sentinel_sys";
//const SUBSCRIPTION_SYS: &str = "server_subscription_sys";
//const TERRAIN_SYNC_SYS: &str = "server_terrain_sync_sys";
const TERRAIN_SYS: &str = "server_terrain_sys";
const WAYPOINT_SYS: &str = "server_waypoint_sys";
const INVITE_TIMEOUT_SYS: &str = "server_invite_timeout_sys";
const PERSISTENCE_SYS: &str = "server_persistence_sys";
const OBJECT_SYS: &str = "server_object_sys";
pub const AGENT_SYS: &str = "agent_sys";
pub fn add_server_systems(dispatch_builder: &mut DispatcherBuilder) { pub fn add_server_systems(dispatch_builder: &mut DispatcherBuilder) {
dispatch_builder.add(terrain::Sys, TERRAIN_SYS, &[]); dispatch::<terrain::Sys>(dispatch_builder, &[]);
dispatch_builder.add(waypoint::Sys, WAYPOINT_SYS, &[]); dispatch::<waypoint::Sys>(dispatch_builder, &[]);
dispatch_builder.add(invite_timeout::Sys, INVITE_TIMEOUT_SYS, &[]); dispatch::<invite_timeout::Sys>(dispatch_builder, &[]);
dispatch_builder.add(persistence::Sys, PERSISTENCE_SYS, &[]); dispatch::<persistence::Sys>(dispatch_builder, &[]);
dispatch_builder.add(object::Sys, OBJECT_SYS, &[]); dispatch::<object::Sys>(dispatch_builder, &[]);
} }
pub fn run_sync_systems(ecs: &mut specs::World) { pub fn run_sync_systems(ecs: &mut specs::World) {
use specs::RunNow;
// Setup for entity sync // Setup for entity sync
// If I'm not mistaken, these two could be ran in parallel // If I'm not mistaken, these two could be ran in parallel
sentinel::Sys.run_now(ecs); run_now::<sentinel::Sys>(ecs);
subscription::Sys.run_now(ecs); run_now::<subscription::Sys>(ecs);
// Sync // Sync
terrain_sync::Sys.run_now(ecs); run_now::<terrain_sync::Sys>(ecs);
entity_sync::Sys.run_now(ecs); run_now::<entity_sync::Sys>(ecs);
} }
/// Used to schedule systems to run at an interval /// Used to schedule systems to run at an interval

View File

@ -6,11 +6,11 @@ use crate::{
use common::{ use common::{
comp::{ChatType, Player, UnresolvedChatMsg}, comp::{ChatType, Player, UnresolvedChatMsg},
event::{EventBus, ServerEvent}, event::{EventBus, ServerEvent},
span,
uid::Uid, uid::Uid,
vsystem::{Origin, Phase, VJob, VSystem},
}; };
use common_net::msg::{ClientGeneral, ServerGeneral}; use common_net::msg::{ClientGeneral, ServerGeneral};
use specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, Write}; use specs::{Entities, Join, Read, ReadExpect, ReadStorage, Write};
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use tracing::{debug, warn}; use tracing::{debug, warn};
@ -121,8 +121,9 @@ impl Sys {
} }
/// This system will handle new messages from clients /// This system will handle new messages from clients
#[derive(Default)]
pub struct Sys; pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> VSystem<'a> for Sys {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
type SystemData = ( type SystemData = (
Entities<'a>, Entities<'a>,
@ -137,8 +138,12 @@ impl<'a> System<'a> for Sys {
ReadExpect<'a, AliasValidator>, ReadExpect<'a, AliasValidator>,
); );
const NAME: &'static str = "msg::character_screen";
const ORIGIN: Origin = Origin::Server;
const PHASE: Phase = Phase::Create;
fn run( fn run(
&mut self, _job: &mut VJob<Self>,
( (
entities, entities,
server_event_bus, server_event_bus,
@ -152,7 +157,6 @@ impl<'a> System<'a> for Sys {
alias_validator, alias_validator,
): Self::SystemData, ): Self::SystemData,
) { ) {
span!(_guard, "run", "msg::character_screen::Sys::run");
timer.start(); timer.start();
let mut server_emitter = server_event_bus.emitter(); let mut server_emitter = server_event_bus.emitter();

View File

@ -4,13 +4,13 @@ use common::{
comp::{ChatMode, Player, UnresolvedChatMsg}, comp::{ChatMode, Player, UnresolvedChatMsg},
event::{EventBus, ServerEvent}, event::{EventBus, ServerEvent},
resources::Time, resources::Time,
span,
uid::Uid, uid::Uid,
vsystem::{Origin, Phase, VJob, VSystem},
}; };
use common_net::msg::{ use common_net::msg::{
validate_chat_msg, ChatMsgValidationError, ClientGeneral, MAX_BYTES_CHAT_MSG, validate_chat_msg, ChatMsgValidationError, ClientGeneral, MAX_BYTES_CHAT_MSG,
}; };
use specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, Write}; use specs::{Entities, Join, Read, ReadExpect, ReadStorage, Write};
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use tracing::{debug, error, warn}; use tracing::{debug, error, warn};
@ -65,8 +65,9 @@ impl Sys {
} }
/// This system will handle new messages from clients /// This system will handle new messages from clients
#[derive(Default)]
pub struct Sys; pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> VSystem<'a> for Sys {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
type SystemData = ( type SystemData = (
Entities<'a>, Entities<'a>,
@ -80,8 +81,12 @@ impl<'a> System<'a> for Sys {
ReadStorage<'a, Client>, ReadStorage<'a, Client>,
); );
const NAME: &'static str = "msg::general";
const ORIGIN: Origin = Origin::Server;
const PHASE: Phase = Phase::Create;
fn run( fn run(
&mut self, _job: &mut VJob<Self>,
( (
entities, entities,
server_event_bus, server_event_bus,
@ -94,7 +99,6 @@ impl<'a> System<'a> for Sys {
clients, clients,
): Self::SystemData, ): Self::SystemData,
) { ) {
span!(_guard, "run", "msg::general::Sys::run");
timer.start(); timer.start();
let mut server_emitter = server_event_bus.emitter(); let mut server_emitter = server_event_bus.emitter();

View File

@ -3,13 +3,13 @@ use crate::{client::Client, metrics::NetworkRequestMetrics, presence::Presence,
use common::{ use common::{
comp::{CanBuild, ControlEvent, Controller, ForceUpdate, Health, Ori, Pos, Stats, Vel}, comp::{CanBuild, ControlEvent, Controller, ForceUpdate, Health, Ori, Pos, Stats, Vel},
event::{EventBus, ServerEvent}, event::{EventBus, ServerEvent},
span,
terrain::{TerrainChunkSize, TerrainGrid}, terrain::{TerrainChunkSize, TerrainGrid},
vol::{ReadVol, RectVolSize}, vol::{ReadVol, RectVolSize},
vsystem::{Origin, Phase, VJob, VSystem},
}; };
use common_net::msg::{ClientGeneral, PresenceKind, ServerGeneral}; use common_net::msg::{ClientGeneral, PresenceKind, ServerGeneral};
use common_sys::state::BlockChange; use common_sys::state::BlockChange;
use specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, Write, WriteStorage}; use specs::{Entities, Join, Read, ReadExpect, ReadStorage, Write, WriteStorage};
use tracing::{debug, trace}; use tracing::{debug, trace};
impl Sys { impl Sys {
@ -165,8 +165,9 @@ impl Sys {
} }
/// This system will handle new messages from clients /// This system will handle new messages from clients
#[derive(Default)]
pub struct Sys; pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> VSystem<'a> for Sys {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
type SystemData = ( type SystemData = (
Entities<'a>, Entities<'a>,
@ -188,8 +189,12 @@ impl<'a> System<'a> for Sys {
Read<'a, Settings>, Read<'a, Settings>,
); );
const NAME: &'static str = "msg::in_game";
const ORIGIN: Origin = Origin::Server;
const PHASE: Phase = Phase::Create;
fn run( fn run(
&mut self, _job: &mut VJob<Self>,
( (
entities, entities,
server_event_bus, server_event_bus,
@ -210,7 +215,6 @@ impl<'a> System<'a> for Sys {
settings, settings,
): Self::SystemData, ): Self::SystemData,
) { ) {
span!(_guard, "run", "msg::in_game::Sys::run");
timer.start(); timer.start();
let mut server_emitter = server_event_bus.emitter(); let mut server_emitter = server_event_bus.emitter();

View File

@ -3,10 +3,10 @@ use crate::{client::Client, metrics::PlayerMetrics, Settings};
use common::{ use common::{
event::{EventBus, ServerEvent}, event::{EventBus, ServerEvent},
resources::Time, resources::Time,
span, vsystem::{Origin, Phase, VJob, VSystem},
}; };
use common_net::msg::PingMsg; use common_net::msg::PingMsg;
use specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, Write}; use specs::{Entities, Join, Read, ReadExpect, ReadStorage, Write};
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use tracing::{debug, info}; use tracing::{debug, info};
@ -21,8 +21,9 @@ impl Sys {
} }
/// This system will handle new messages from clients /// This system will handle new messages from clients
#[derive(Default)]
pub struct Sys; pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> VSystem<'a> for Sys {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
type SystemData = ( type SystemData = (
Entities<'a>, Entities<'a>,
@ -34,8 +35,12 @@ impl<'a> System<'a> for Sys {
Read<'a, Settings>, Read<'a, Settings>,
); );
const NAME: &'static str = "msg::ping";
const ORIGIN: Origin = Origin::Server;
const PHASE: Phase = Phase::Create;
fn run( fn run(
&mut self, _job: &mut VJob<Self>,
( (
entities, entities,
server_event_bus, server_event_bus,
@ -46,7 +51,6 @@ impl<'a> System<'a> for Sys {
settings, settings,
): Self::SystemData, ): Self::SystemData,
) { ) {
span!(_guard, "run", "msg::ping::Sys::run");
timer.start(); timer.start();
let mut server_emitter = server_event_bus.emitter(); let mut server_emitter = server_event_bus.emitter();

View File

@ -3,13 +3,15 @@ use common::{
effect::Effect, effect::Effect,
event::{EventBus, ServerEvent}, event::{EventBus, ServerEvent},
resources::DeltaTime, resources::DeltaTime,
span, Damage, DamageSource, Explosion, RadiusEffect, vsystem::{Origin, Phase, VJob, VSystem},
Damage, DamageSource, Explosion, RadiusEffect,
}; };
use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage}; use specs::{Entities, Join, Read, ReadStorage, WriteStorage};
/// This system is responsible for handling misc object behaviours /// This system is responsible for handling misc object behaviours
#[derive(Default)]
pub struct Sys; pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> VSystem<'a> for Sys {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
type SystemData = ( type SystemData = (
Entities<'a>, Entities<'a>,
@ -21,11 +23,14 @@ impl<'a> System<'a> for Sys {
WriteStorage<'a, Object>, WriteStorage<'a, Object>,
); );
const NAME: &'static str = "object";
const ORIGIN: Origin = Origin::Server;
const PHASE: Phase = Phase::Create;
fn run( fn run(
&mut self, _job: &mut VJob<Self>,
(entities, _dt, server_bus, positions, velocities, physics_states, mut objects): Self::SystemData, (entities, _dt, server_bus, positions, velocities, physics_states, mut objects): Self::SystemData,
) { ) {
span!(_guard, "run", "object::Sys::run");
let mut server_emitter = server_bus.emitter(); let mut server_emitter = server_bus.emitter();
// Objects // Objects

View File

@ -5,14 +5,15 @@ use crate::{
}; };
use common::{ use common::{
comp::{Inventory, Stats, Waypoint}, comp::{Inventory, Stats, Waypoint},
span, vsystem::{Origin, Phase, VJob, VSystem},
}; };
use common_net::msg::PresenceKind; use common_net::msg::PresenceKind;
use specs::{Join, ReadExpect, ReadStorage, System, Write}; use specs::{Join, ReadExpect, ReadStorage, Write};
#[derive(Default)]
pub struct Sys; pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> VSystem<'a> for Sys {
#[allow(clippy::type_complexity)] // TODO: Pending review in #587 #[allow(clippy::type_complexity)] // TODO: Pending review in #587
type SystemData = ( type SystemData = (
ReadStorage<'a, Presence>, ReadStorage<'a, Presence>,
@ -24,8 +25,12 @@ impl<'a> System<'a> for Sys {
Write<'a, SysTimer<Self>>, Write<'a, SysTimer<Self>>,
); );
const NAME: &'static str = "persistence";
const ORIGIN: Origin = Origin::Server;
const PHASE: Phase = Phase::Create;
fn run( fn run(
&mut self, _job: &mut VJob<Self>,
( (
presences, presences,
player_stats, player_stats,
@ -36,7 +41,6 @@ impl<'a> System<'a> for Sys {
mut timer, mut timer,
): Self::SystemData, ): Self::SystemData,
) { ) {
span!(_guard, "run", "persistence::Sys::run");
if scheduler.should_run() { if scheduler.should_run() {
timer.start(); timer.start();
updater.batch_update( updater.batch_update(

View File

@ -5,8 +5,8 @@ use common::{
Gravity, Group, Health, Inventory, Item, LightEmitter, Mass, MountState, Mounting, Ori, Gravity, Group, Health, Inventory, Item, LightEmitter, Mass, MountState, Mounting, Ori,
Player, Poise, Pos, Scale, Shockwave, Stats, Sticky, Vel, Player, Poise, Pos, Scale, Shockwave, Stats, Sticky, Vel,
}, },
span,
uid::Uid, uid::Uid,
vsystem::{Origin, Phase, VJob, VSystem},
}; };
use common_net::{ use common_net::{
msg::EcsCompPacket, msg::EcsCompPacket,
@ -14,24 +14,28 @@ use common_net::{
}; };
use hashbrown::HashMap; use hashbrown::HashMap;
use specs::{ use specs::{
shred::ResourceId, Entity as EcsEntity, Join, ReadExpect, ReadStorage, System, SystemData, shred::ResourceId, Entity as EcsEntity, Join, ReadExpect, ReadStorage, SystemData, World,
World, Write, WriteExpect, Write, WriteExpect,
}; };
use vek::*; use vek::*;
/// Always watching /// Always watching
/// This system will monitor specific components for insertion, removal, and /// This system will monitor specific components for insertion, removal, and
/// modification /// modification
#[derive(Default)]
pub struct Sys; pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> VSystem<'a> for Sys {
type SystemData = ( type SystemData = (
Write<'a, SysTimer<Self>>, Write<'a, SysTimer<Self>>,
TrackedComps<'a>, TrackedComps<'a>,
WriteTrackers<'a>, WriteTrackers<'a>,
); );
fn run(&mut self, (mut timer, comps, mut trackers): Self::SystemData) { const NAME: &'static str = "sentinel";
span!(_guard, "run", "sentinel::Sys::run"); const ORIGIN: Origin = Origin::Server;
const PHASE: Phase = Phase::Create;
fn run(_job: &mut VJob<Self>, (mut timer, comps, mut trackers): Self::SystemData) {
timer.start(); timer.start();
record_changes(&comps, &mut trackers); record_changes(&comps, &mut trackers);

View File

@ -9,22 +9,22 @@ use crate::{
use common::{ use common::{
comp::{Ori, Pos, Vel}, comp::{Ori, Pos, Vel},
region::{region_in_vd, regions_in_vd, Event as RegionEvent, RegionMap}, region::{region_in_vd, regions_in_vd, Event as RegionEvent, RegionMap},
span,
terrain::TerrainChunkSize, terrain::TerrainChunkSize,
uid::Uid, uid::Uid,
vol::RectVolSize, vol::RectVolSize,
vsystem::{Origin, Phase, VJob, VSystem},
}; };
use common_net::msg::ServerGeneral; use common_net::msg::ServerGeneral;
use specs::{ use specs::{
Entities, Join, ReadExpect, ReadStorage, System, SystemData, World, WorldExt, Write, Entities, Join, ReadExpect, ReadStorage, SystemData, World, WorldExt, Write, WriteStorage,
WriteStorage,
}; };
use tracing::{debug, error}; use tracing::{debug, error};
use vek::*; use vek::*;
/// This system will update region subscriptions based on client positions /// This system will update region subscriptions based on client positions
#[derive(Default)]
pub struct Sys; pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> VSystem<'a> for Sys {
#[allow(clippy::type_complexity)] // TODO: Pending review in #587 #[allow(clippy::type_complexity)] // TODO: Pending review in #587
type SystemData = ( type SystemData = (
Entities<'a>, Entities<'a>,
@ -41,9 +41,13 @@ impl<'a> System<'a> for Sys {
TrackedComps<'a>, TrackedComps<'a>,
); );
const NAME: &'static str = "subscription";
const ORIGIN: Origin = Origin::Server;
const PHASE: Phase = Phase::Create;
#[allow(clippy::blocks_in_if_conditions)] // TODO: Pending review in #587 #[allow(clippy::blocks_in_if_conditions)] // TODO: Pending review in #587
fn run( fn run(
&mut self, _job: &mut VJob<Self>,
( (
entities, entities,
region_map, region_map,
@ -59,7 +63,6 @@ impl<'a> System<'a> for Sys {
tracked_comps, tracked_comps,
): Self::SystemData, ): Self::SystemData,
) { ) {
span!(_guard, "run", "subscription::Sys::run");
timer.start(); timer.start();
// To update subscriptions // To update subscriptions

View File

@ -7,13 +7,13 @@ use common::{
event::{EventBus, ServerEvent}, event::{EventBus, ServerEvent},
generation::get_npc_name, generation::get_npc_name,
npc::NPC_NAMES, npc::NPC_NAMES,
span,
terrain::TerrainGrid, terrain::TerrainGrid,
vsystem::{Origin, Phase, VJob, VSystem},
LoadoutBuilder, SkillSetBuilder, LoadoutBuilder, SkillSetBuilder,
}; };
use common_net::msg::ServerGeneral; use common_net::msg::ServerGeneral;
use common_sys::state::TerrainChanges; use common_sys::state::TerrainChanges;
use specs::{Join, Read, ReadStorage, System, Write, WriteExpect}; use specs::{Join, Read, ReadStorage, Write, WriteExpect};
use std::sync::Arc; use std::sync::Arc;
use vek::*; use vek::*;
@ -23,8 +23,9 @@ use vek::*;
/// 2. Sends new chunks to nearby clients /// 2. Sends new chunks to nearby clients
/// 3. Handles the chunk's supplement (e.g. npcs) /// 3. Handles the chunk's supplement (e.g. npcs)
/// 4. Removes chunks outside the range of players /// 4. Removes chunks outside the range of players
#[derive(Default)]
pub struct Sys; pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> VSystem<'a> for Sys {
#[allow(clippy::type_complexity)] // TODO: Pending review in #587 #[allow(clippy::type_complexity)] // TODO: Pending review in #587
type SystemData = ( type SystemData = (
Read<'a, EventBus<ServerEvent>>, Read<'a, EventBus<ServerEvent>>,
@ -39,8 +40,12 @@ impl<'a> System<'a> for Sys {
ReadStorage<'a, Client>, ReadStorage<'a, Client>,
); );
const NAME: &'static str = "terrain";
const ORIGIN: Origin = Origin::Server;
const PHASE: Phase = Phase::Create;
fn run( fn run(
&mut self, _job: &mut VJob<Self>,
( (
server_event_bus, server_event_bus,
tick, tick,
@ -54,7 +59,6 @@ impl<'a> System<'a> for Sys {
clients, clients,
): Self::SystemData, ): Self::SystemData,
) { ) {
span!(_guard, "run", "terrain::Sys::run");
timer.start(); timer.start();
let mut server_emitter = server_event_bus.emitter(); let mut server_emitter = server_event_bus.emitter();

View File

@ -1,14 +1,19 @@
use super::SysTimer; use super::SysTimer;
use crate::{client::Client, presence::Presence}; use crate::{client::Client, presence::Presence};
use common::{comp::Pos, span, terrain::TerrainGrid}; use common::{
comp::Pos,
terrain::TerrainGrid,
vsystem::{Origin, Phase, VJob, VSystem},
};
use common_net::msg::ServerGeneral; use common_net::msg::ServerGeneral;
use common_sys::state::TerrainChanges; use common_sys::state::TerrainChanges;
use specs::{Join, Read, ReadExpect, ReadStorage, System, Write}; use specs::{Join, Read, ReadExpect, ReadStorage, Write};
/// This systems sends new chunks to clients as well as changes to existing /// This systems sends new chunks to clients as well as changes to existing
/// chunks /// chunks
#[derive(Default)]
pub struct Sys; pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> VSystem<'a> for Sys {
#[allow(clippy::type_complexity)] // TODO: Pending review in #587 #[allow(clippy::type_complexity)] // TODO: Pending review in #587
type SystemData = ( type SystemData = (
ReadExpect<'a, TerrainGrid>, ReadExpect<'a, TerrainGrid>,
@ -19,11 +24,14 @@ impl<'a> System<'a> for Sys {
ReadStorage<'a, Client>, ReadStorage<'a, Client>,
); );
const NAME: &'static str = "terrain_sync";
const ORIGIN: Origin = Origin::Server;
const PHASE: Phase = Phase::Create;
fn run( fn run(
&mut self, _job: &mut VJob<Self>,
(terrain, terrain_changes, mut timer, positions, presences, clients): Self::SystemData, (terrain, terrain_changes, mut timer, positions, presences, clients): Self::SystemData,
) { ) {
span!(_guard, "run", "terrain_sync::Sys::run");
timer.start(); timer.start();
// Sync changed chunks // Sync changed chunks

View File

@ -3,18 +3,19 @@ use crate::client::Client;
use common::{ use common::{
comp::{Player, Pos, Waypoint, WaypointArea}, comp::{Player, Pos, Waypoint, WaypointArea},
resources::Time, resources::Time,
span, vsystem::{Origin, Phase, VJob, VSystem},
}; };
use common_net::msg::{Notification, ServerGeneral}; use common_net::msg::{Notification, ServerGeneral};
use specs::{Entities, Join, Read, ReadStorage, System, Write, WriteStorage}; use specs::{Entities, Join, Read, ReadStorage, Write, WriteStorage};
/// Cooldown time (in seconds) for "Waypoint Saved" notifications /// Cooldown time (in seconds) for "Waypoint Saved" notifications
const NOTIFY_TIME: f64 = 10.0; const NOTIFY_TIME: f64 = 10.0;
/// This system updates player waypoints /// This system updates player waypoints
/// TODO: Make this faster by only considering local waypoints /// TODO: Make this faster by only considering local waypoints
#[derive(Default)]
pub struct Sys; pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> VSystem<'a> for Sys {
#[allow(clippy::type_complexity)] // TODO: Pending review in #587 #[allow(clippy::type_complexity)] // TODO: Pending review in #587
type SystemData = ( type SystemData = (
Entities<'a>, Entities<'a>,
@ -27,8 +28,12 @@ impl<'a> System<'a> for Sys {
Write<'a, SysTimer<Self>>, Write<'a, SysTimer<Self>>,
); );
const NAME: &'static str = "waypoint";
const ORIGIN: Origin = Origin::Server;
const PHASE: Phase = Phase::Create;
fn run( fn run(
&mut self, _job: &mut VJob<Self>,
( (
entities, entities,
positions, positions,
@ -40,7 +45,6 @@ impl<'a> System<'a> for Sys {
mut timer, mut timer,
): Self::SystemData, ): Self::SystemData,
) { ) {
span!(_guard, "run", "waypoint::Sys::run");
timer.start(); timer.start();
for (entity, player_pos, _, client) in (&entities, &positions, &players, &clients).join() { for (entity, player_pos, _, client) in (&entities, &positions, &players, &clients).join() {

View File

@ -1,15 +1,10 @@
pub mod floater; pub mod floater;
mod interpolation; mod interpolation;
use common::vsystem::{dispatch, VSystem};
use specs::DispatcherBuilder; use specs::DispatcherBuilder;
// System names
const FLOATER_SYS: &str = "floater_voxygen_sys";
const INTERPOLATION_SYS: &str = "interpolation_voxygen_sys";
pub fn add_local_systems(dispatch_builder: &mut DispatcherBuilder) { pub fn add_local_systems(dispatch_builder: &mut DispatcherBuilder) {
dispatch_builder.add(interpolation::Sys, INTERPOLATION_SYS, &[ dispatch::<interpolation::Sys>(dispatch_builder, &[&common_sys::phys::Sys::sys_name()]);
common_sys::PHYS_SYS, dispatch::<floater::Sys>(dispatch_builder, &[&interpolation::Sys::sys_name()]);
]);
dispatch_builder.add(floater::Sys, FLOATER_SYS, &[INTERPOLATION_SYS]);
} }

View File

@ -6,16 +6,18 @@ use common::{
comp::{Health, HealthSource, Pos}, comp::{Health, HealthSource, Pos},
resources::DeltaTime, resources::DeltaTime,
uid::Uid, uid::Uid,
vsystem::{Origin, Phase, VJob, VSystem},
}; };
use specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, WriteStorage}; use specs::{Entities, Join, Read, ReadExpect, ReadStorage, WriteStorage};
// How long floaters last (in seconds) // How long floaters last (in seconds)
pub const HP_SHOWTIME: f32 = 3.0; pub const HP_SHOWTIME: f32 = 3.0;
pub const MY_HP_SHOWTIME: f32 = 2.5; pub const MY_HP_SHOWTIME: f32 = 2.5;
pub const HP_ACCUMULATETIME: f32 = 1.0; pub const HP_ACCUMULATETIME: f32 = 1.0;
#[derive(Default)]
pub struct Sys; pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> VSystem<'a> for Sys {
#[allow(clippy::type_complexity)] // TODO: Pending review in #587 #[allow(clippy::type_complexity)] // TODO: Pending review in #587
type SystemData = ( type SystemData = (
Entities<'a>, Entities<'a>,
@ -27,9 +29,13 @@ impl<'a> System<'a> for Sys {
WriteStorage<'a, HpFloaterList>, WriteStorage<'a, HpFloaterList>,
); );
const NAME: &'static str = "floater";
const ORIGIN: Origin = Origin::Frontend("voxygen");
const PHASE: Phase = Phase::Create;
#[allow(clippy::blocks_in_if_conditions)] // TODO: Pending review in #587 #[allow(clippy::blocks_in_if_conditions)] // TODO: Pending review in #587
fn run( fn run(
&mut self, _job: &mut VJob<Self>,
(entities, my_entity, dt, uids, pos, healths, mut hp_floater_lists): Self::SystemData, (entities, my_entity, dt, uids, pos, healths, mut hp_floater_lists): Self::SystemData,
) { ) {
// Add hp floater lists to all entities with health and a position // Add hp floater lists to all entities with health and a position

View File

@ -2,14 +2,16 @@ use crate::ecs::comp::Interpolated;
use common::{ use common::{
comp::{object, Body, Ori, Pos, Vel}, comp::{object, Body, Ori, Pos, Vel},
resources::DeltaTime, resources::DeltaTime,
vsystem::{Origin, Phase, VJob, VSystem},
}; };
use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage}; use specs::{Entities, Join, Read, ReadStorage, WriteStorage};
use tracing::warn; use tracing::warn;
use vek::*; use vek::*;
/// This system will allow NPCs to modify their controller /// This system will allow NPCs to modify their controller
#[derive(Default)]
pub struct Sys; pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> VSystem<'a> for Sys {
#[allow(clippy::type_complexity)] // TODO: Pending review in #587 #[allow(clippy::type_complexity)] // TODO: Pending review in #587
type SystemData = ( type SystemData = (
Entities<'a>, Entities<'a>,
@ -21,8 +23,12 @@ impl<'a> System<'a> for Sys {
WriteStorage<'a, Interpolated>, WriteStorage<'a, Interpolated>,
); );
const NAME: &'static str = "interpolation";
const ORIGIN: Origin = Origin::Frontend("voxygen");
const PHASE: Phase = Phase::Create;
fn run( fn run(
&mut self, _job: &mut VJob<Self>,
(entities, dt, positions, orientations, velocities, bodies, mut interpolated): Self::SystemData, (entities, dt, positions, orientations, velocities, bodies, mut interpolated): Self::SystemData,
) { ) {
// Update interpolated positions and orientations // Update interpolated positions and orientations