fix(client): timestamp probes after successful send

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.
This commit is contained in:
Nils Andreas Svee committed 2026-08-15 19:26:57 +07:00
1 parent 0ca36f2192
commit a3896376da
10 files changed
+502 -128

No files matched your search

+15 -7
View File
@@ -94,16 +94,19 @@ pub enum ClientEvent {
remote: SocketAddr,
/// Monotonic deadline at which the probe was scheduled to be sent.
scheduled_at: Instant,
/// Client wall/monotonic timestamp captured after probe preparation,
/// immediately before timeout finalization and the socket send.
/// Paired client wall/monotonic timestamp captured immediately after
/// the successful UDP send completed. This is the RTT and userspace
/// upstream one-way-delay fallback endpoint. The operational probe
/// timeout deadline is computed from an earlier, private, pre-send
/// timestamp instead — see the client crate's `AGENTS.md`.
sent_at: ClientTimestamp,
/// Number of bytes passed to the UDP socket.
bytes: usize,
/// Elapsed time spent in the socket send call, excluding protocol and
/// scheduler commit work.
send_call: Duration,
/// Absolute difference between the scheduled send time and actual send
/// timestamp.
/// Absolute difference between the scheduled send time and the
/// post-send `sent_at` timestamp above.
timer_error: Duration,
},
@@ -117,7 +120,8 @@ pub enum ClientEvent {
seq: u32,
/// Resolved remote socket address.
remote: SocketAddr,
/// Client timestamp recorded when the matching request was sent.
/// Client timestamp recorded immediately after the matching request
/// finished sending (see `ClientEvent::EchoSent::sent_at`).
sent_at: ClientTimestamp,
/// Client timestamp recorded when the reply was received.
received_at: ClientTimestamp,
@@ -143,7 +147,10 @@ pub enum ClientEvent {
EchoLoss {
/// Wire sequence number that timed out.
seq: u32,
/// Client timestamp recorded when the request was sent.
/// Client timestamp recorded immediately after the request finished
/// sending (see `ClientEvent::EchoSent::sent_at`). The timeout
/// deadline below is anchored to an earlier, private, pre-send
/// timestamp, not to this one.
sent_at: ClientTimestamp,
/// Monotonic deadline at which the probe was declared lost.
timeout_at: std::time::Instant,
@@ -178,7 +185,8 @@ pub enum ClientEvent {
highest_seen: u32,
/// Resolved remote socket address.
remote: SocketAddr,
/// Original client send timestamp, when still retained.
/// Original post-send client timestamp, when still retained (see
/// `ClientEvent::EchoSent::sent_at`).
sent_at: Option<ClientTimestamp>,
/// Client timestamp recorded when the late reply was received.
received_at: ClientTimestamp,