Integrate new systems with metrics

This commit is contained in:
Imbris 2019-10-20 03:20:21 -04:00 committed by Imbris
parent 8f81b69a25
commit 966b2bfbff
8 changed files with 142 additions and 14 deletions

View File

@ -94,6 +94,19 @@ impl Server {
state.ecs_mut().add_resource(AuthProvider::new());
state.ecs_mut().add_resource(Tick(0));
state.ecs_mut().add_resource(ChunkGenerator::new());
// System timers
state
.ecs_mut()
.add_resource(sys::EntitySyncTimer::default());
state.ecs_mut().add_resource(sys::MessageTimer::default());
state
.ecs_mut()
.add_resource(sys::SubscriptionTimer::default());
state
.ecs_mut()
.add_resource(sys::TerrainSyncTimer::default());
state.ecs_mut().add_resource(sys::TerrainTimer::default());
// Server-only components
state.ecs_mut().register::<RegionSubscription>();
state.ecs_mut().register::<Client>();
@ -761,8 +774,8 @@ impl Server {
// Tick the world
self.world.tick(dt);
let before_tick_5 = Instant::now();
// 5) Fetch any generated `TerrainChunk`s and insert them into the terrain.
// in sys/terrain.rs
let before_tick_6 = Instant::now();
// 6) Synchronise clients with the new state of the world.
@ -791,24 +804,61 @@ impl Server {
}
let before_tick_7 = Instant::now();
// TODO: Update metrics now that a lot of processing has been moved to ecs systems
// 7) Update Metrics
let entity_sync_nanos = self
.state
.ecs()
.read_resource::<sys::EntitySyncTimer>()
.nanos as i64;
let message_nanos = self.state.ecs().read_resource::<sys::MessageTimer>().nanos as i64;
let subscription_nanos = self
.state
.ecs()
.read_resource::<sys::SubscriptionTimer>()
.nanos as i64;
let terrain_sync_nanos = self
.state
.ecs()
.read_resource::<sys::TerrainSyncTimer>()
.nanos as i64;
let terrain_nanos = self.state.ecs().read_resource::<sys::TerrainTimer>().nanos as i64;
let total_sys_nanos = entity_sync_nanos
+ message_nanos
+ subscription_nanos
+ terrain_sync_nanos
+ terrain_nanos;
self.metrics
.tick_time
.with_label_values(&["input"])
.set((before_tick_4 - before_tick_1).as_nanos() as i64);
self.metrics
.tick_time
.with_label_values(&["world"])
.set((before_tick_5 - before_tick_4).as_nanos() as i64);
.with_label_values(&["state tick"])
.set((before_tick_6 - before_tick_4).as_nanos() as i64 - total_sys_nanos);
self.metrics
.tick_time
.with_label_values(&["sphynx sync"])
.set((before_tick_7 - before_tick_6).as_nanos() as i64);
self.metrics
.tick_time
.with_label_values(&["entity sync"])
.set(entity_sync_nanos);
self.metrics
.tick_time
.with_label_values(&["message"])
.set(message_nanos);
self.metrics
.tick_time
.with_label_values(&["subscription"])
.set(subscription_nanos);
self.metrics
.tick_time
.with_label_values(&["terrain sync"])
.set(terrain_sync_nanos);
self.metrics
.tick_time
.with_label_values(&["terrain"])
.set((before_tick_6 - before_tick_5).as_nanos() as i64);
self.metrics
.tick_time
.with_label_values(&["sync"])
.set((before_tick_7 - before_tick_6).as_nanos() as i64);
.set(terrain_nanos);
self.metrics
.player_online
.set(self.state.ecs().read_storage::<Client>().join().count() as i64);

View File

@ -1,3 +1,4 @@
use super::SysTimer;
use crate::{
client::{Client, RegionSubscription},
Tick,
@ -9,7 +10,7 @@ use common::{
state::Uid,
};
use specs::{
Entities, Entity as EcsEntity, Join, Read, ReadExpect, ReadStorage, System, WriteStorage,
Entities, Entity as EcsEntity, Join, Read, ReadExpect, ReadStorage, System, Write, WriteStorage,
};
/// This system will send physics updates to the client
@ -19,6 +20,7 @@ impl<'a> System<'a> for Sys {
Entities<'a>,
Read<'a, Tick>,
ReadExpect<'a, RegionMap>,
Write<'a, SysTimer<Self>>,
ReadStorage<'a, Uid>,
ReadStorage<'a, Pos>,
ReadStorage<'a, Vel>,
@ -41,6 +43,7 @@ impl<'a> System<'a> for Sys {
entities,
tick,
region_map,
mut timer,
uids,
positions,
velocities,
@ -57,6 +60,8 @@ impl<'a> System<'a> for Sys {
mut inventory_updates,
): Self::SystemData,
) {
timer.start();
let tick = tick.0;
// To send entity updates
// 1. Iterate through regions
@ -222,5 +227,7 @@ impl<'a> System<'a> for Sys {
// Remove all force flags.
force_updates.clear();
inventory_updates.clear();
timer.end();
}
}

View File

@ -1,3 +1,4 @@
use super::SysTimer;
use crate::{auth_provider::AuthProvider, client::Client, CLIENT_TIMEOUT};
use common::{
comp::{Admin, Body, CanBuild, Controller, Item, Ori, Player, Pos, Vel},
@ -20,6 +21,7 @@ impl<'a> System<'a> for Sys {
Read<'a, EventBus<ServerEvent>>,
Read<'a, Time>,
ReadExpect<'a, TerrainGrid>,
Write<'a, SysTimer<Self>>,
ReadStorage<'a, Body>,
ReadStorage<'a, CanBuild>,
ReadStorage<'a, Admin>,
@ -40,6 +42,7 @@ impl<'a> System<'a> for Sys {
server_emitter,
time,
terrain,
mut timer,
bodies,
can_build,
admins,
@ -53,6 +56,8 @@ impl<'a> System<'a> for Sys {
mut controllers,
): Self::SystemData,
) {
timer.start();
let time = time.0;
let mut new_chat_msgs = Vec::new();
@ -316,5 +321,7 @@ impl<'a> System<'a> for Sys {
}
}
}
timer.end()
}
}

View File

@ -5,6 +5,13 @@ pub mod terrain;
pub mod terrain_sync;
use specs::DispatcherBuilder;
use std::{marker::PhantomData, time::Instant};
pub type EntitySyncTimer = SysTimer<entity_sync::Sys>;
pub type MessageTimer = SysTimer<message::Sys>;
pub type SubscriptionTimer = SysTimer<subscription::Sys>;
pub type TerrainTimer = SysTimer<terrain::Sys>;
pub type TerrainSyncTimer = SysTimer<terrain_sync::Sys>;
// System names
const ENTITY_SYNC_SYS: &str = "server_entity_sync_sys";
@ -21,3 +28,35 @@ pub fn add_server_systems(dispatch_builder: &mut DispatcherBuilder) {
dispatch_builder.add(terrain::Sys, TERRAIN_SYNC_SYS, &[TERRAIN_SYS]);
dispatch_builder.add(message::Sys, MESSAGE_SYS, &[]);
}
/// Used to keep track of how much time each system takes
pub struct SysTimer<S> {
pub nanos: u64,
start: Option<Instant>,
_phantom: PhantomData<S>,
}
impl<S> SysTimer<S> {
pub fn start(&mut self) {
if self.start.is_some() {
panic!("Timer already started");
}
self.start = Some(Instant::now());
}
pub fn end(&mut self) {
self.nanos = self
.start
.take()
.expect("Timer ended without starting it")
.elapsed()
.as_nanos() as u64;
}
}
impl<S> Default for SysTimer<S> {
fn default() -> Self {
Self {
nanos: 0,
start: None,
_phantom: PhantomData,
}
}
}

View File

@ -1,3 +1,4 @@
use super::SysTimer;
use crate::client::{self, Client, RegionSubscription};
use common::{
comp::{Player, Pos},
@ -7,7 +8,7 @@ use common::{
terrain::TerrainChunkSize,
vol::RectVolSize,
};
use specs::{Entities, Join, ReadExpect, ReadStorage, System, WriteStorage};
use specs::{Entities, Join, ReadExpect, ReadStorage, System, Write, WriteStorage};
use vek::*;
/// This system will update region subscriptions based on client positions
@ -16,6 +17,7 @@ impl<'a> System<'a> for Sys {
type SystemData = (
Entities<'a>,
ReadExpect<'a, RegionMap>,
Write<'a, SysTimer<Self>>,
ReadStorage<'a, Uid>,
ReadStorage<'a, Pos>,
ReadStorage<'a, Player>,
@ -25,8 +27,10 @@ impl<'a> System<'a> for Sys {
fn run(
&mut self,
(entities, region_map, uids, positions, players, mut clients, mut subscriptions): Self::SystemData,
(entities, region_map, mut timer, uids, positions, players, mut clients, mut subscriptions): Self::SystemData,
) {
timer.start();
// To update subscriptions
// 1. Iterate through clients
// 2. Calculate current chunk position
@ -121,5 +125,7 @@ impl<'a> System<'a> for Sys {
}
}
}
timer.end();
}
}

View File

@ -1,3 +1,4 @@
use super::SysTimer;
use crate::{chunk_generator::ChunkGenerator, client::Client, Tick};
use common::{
comp::{self, Player, Pos},
@ -21,6 +22,7 @@ impl<'a> System<'a> for Sys {
type SystemData = (
Read<'a, EventBus<ServerEvent>>,
Read<'a, Tick>,
Write<'a, SysTimer<Self>>,
WriteExpect<'a, ChunkGenerator>,
WriteExpect<'a, TerrainGrid>,
Write<'a, TerrainChanges>,
@ -34,6 +36,7 @@ impl<'a> System<'a> for Sys {
(
server_emitter,
tick,
mut timer,
mut chunk_generator,
mut terrain,
mut terrain_changes,
@ -42,6 +45,8 @@ impl<'a> System<'a> for Sys {
mut clients,
): Self::SystemData,
) {
timer.start();
// Fetch any generated `TerrainChunk`s and insert them into the terrain.
// Also, send the chunk data to anybody that is close by.
'insert_terrain_chunks: while let Some((key, res)) = chunk_generator.recv_new_chunk() {
@ -180,6 +185,8 @@ impl<'a> System<'a> for Sys {
chunk_generator.cancel_if_pending(key);
}
timer.end()
}
}

View File

@ -1,3 +1,4 @@
use super::SysTimer;
use crate::client::Client;
use common::{
comp::{Player, Pos},
@ -5,7 +6,7 @@ use common::{
state::TerrainChanges,
terrain::TerrainGrid,
};
use specs::{Join, Read, ReadExpect, ReadStorage, System, WriteStorage};
use specs::{Join, Read, ReadExpect, ReadStorage, System, Write, WriteStorage};
/// This system will handle loading generated chunks and unloading uneeded chunks.
/// 1. Inserts newly generated chunks into the TerrainGrid
@ -17,6 +18,7 @@ impl<'a> System<'a> for Sys {
type SystemData = (
ReadExpect<'a, TerrainGrid>,
Read<'a, TerrainChanges>,
Write<'a, SysTimer<Self>>,
ReadStorage<'a, Pos>,
ReadStorage<'a, Player>,
WriteStorage<'a, Client>,
@ -24,8 +26,10 @@ impl<'a> System<'a> for Sys {
fn run(
&mut self,
(terrain, terrain_changes, positions, players, mut clients): Self::SystemData,
(terrain, terrain_changes, mut timer, positions, players, mut clients): Self::SystemData,
) {
timer.start();
// Sync changed chunks
'chunk: for chunk_key in &terrain_changes.modified_chunks {
for (player, pos, client) in (&players, &positions, &mut clients).join() {
@ -53,5 +57,7 @@ impl<'a> System<'a> for Sys {
client.notify(msg.clone());
}
}
timer.end();
}
}

View File

@ -58,6 +58,12 @@ impl PlayState for StartSingleplayerState {
}
};
// Print the metrics port
println!(
"Metrics port: {}",
self.server_settings.metrics_address.port()
);
PlayStateResult::Push(Box::new(CharSelectionState::new(
global_state,
std::rc::Rc::new(std::cell::RefCell::new(client)),