refactor(client): use SignedDuration for one-way delay to support negative values
Allow one-way delay samples to represent negative values caused by wall-clock skew between client and server. Update CLI output and statistics collection to correctly handle and report these signed durations.
This commit is contained in:
1 parent
0b16ee802d
commit
3b5336a487
7 files changed
+193
-19
No files matched your search
@@ -789,11 +789,11 @@ fn compute_one_way(
|
||||
let c2s = server_recv_wall
|
||||
.zip(client_send_ns)
|
||||
.and_then(|(srv, cli)| srv.checked_sub(cli))
|
||||
.and_then(|d| u64::try_from(d).ok().map(Duration::from_nanos));
|
||||
.map(|d| SignedDuration::from_nanos(i128::from(d)));
|
||||
let s2c = client_recv_ns
|
||||
.zip(server_send_wall)
|
||||
.and_then(|(cli, srv)| cli.checked_sub(srv))
|
||||
.and_then(|d| u64::try_from(d).ok().map(Duration::from_nanos));
|
||||
.map(|d| SignedDuration::from_nanos(i128::from(d)));
|
||||
|
||||
if c2s.is_none() && s2c.is_none() {
|
||||
return None;
|
||||
|
||||
@@ -90,6 +90,68 @@ fn compute_one_way_returns_available_direction_samples() {
|
||||
};
|
||||
|
||||
let sample = compute_one_way(&sent_at, &received_at, &ts).unwrap();
|
||||
assert_eq!(sample.client_to_server, Some(Duration::from_millis(15)));
|
||||
assert_eq!(sample.server_to_client, Some(Duration::from_millis(15)));
|
||||
assert_eq!(
|
||||
sample.client_to_server,
|
||||
Some(SignedDuration::from_nanos(15_000_000))
|
||||
);
|
||||
assert_eq!(
|
||||
sample.server_to_client,
|
||||
Some(SignedDuration::from_nanos(15_000_000))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compute_one_way_preserves_negative_client_to_server_delay() {
|
||||
let sent_at = ClientTimestamp {
|
||||
mono: Instant::now(),
|
||||
wall: SystemTime::UNIX_EPOCH + Duration::from_secs(10),
|
||||
};
|
||||
let received_at = ClientTimestamp {
|
||||
mono: sent_at.mono + Duration::from_millis(40),
|
||||
wall: SystemTime::UNIX_EPOCH + Duration::from_secs(10) + Duration::from_millis(40),
|
||||
};
|
||||
let ts = TimestampFields {
|
||||
recv_wall: Some(10_000_000_000 - 5_000_000),
|
||||
send_wall: Some(10_000_000_000 + 25_000_000),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let sample = compute_one_way(&sent_at, &received_at, &ts).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
sample.client_to_server,
|
||||
Some(SignedDuration::from_nanos(-5_000_000))
|
||||
);
|
||||
assert_eq!(
|
||||
sample.server_to_client,
|
||||
Some(SignedDuration::from_nanos(15_000_000))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compute_one_way_preserves_negative_server_to_client_delay() {
|
||||
let sent_at = ClientTimestamp {
|
||||
mono: Instant::now(),
|
||||
wall: SystemTime::UNIX_EPOCH + Duration::from_secs(10),
|
||||
};
|
||||
let received_at = ClientTimestamp {
|
||||
mono: sent_at.mono + Duration::from_millis(40),
|
||||
wall: SystemTime::UNIX_EPOCH + Duration::from_secs(10) + Duration::from_millis(40),
|
||||
};
|
||||
let ts = TimestampFields {
|
||||
recv_wall: Some(10_000_000_000 + 15_000_000),
|
||||
send_wall: Some(10_000_000_000 + 45_000_000),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let sample = compute_one_way(&sent_at, &received_at, &ts).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
sample.client_to_server,
|
||||
Some(SignedDuration::from_nanos(15_000_000))
|
||||
);
|
||||
assert_eq!(
|
||||
sample.server_to_client,
|
||||
Some(SignedDuration::from_nanos(-5_000_000))
|
||||
);
|
||||
}
|
||||
@@ -168,9 +168,27 @@ pub struct ServerTiming {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
/// Directional one-way delay samples computed from wall-clock timestamps.
|
||||
///
|
||||
/// Each directional field is an `Option<SignedDuration>`. `None` means the
|
||||
/// required client or server wall-clock timestamp was unavailable, or the
|
||||
/// timestamp arithmetic was out of range. `Some(value)` means the delay was
|
||||
/// computed from available timestamps.
|
||||
///
|
||||
/// Negative computed values are preserved as `Some` instead of being clamped to
|
||||
/// zero or dropped. A negative one-way delay usually indicates wall-clock skew
|
||||
/// between the client and server.
|
||||
pub struct OneWayDelaySample {
|
||||
pub client_to_server: Option<Duration>,
|
||||
pub server_to_client: Option<Duration>,
|
||||
/// Client-to-server delay.
|
||||
///
|
||||
/// This is computed from the client send wall time and the server receive
|
||||
/// wall time when both are available.
|
||||
pub client_to_server: Option<SignedDuration>,
|
||||
/// Server-to-client delay.
|
||||
///
|
||||
/// This is computed from the server send wall time and the client receive
|
||||
/// wall time when both are available.
|
||||
pub server_to_client: Option<SignedDuration>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
|
||||
Reference in new issue
Block a user