Make fps display and specification more precise

This commit is contained in:
Imbris 2020-11-11 21:47:22 -05:00
parent c8357842af
commit a97b188bea
8 changed files with 47 additions and 39 deletions

1
Cargo.lock generated
View File

@ -5140,6 +5140,7 @@ dependencies = [
"notify", "notify",
"num-derive", "num-derive",
"num-traits 0.2.12", "num-traits 0.2.12",
"ordered-float 2.0.0",
"parking_lot 0.11.0", "parking_lot 0.11.0",
"rand 0.7.3", "rand 0.7.3",
"rayon", "rayon",

View File

@ -26,7 +26,7 @@ fn main() {
info!("Starting chat-cli..."); info!("Starting chat-cli...");
// Set up an fps clock. // Set up an fps clock.
let mut clock = Clock::new(Duration::from_millis(1000 / TPS)); let mut clock = Clock::new(Duration::from_secs_f64(1.0 / TPS as f64));
println!("Enter your username"); println!("Enter your username");
let username = read_input(); let username = read_input();

View File

@ -13,34 +13,36 @@ default = ["simd"]
[dependencies] [dependencies]
arraygen = "0.1.13" arraygen = "0.1.13"
specs-idvs = { git = "https://gitlab.com/veloren/specs-idvs.git", branch = "specs-git" } authc = { git = "https://gitlab.com/veloren/auth.git", rev = "b943c85e4a38f5ec60cd18c34c73097640162bfe" }
crossbeam = "0.7"
roots = "0.0.6"
specs = { git = "https://github.com/amethyst/specs.git", features = ["serde", "storage-event-control"], rev = "7a2e348ab2223818bad487695c66c43db88050a5" }
vek = { version = "0.12.0", features = ["serde"] }
directories-next = "2.0" directories-next = "2.0"
dot_vox = "4.0" dot_vox = "4.0"
enum-iterator = "0.6"
hashbrown = { version = "0.7.2", features = ["rayon", "serde", "nightly"] }
image = { version = "0.23.8", default-features = false, features = ["png"] } image = { version = "0.23.8", default-features = false, features = ["png"] }
indexmap = "1.3.0"
lazy_static = "1.4.0"
notify = "5.0.0-pre.3"
num-derive = "0.3"
num-traits = "0.2"
ordered-float = { version = "2.0.0", default-features = false }
parking_lot = "0.11.0"
rand = "0.7"
rayon = "1.3.0"
ron = { version = "0.6", default-features = false }
roots = "0.0.6"
serde = { version = "1.0.110", features = ["derive", "rc"] } serde = { version = "1.0.110", features = ["derive", "rc"] }
serde_json = "1.0.50" serde_json = "1.0.50"
serde_repr = "0.1.6" serde_repr = "0.1.6"
ron = { version = "0.6", default-features = false }
tracing = { version = "0.1", default-features = false }
rand = "0.7"
rayon = "1.3.0"
lazy_static = "1.4.0"
hashbrown = { version = "0.7.2", features = ["rayon", "serde", "nightly"] }
parking_lot = "0.11.0"
crossbeam = "0.7"
notify = "5.0.0-pre.3"
indexmap = "1.3.0"
sum_type = "0.2.0"
authc = { git = "https://gitlab.com/veloren/auth.git", rev = "b943c85e4a38f5ec60cd18c34c73097640162bfe" }
slab = "0.4.2" slab = "0.4.2"
enum-iterator = "0.6"
spin_sleep = "1.0" spin_sleep = "1.0"
num-traits = "0.2" sum_type = "0.2.0"
num-derive = "0.3" tracing = { version = "0.1", default-features = false }
vek = { version = "0.12.0", features = ["serde"] }
# ECS
specs = { git = "https://github.com/amethyst/specs.git", features = ["serde", "storage-event-control"], rev = "7a2e348ab2223818bad487695c66c43db88050a5" }
specs-idvs = { git = "https://gitlab.com/veloren/specs-idvs.git", branch = "specs-git" }
# Tracy # Tracy
tracy-client = { version = "0.9.0", optional = true } tracy-client = { version = "0.9.0", optional = true }

View File

@ -1,4 +1,5 @@
use crate::span; use crate::span;
use ordered_float::NotNan;
use std::{ use std::{
collections::VecDeque, collections::VecDeque,
time::{Duration, Instant}, time::{Duration, Instant},
@ -26,10 +27,9 @@ pub struct Clock {
/// summed up `last_dt` /// summed up `last_dt`
total_tick_time: Duration, total_tick_time: Duration,
// Stats only // Stats only
// stored as millis in u16 to save space. if it's more than u16::MAX (16s) we have other // uses f32 so we have enough precision to display fps values while saving space
// problems last_dts_millis: VecDeque<NotNan<f32>>,
last_dts_millis: VecDeque<u16>, last_dts_millis_sorted: Vec<NotNan<f32>>,
last_dts_millis_sorted: Vec<u16>,
stats: ClockStats, stats: ClockStats,
} }
@ -74,13 +74,14 @@ impl Clock {
/// Do not modify without asking @xMAC94x first! /// Do not modify without asking @xMAC94x first!
pub fn tick(&mut self) { pub fn tick(&mut self) {
span!(_guard, "tick", "Clock::tick"); span!(_guard, "tick", "Clock::tick");
span!(guard, "clock work");
let current_sys_time = Instant::now(); let current_sys_time = Instant::now();
let busy_delta = current_sys_time.duration_since(self.last_sys_time); let busy_delta = current_sys_time.duration_since(self.last_sys_time);
// Maintain TPS // Maintain TPS
self.last_dts_millis_sorted = self.last_dts_millis.iter().copied().collect(); self.last_dts_millis_sorted = self.last_dts_millis.iter().copied().collect();
self.last_dts_millis_sorted.sort_unstable(); self.last_dts_millis_sorted.sort_unstable();
self.stats = ClockStats::new(&self.last_dts_millis_sorted, busy_delta); self.stats = ClockStats::new(&self.last_dts_millis_sorted, busy_delta);
drop(guard);
// Attempt to sleep to fill the gap. // Attempt to sleep to fill the gap.
if let Some(sleep_dur) = self.target_dt.checked_sub(busy_delta) { if let Some(sleep_dur) = self.target_dt.checked_sub(busy_delta) {
spin_sleep::sleep(sleep_dur); spin_sleep::sleep(sleep_dur);
@ -91,29 +92,31 @@ impl Clock {
if self.last_dts_millis.len() >= NUMBER_OF_OLD_DELTAS_KEPT { if self.last_dts_millis.len() >= NUMBER_OF_OLD_DELTAS_KEPT {
self.last_dts_millis.pop_front(); self.last_dts_millis.pop_front();
} }
self.last_dts_millis self.last_dts_millis.push_back(
.push_back((self.last_dt.as_millis() as u16).min(std::u16::MAX)); NotNan::new(self.last_dt.as_secs_f32() * 1000.0)
.expect("Duration::as_secs_f32 never returns NaN"),
);
self.total_tick_time += self.last_dt; self.total_tick_time += self.last_dt;
self.last_sys_time = after_sleep_sys_time; self.last_sys_time = after_sleep_sys_time;
} }
} }
impl ClockStats { impl ClockStats {
fn new(sorted: &[u16], last_busy_dt: Duration) -> Self { fn new(sorted: &[NotNan<f32>], last_busy_dt: Duration) -> Self {
const NANOS_PER_SEC: f64 = Duration::from_secs(1).as_nanos() as f64; const NANOS_PER_SEC: f64 = Duration::from_secs(1).as_nanos() as f64;
const NANOS_PER_MILLI: f64 = Duration::from_millis(1).as_nanos() as f64; const NANOS_PER_MILLI: f64 = Duration::from_millis(1).as_nanos() as f64;
let len = sorted.len(); let len = sorted.len();
let average_millis = sorted.iter().fold(0, |a, x| a + *x as u32) / len.max(1) as u32; let average_millis = sorted.iter().sum::<NotNan<f32>>().into_inner() / len.max(1) as f32;
let average_tps = NANOS_PER_SEC / (average_millis as f64 * NANOS_PER_MILLI); let average_tps = NANOS_PER_SEC / (average_millis as f64 * NANOS_PER_MILLI);
let (median_tps, percentile_90_tps, percentile_95_tps, percentile_99_tps) = if len let (median_tps, percentile_90_tps, percentile_95_tps, percentile_99_tps) = if len
>= NUMBER_OF_OLD_DELTAS_KEPT >= NUMBER_OF_OLD_DELTAS_KEPT
{ {
let median_millis = sorted[len / 2]; let median_millis = *sorted[len / 2];
let percentile_90_millis = sorted[(NUMBER_OF_OLD_DELTAS_KEPT as f32 * 0.1) as usize]; let percentile_90_millis = *sorted[(NUMBER_OF_OLD_DELTAS_KEPT as f32 * 0.1) as usize];
let percentile_95_millis = sorted[(NUMBER_OF_OLD_DELTAS_KEPT as f32 * 0.05) as usize]; let percentile_95_millis = *sorted[(NUMBER_OF_OLD_DELTAS_KEPT as f32 * 0.05) as usize];
let percentile_99_millis = sorted[(NUMBER_OF_OLD_DELTAS_KEPT as f32 * 0.01) as usize]; let percentile_99_millis = *sorted[(NUMBER_OF_OLD_DELTAS_KEPT as f32 * 0.01) as usize];
let median_tps = NANOS_PER_SEC / (median_millis as f64 * NANOS_PER_MILLI); let median_tps = NANOS_PER_SEC / (median_millis as f64 * NANOS_PER_MILLI);
let percentile_90_tps = NANOS_PER_SEC / (percentile_90_millis as f64 * NANOS_PER_MILLI); let percentile_90_tps = NANOS_PER_SEC / (percentile_90_millis as f64 * NANOS_PER_MILLI);

View File

@ -140,7 +140,7 @@ fn main() -> io::Result<()> {
let mut shutdown_coordinator = ShutdownCoordinator::new(Arc::clone(&sigusr1_signal)); let mut shutdown_coordinator = ShutdownCoordinator::new(Arc::clone(&sigusr1_signal));
// Set up an fps clock // Set up an fps clock
let mut clock = Clock::new(Duration::from_millis(1000 / TPS)); let mut clock = Clock::new(Duration::from_secs_f64(1.0 / TPS as f64));
// Wait for a tick so we don't start with a zero dt // Wait for a tick so we don't start with a zero dt
loop { loop {

View File

@ -184,8 +184,10 @@ fn main() {
audio, audio,
profile, profile,
window, window,
clock: Clock::new(std::time::Duration::from_secs_f64(
1.0 / settings.graphics.max_fps as f64,
)),
settings, settings,
clock: Clock::new(std::time::Duration::from_millis(30)),
info_message: None, info_message: None,
#[cfg(feature = "singleplayer")] #[cfg(feature = "singleplayer")]
singleplayer: None, singleplayer: None,

View File

@ -178,8 +178,8 @@ fn handle_main_events_cleared(
if !exit { if !exit {
// Wait for the next tick. // Wait for the next tick.
span!(_guard, "Main thread sleep"); span!(_guard, "Main thread sleep");
global_state.clock.set_target_dt(Duration::from_millis( global_state.clock.set_target_dt(Duration::from_secs_f64(
1000 / global_state.settings.graphics.max_fps as u64, 1.0 / global_state.settings.graphics.max_fps as f64,
)); ));
global_state.clock.tick(); global_state.clock.tick();

View File

@ -152,7 +152,7 @@ fn run_server(mut server: Server, rec: Receiver<Msg>, paused: Arc<AtomicBool>) {
info!("Starting server-cli..."); info!("Starting server-cli...");
// Set up an fps clock // Set up an fps clock
let mut clock = Clock::new(Duration::from_millis(1000 / TPS)); let mut clock = Clock::new(Duration::from_secs_f64(1.0 / TPS as f64));
loop { loop {
// Check any event such as stopping and pausing // Check any event such as stopping and pausing