CMV: Rust's time handling is overengineered

This commit is contained in:
lemonsh 2022-01-02 19:06:56 +01:00
commit 050ea0c1cd
4 changed files with 229 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/target
.idea

126
Cargo.lock generated Normal file
View File

@ -0,0 +1,126 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "autocfg"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "chrono"
version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
dependencies = [
"libc",
"num-integer",
"num-traits",
"time",
"winapi",
]
[[package]]
name = "libc"
version = "0.2.112"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125"
[[package]]
name = "no-std-net"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bcece43b12349917e096cddfa66107277f123e6c96a5aea78711dc601a47152"
[[package]]
name = "num-integer"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
[[package]]
name = "sntp-yield"
version = "0.1.0"
dependencies = [
"chrono",
"sntpc",
"spin_sleep",
]
[[package]]
name = "sntpc"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dd9ef0de174c00dfc61054e7402b8b133a03943c2c9697c497650c4d2cf52f3"
dependencies = [
"no-std-net",
]
[[package]]
name = "spin_sleep"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a98101bdc3833e192713c2af0b0dd2614f50d1cf1f7a97c5221b7aac052acc7"
dependencies = [
"once_cell",
"winapi",
]
[[package]]
name = "time"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
dependencies = [
"libc",
"wasi",
"winapi",
]
[[package]]
name = "wasi"
version = "0.10.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

9
Cargo.toml Normal file
View File

@ -0,0 +1,9 @@
[package]
name = "sntp-yield"
version = "0.1.0"
edition = "2021"
[dependencies]
spin_sleep = "1.0"
sntpc = "0.3"
chrono = "0.4"

92
src/main.rs Normal file
View File

@ -0,0 +1,92 @@
use std::io::{stdout, Write};
use sntpc::{Error, NtpContext, NtpTimestampGenerator, NtpUdpSocket, Result};
use std::net::{SocketAddr, ToSocketAddrs, UdpSocket};
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use chrono::NaiveDateTime;
use spin_sleep::LoopHelper;
#[derive(Copy, Clone, Default)]
struct StdTimestampGen {
duration: Duration,
}
impl NtpTimestampGenerator for StdTimestampGen {
fn init(&mut self) {
self.duration = std::time::SystemTime::now()
.duration_since(std::time::SystemTime::UNIX_EPOCH)
.unwrap();
}
fn timestamp_sec(&self) -> u64 {
self.duration.as_secs()
}
fn timestamp_subsec_micros(&self) -> u32 {
self.duration.subsec_micros()
}
}
#[derive(Debug)]
struct UdpSocketWrapper(UdpSocket);
impl NtpUdpSocket for UdpSocketWrapper {
fn send_to<T: ToSocketAddrs>(
&self,
buf: &[u8],
addr: T,
) -> Result<usize> {
match self.0.send_to(buf, addr) {
Ok(usize) => Ok(usize),
Err(_) => Err(Error::Network),
}
}
fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, SocketAddr)> {
match self.0.recv_from(buf) {
Ok((size, addr)) => Ok((size, addr)),
Err(_) => Err(Error::Network),
}
}
}
fn stable_abs_diff(a: u64, b: u64) -> u64 {
if a < b {
b - a
} else {
a - b
}
}
fn main() {
println!("Synchronizing with Google Atomic Clock...");
let mut loop_helper = LoopHelper::builder().report_interval_s(2.0).build_with_target_rate(20);
let mut current_fps: f64 = 0.0;
let socket = UdpSocket::bind("0.0.0.0:0")
.expect("Unable to crate UDP socket");
socket.set_read_timeout(Some(Duration::from_secs(2)))
.expect("Unable to set UDP socket read timeout");
let sock_wrapper = UdpSocketWrapper(socket);
let ntp_context = NtpContext::new(StdTimestampGen::default());
let result = sntpc::get_time("time.google.com:123", sock_wrapper, ntp_context);
let start = SystemTime::now();
let native_timestamp = start.duration_since(UNIX_EPOCH).unwrap().as_millis() as u64;
match result {
Ok(time) => {
let timestamp = (time.seconds as u64 * 1000) + ((time.seconds_fraction as u64 * 1000) >> 32);
println!("Roundtrip: {}us\nNTP Timestamp: {}ms\nNative timestamp: {}ms\nDelta: {}ms\nNTP Delta: {}us\n\nCurrent time:", time.roundtrip, timestamp, native_timestamp, stable_abs_diff(timestamp, native_timestamp), time.offset);
loop {
let frame_delta = loop_helper.loop_start();
if let Some(fps) = loop_helper.report_rate() {
current_fps = fps;
}
let formatted_time = NaiveDateTime::from_timestamp(timestamp as i64, 0).format("%Y-%m-%d %H:%M:%S");
println!("{} @ {} fps ({}ms frametime)\r", formatted_time, current_fps, frame_delta.as_millis());
stdout().flush().unwrap();
loop_helper.loop_sleep();
}
}
Err(err) => println!("Could not get time from the NTP server: {:?}", err),
}
}