diff --git a/crates/irtt-client/src/client.rs b/crates/irtt-client/src/client.rs index 973fc40..a7e40bd 100644 --- a/crates/irtt-client/src/client.rs +++ b/crates/irtt-client/src/client.rs @@ -201,9 +201,8 @@ impl Client { payload: vec![], }; let packet = encode_echo_request(&request, self.config.hmac_key.as_deref())?; - self.socket.send(&packet)?; - let sent_at = override_ts.unwrap_or_else(ClientTimestamp::now); + self.socket.send(&packet)?; let session = self .session diff --git a/docs/IMPLEMENTATION_PLAN.md b/docs/IMPLEMENTATION_PLAN.md index dca554a..b0c8c1d 100644 --- a/docs/IMPLEMENTATION_PLAN.md +++ b/docs/IMPLEMENTATION_PLAN.md @@ -546,8 +546,8 @@ Steps: 1. Assert Active phase 2. Check if duration exceeded (if finite mode) → if so, transition to Draining 3. Encode echo request with current sequence number, connection token -4. Call `socket.send()` -5. Capture send timestamp (Instant + SystemTime) immediately after send returns +4. Capture send timestamp (Instant + SystemTime) immediately before send call +5. Call `socket.send()` 6. Insert PendingProbe into pending map 7. Increment sequence counters 8. Return any events (e.g., eviction-triggered loss events from bounded map) @@ -649,7 +649,7 @@ No signal handling in `Client`. Caller controls lifecycle by: - Maintains absolute send schedule: `scheduled_time(seq) = session_start + seq * interval` - Prepares echo request packets - Sends packets at scheduled times -- Captures send timestamps immediately after send +- Captures send timestamps immediately before send call - Sends compact `SentRecord { wire_seq, logical_seq, sent_at_mono, sent_at_wall }` to coordinator - Must NOT perform: event fanout, stats, subscriber delivery, blocking coordination @@ -1861,7 +1861,7 @@ Require `irtt` server binary in PATH. Gated behind `--features interop`. **Blocks implementation:** No. This is an implementation choice. -**Recommended behavior:** Capture `Instant::now()` + `SystemTime::now()` immediately after `send()` returns. This is what the spec recommends and is the simplest correct approach. +**Recommended behavior:** Capture `Instant::now()` + `SystemTime::now()` immediately before `send()`. This ensures the measured RTT includes local send/enqueue overhead, which is more conservative for latency-control consumers like sqm-autorate-rust. The receive timestamp remains captured immediately after `recv()` returns. ### Q3: RTT When Server Processing > Raw RTT (Section 19.12) diff --git a/docs/IRTT_CLIENT_PROTOCOL_SPEC.md b/docs/IRTT_CLIENT_PROTOCOL_SPEC.md index d53fb34..a643c92 100644 --- a/docs/IRTT_CLIENT_PROTOCOL_SPEC.md +++ b/docs/IRTT_CLIENT_PROTOCOL_SPEC.md @@ -692,7 +692,8 @@ The following configuration parameters affect protocol behavior: - **Client send timestamp:** SHOULD be captured as close as possible to the send system call. For best RTT accuracy, the timestamp should be taken - immediately after the send call returns. + immediately before the send call, so that the measured RTT includes any + local send/enqueue overhead. - **Client receive timestamp:** SHOULD be captured as close as possible to the receive system call return, before any packet processing. - **Server timestamps:** Determined by the negotiated StampAt parameter: diff --git a/docs/RUST_DESIGN.md b/docs/RUST_DESIGN.md index 3288c7a..96fb1d2 100644 --- a/docs/RUST_DESIGN.md +++ b/docs/RUST_DESIGN.md @@ -558,7 +558,7 @@ It should only: - maintain absolute send schedule - prepare outgoing packets before deadline where possible - send packets -- timestamp successful sends immediately after send returns +- timestamp immediately before send call - report compact sent records to coordinator ### Receiver Thread @@ -845,7 +845,9 @@ The server is authoritative unless the caller explicitly requires exact or bound ## Send Timestamp -Capture send timestamp immediately after `send` returns. +Capture send timestamp immediately before the `send` call. This ensures the +measured RTT includes local send/enqueue overhead, which is the more +conservative direction for latency-control consumers. ## Receive Timestamp