Moves the client userspace probe sent_at measurement to immediately after a successful UDP send, improving raw RTT and the userspace upstream-OWD fallback by excluding the socket send-call interval and the small amount of local work preceding it. All fallible probe-commit preflight (timeout deadline checked_add, capacity/collision checks) still runs before the send, from a private pre-send anchor (SessionMachine::finalize_probe_commit). The public sent_at is now supplied afterward to an infallible SessionMachine::commit_probe_sent, so DurationOverflow still guarantees nothing was transmitted and a WouldBlock try_send still commits nothing. The operational probe timeout deadline stays anchored to the pre-send timestamp on purpose, not to the new post-send sent_at, preserving existing timeout/loss timing. Linux kernel TX_SOFTWARE plausibility keeps its own pre-send wall-clock lower bound (PendingProbe::tx_not_before_wall) instead of the post-send sent_at, since a legitimate TX_SOFTWARE timestamp can be generated while the send syscall is still in flight and would otherwise be wrongly rejected. Also flags (without touching production code) that irtt-stats' ReplySample::from_reply_parts feeds the public sent_at directly into IpdvSample.client_send_mono/client_send_wall_ns, so the upstream/send IPDV component naturally shifts along with the sent_at semantics change; per scope this is reported rather than compensated for.
193 lines
5.2 KiB
Rust
193 lines
5.2 KiB
Rust
use super::*;
|
|
use crate::metadata::ReceiveMeta;
|
|
|
|
#[test]
|
|
fn server_processing_greater_than_raw_does_not_underflow() {
|
|
let base = Instant::now();
|
|
let rtt = compute_rtt(
|
|
&ClientTimestamp {
|
|
mono: base,
|
|
wall: SystemTime::now(),
|
|
},
|
|
&ClientTimestamp {
|
|
mono: base + Duration::from_nanos(1),
|
|
wall: SystemTime::now(),
|
|
},
|
|
&TimestampFields {
|
|
recv_mono: Some(0),
|
|
send_mono: Some(1_000_000_000),
|
|
..Default::default()
|
|
},
|
|
);
|
|
assert_eq!(rtt.adjusted, Some(SignedDuration::from_nanos(-999_999_999)));
|
|
assert_eq!(rtt.effective, SignedDuration::from_nanos(-999_999_999));
|
|
}
|
|
|
|
#[test]
|
|
fn effective_rtt_uses_raw_when_adjusted_rtt_is_unavailable() {
|
|
let base = Instant::now();
|
|
let rtt = compute_rtt(
|
|
&ClientTimestamp {
|
|
mono: base,
|
|
wall: SystemTime::now(),
|
|
},
|
|
&ClientTimestamp {
|
|
mono: base + Duration::from_nanos(42),
|
|
wall: SystemTime::now(),
|
|
},
|
|
&TimestampFields::default(),
|
|
);
|
|
|
|
assert_eq!(rtt.adjusted, None);
|
|
assert_eq!(rtt.effective, SignedDuration::from_duration(rtt.raw));
|
|
}
|
|
|
|
#[test]
|
|
fn unix_epoch_ns_i64_rejects_out_of_range_wall_time() {
|
|
let i64_max_ns = u64::try_from(i64::MAX).unwrap();
|
|
let max = SystemTime::UNIX_EPOCH + Duration::from_nanos(i64_max_ns);
|
|
let overflow = max + Duration::from_nanos(1);
|
|
|
|
assert_eq!(unix_epoch_ns_i64(max), Some(i64::MAX));
|
|
assert_eq!(unix_epoch_ns_i64(overflow), None);
|
|
}
|
|
|
|
#[test]
|
|
fn compute_one_way_omits_samples_when_client_wall_time_overflows_i64() {
|
|
let i64_max_ns = u64::try_from(i64::MAX).unwrap();
|
|
let overflow_wall =
|
|
SystemTime::UNIX_EPOCH + Duration::from_nanos(i64_max_ns) + Duration::from_nanos(1);
|
|
let sent_at = ClientTimestamp {
|
|
mono: Instant::now(),
|
|
wall: overflow_wall,
|
|
};
|
|
let received_at = ClientTimestamp {
|
|
mono: sent_at.mono + Duration::from_millis(40),
|
|
wall: overflow_wall + Duration::from_millis(40),
|
|
};
|
|
let ts = TimestampFields {
|
|
recv_wall: Some(i64::MAX),
|
|
send_wall: Some(i64::MAX),
|
|
..Default::default()
|
|
};
|
|
|
|
assert_eq!(
|
|
compute_one_way(
|
|
&sent_at,
|
|
sent_at.wall,
|
|
&received_at,
|
|
None,
|
|
&ReceiveMeta::default(),
|
|
&ts
|
|
),
|
|
None
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn compute_one_way_returns_available_direction_samples() {
|
|
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 + 25_000_000),
|
|
..Default::default()
|
|
};
|
|
|
|
let sample = compute_one_way(
|
|
&sent_at,
|
|
sent_at.wall,
|
|
&received_at,
|
|
None,
|
|
&ReceiveMeta::default(),
|
|
&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(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,
|
|
sent_at.wall,
|
|
&received_at,
|
|
None,
|
|
&ReceiveMeta::default(),
|
|
&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,
|
|
sent_at.wall,
|
|
&received_at,
|
|
None,
|
|
&ReceiveMeta::default(),
|
|
&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))
|
|
);
|
|
}
|