Repository navigation
Conversation
… grew The T14's wired upload trails Linux's with no loss, and every osbench round is a new connection, so the question is how fast each connection's window opens. Two instruments read it. osbench-lan (protocol /3): the sink answers what it had received by 100 ms, 300 ms, 1 s and 2 s after its first byte, and the upload row carries their means. ToyOS's and Linux's senders are read the same way, at the receiver, as delivered bytes. ToyOS's rows also read net.wire.received, the ACK frames. [tcp] counts each ACK outside recovery by whether cwnd ended the opportunity before it (tcp.acks.cwnd-limited, tcp.acks.not-limited), the bytes it acknowledged (tcp.acks.bytes) and what it grew cwnd by (tcp.cwnd.grown.bytes): bytes per ACK and growth per ACK, the two quantities slow start's per-ACK rule turns into a rate. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… in flight is in use On the T14's wired upload to the AMD's Wi-Fi peer, ToyOS delivered 0.32 MB by 100 ms, 2.0 MB by 300 ms and 39 MB by 1 s of each new connection, where Linux delivered 6.1, 28.5 and 109 MB. From 1 s to 2 s ToyOS carried 112-117 MB, Linux 115. The whole gap is the first second: the window opened slowly, and nothing was lost. Two rules held it. - Each growing ACK added one SMSS, RFC 5681 §3.1's min(N, SMSS), and this peer acknowledges about 50 KB (34 segments) at a time. Slow start then grows a few percent per round trip rather than doubling. RFC 9438 §4.10 says CUBIC SHOULD use HyStart++ (RFC 9406), whose initial slow start adds min(N, L * SMSS) with L = 8 for a sender that does not pace (§4.3). [tcp] does not pace, so L is 8. HyStart++ also exits on a delay increase: a round whose minimum RTT rises by RttThresh over the last enters Conservative Slow Start, which grows by a quarter and either resumes slow start when the RTT falls back under its baseline or, after CSS_ROUNDS rounds, sets ssthresh to cwnd. Avoidance then starts with K = 0 and W_max = cwnd_prior = cwnd (RFC 9438 §4.10). The constants are §4.3's. HyStart++ runs only while ssthresh is still the initial value; slow start after a loss stays RFC 5681's. - An opportunity the card's credit ended counted as cwnd's only if it left less than one segment of room, and 75-76 % of the ACKs then grew nothing. RFC 9438 §5.8's application limit is the sender application's or the receiver's window; the local interface is neither. Such an opportunity now leaves the window in use when at least half of cwnd is in flight, the threshold RFC 7661 §4.3 sets for a validated window. s_cc_017 now holds both sides of that boundary. The RTT sample an ACK gave is passed to congestion control with the ACK. [tcp] counts CSS entries, resumptions, exits and cwnd at exit (tcp.hystart.*), so a row says whether and where slow start ended. the_receive_window_grows_by_what_is_read_per_round_trip quadrupled the path's RTT after its writer had started, which HyStart++ reads, as specified, as a queue; its writer now starts after the change, and the test still checks the receiver's window, its claim. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
TSval ticks at 1 ms, the finest RFC 7323 §5.4 allows, and with timestamps every RTT sample comes from TSecr. On a 2 ms LAN path that quantum is half the round trip and a quarter of HyStart++'s 4 ms threshold. Recorded with its exit, per-segment send times (RFC 8985 §6.1); nothing measured yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…is left T14, osbench_lan, 2026-10-28: Linux, A B A B A B, Linux, where A is the fix reverted (f895223) and B the fix (94e3ee70d). Upload p50: A 87, 87, 87; B 112, 112, 112; Linux 113, 113. B was faster in every pair (one-sided p = 1/20), with nothing resent and no loss probe. Received by 1 s: A 34-38 MB, B 106-107, Linux 110-111. The record stays open on what is left, each connection's first 300 ms (B 24-25 MB by 300 ms against Linux's 29.7). In every B row HyStart++ entered CSS 590-702 times and resumed every time, never exiting. That this oscillation is the residual is an inference. The exit now names it and pacing as the leads. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of #1102 at 1250226ArchitectureThe ownership is right. Congestion control stays in [tcp]'s RFC 9406 / 9438 conformance, clause by clause
Half-window ruleMechanism: every data hand-off provisionally sets
Tests and controls
EvidenceI checked r2/ab against the PR's table. Upload p50 is A 87/87/87, B 112/112/112, Linux 113/113. Received-by figures and the HyStart counters match (CSS 702/590/679, resumed equal, 0 exits). In every B row: 0 retransmitted bytes, 0 RTOs, 0 recoveries, 0 loss probes. A1 sent 2 loss probes. The images are hashed. The A/B is the whole change reverted onto the measured base, which is the right control. It does not separate HyStart++ from the half-window rule. Counters
FindingsBLOCKER 1 — the half-window rule's justification misstates RFC 9438 §5.8, and the module header is now false.
BLOCKER 2 — false evidence claim in the PR description. "The previous A/B measured this rule alone as worth about 4-5 MB/s." Arm B of that session is BLOCKER 3 — BLOCKER 4 — the timestamps-off weakness is only in the PR body. Without timestamps, SUGGESTION 1 — SUGGESTION 2 — SUGGESTION 3 — SUGGESTION 4 — SUGGESTION 5 (a lead for the residual, an inference I have not measured). SEND BACK |
…renamed to its residual, and CSS flaps counted per round - The half-window rule's comments misread RFC 9438 §5.8. Its definition of an application-limited flow is "sending less than what is allowed by the congestion window", which a card-held sender with room left is. The rule is a deliberate departure: half of cwnd in flight is RFC 7661 §4.3's validated window, which RFC 9438 §4.6 admits; cwnd stays within twice the flight, and a loss sets ssthresh from the flight (§4.6). cc.rs's header now says the gate as it is, and Cc::limited, hand_off and s_cc_017 say the rest. - s_cc_017 pins the boundary: with 9 of cwnd's 18 segments in flight the next ACK grows cwnd; with 8 it grows nothing. A strict comparison, one segment under half and a quarter of cwnd each red it. - The issue's slug and title said the upload ran at a third of Linux's, which the tree refutes. It is now issues/tcp-opens-a-connections-window-slower-than-linux-in-its-first-300-ms.md, whose opening states the residual, and the one citation moves with it. - issues/tcp-samples-rtt-at-a-millisecond.md records that without timestamps HyStart++'s delay exit is inert: one Karn sample a round never reaches N_RTT_SAMPLE, so the initial slow start grows with L = 8 until a loss. - RFC 9406 §4.2 checks for CSS on every ACK of a round once it has its samples, and a round's running minimum only falls. So a round whose minimum falls while it stays past the threshold resumes slow start at each lower sample and re-enters CSS at the next. s_cc_023 holds that, four entries in one round. Each entry now says whether it is its round's first, counted as tcp.hystart.css.rounds, so a row can tell such flaps from rounds that each entered once. - tcp.acks.bytes is dropped: it equals tcp.sent.bytes except under loss. osbench's counter doc no longer lists what it reads, and net.rs's doc is rewrapped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review r2 of #1102 at ae8e78bThe one new commit since 1250226 answers r1. Merge base is unchanged (a5b330f). Its code changes are comments, the r1 blockers
New tests and counter
FindingsSUGGESTION 1 — SUGGESTION 2 — SUGGESTION 3 — PR body, for the orchestrator. "resumed every time, never exiting: the Wi-Fi-jitter risk below, now observed" reads as an established cause. The new last risk bullet correctly says that within-round flapping may account for much of the 590–702 entries, so the attribution is an inference until No blocker remains. LAND |
|
Orchestrator: r2 LAND. I corrected the body's CSS attribution to an inference (suggestion 3). Suggestions 1–2 are left to the follow-up, since the queued session's images already carry the counter's current name. Landing. |
Status: draft. Review round 1's findings are addressed (below); the T14 A/B is done.
Problem
The T14's wired upload (I219 to the AMD bench's Wi-Fi peer) reads 85-89 MB/s under ToyOS against Linux's 110-113. The driver keeps line rate with frames in hand. The receiver-side ramp marks added here read where the rest goes (session at d1ea418, means of five connections a row):
From 1 s on ToyOS runs at line rate. The whole gap is each new connection's first second, with nothing lost. The peer acknowledges about 50 KB (34 segments) per ACK, and each growing ACK added one SMSS (RFC 5681 §3.1's min(N, SMSS)), so slow start grew a few percent per round trip. Also, 75-76 % of ACKs grew nothing, because the card's room had ended the opportunity before them.
Change
limited = trueat every card stop, not this rule, and the A/B below measures it only together with HyStart++.tcp.hystart.{css,css.rounds,resumed,exits,exit.cwnd.bytes};css.rounds(review round 1) counts rounds that entered CSS, besidecss's entries.the_receive_window_grows_by_what_is_read_per_round_tripquadrupled the path RTT after its writer had started. HyStart++ reads that, as specified, as a queue and exits. The writer now starts after the change, and the test still checks the receiver's window.Checks
cargo run -- --ci hostat 94e3ee70d: 105 steps, all green. Rebased onto a5b330f (main) after the A/B: [tcp] 423 passed, andcargo run -- --ci hostat 1250226: 105 steps, all green.cargo run -- --ci host105 steps, all green; [tcp] 424 passed.Metal: T14 A/B, 2026-10-28
osbench_lan, run as Linux, A B A B A B, Linux. A = f895223 (the fix reverted), B = 94e3ee70d (the fix, same code as the head). Every boot rc = 0 and every judge exit 0. The peer and the T14's Linux ran this branch's osbench (lan/3). Evidence r2.issues/tcp-opens-a-connections-window-slower-than-linux-in-its-first-300-ms.md.tcp.hystart.css.roundswill separate them on the next session. Whether either accounts for the residual is not separated. The leads are RFC 9406 §4.3's tunable thresholds on such a path, or pacing with L = ∞, as a follow-up.osbench_lanneeds the T14's I219 and the AMD peer. The AMD bench has no NIC ToyOS drives, and ToyOS has no Wi-Fi driver, so no other bench or row runs this path today.Review round 1
Cc::limited,hand_off, s_cc_017 and above.>for>=, half less a segment, and a quarter each red it.tcp.acks.bytesdropped. S4: osbench's counter doc shortened.tcp.hystart.css.roundscounts rounds entered. Its two controls (the round's first never reset, always first) red it.Risks
issues/tcp-samples-rtt-at-a-millisecond.md, which the stacked step-1 PR closes.tcp.hystart.css.roundsseparates the two on the next metal session.🤖 Generated with Claude Code