Repository navigation
Conversation
2592260 to
5f5fd03
Compare
M3-SPEC v1 S:2012-2013 allows READ len 1..1472, with a reply over 893 B continuing over Data More "exactly as for TCP"; errata v1.1 ER-1 (N-1) bounds each continuation by 12 s from its data-accept, and ER-5 requires each block read to its end first. Firmware 3a1ff9ff: NET_MAX_SOCKET_READ 1472; start_read_reply sends the header + 893, get_more_data the rest (payload only, <= 895), the status line only with the last block. net_poll now asks for min(ring free - 1, 1472). When the first block is read to its end, the header still owes bytes, the state is "11", and exactly 893 bytes have arrived, it data-accepts (m3_next_block: write fence kept, then waits for REPLY_VALID up to 12 s from the accept) and copies on. Anything else is still a hole: Data More after a short block, a short or over-long continuation, a second Data More, a continuation that never comes ($89, ABORT, CLOSE). M3_READ_ONE_BLOCK=1 (and M3_READ_FENCE=1) keep one-block READs and assemble the previous images byte for byte (44648860 / f5d9278b). Model: READ replies are blocked as the firmware blocks them, the status rides the last block, and a continuation can be delayed. Six new tests; seven new mutants, all killed (77/77). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…de per attempt A pre-change (M3_READ_FENCE=1) large fetch entered the viewer at 360,448 of 751,823 B with net_last_error $00; the run did not keep the framing facts that would say whether the client or the server ended it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…D image Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…y set-up Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
5f5fd03 to
b23d405
Compare
|
Closing without merging. #296 has landed. Result. Asking for 1472 B per SOCKET_READ (the firmware's Why. The ESP32 side hands over at most one TLS engine step per read. Worth revisiting if the firmware changes. A change in 1541ultimate could lift this ceiling. Two options were discussed with the firmware side:
If either lands, this branch ( |
Stacked on #296 (base
perf/uci-m3-read-pacing). It is stage 2 of the uci-m3 speed work. Measured result: no gain. Recommendation: do not merge unless the firmware's per-READ cost changes. The evidence and the code are here so that decision can be reviewed.What
net_pollasks formin(ring free - 1, 1472)instead of 893. A reply over 893 B arrives as the first block plus one Data More continuation. The client does this:The ER-5 protection still applies. Each of these is still treated as a hole:
$89, ERROR, then CLOSE.M3_READ_ONE_BLOCK=1keeps one-block READs and assembles #296's image byte for byte:44648860default target,3b3685c9for the REU-sink wiki build.M3_READ_FENCE=1still assembles the pre-#296 client (f5d9278b/a3c67976).Spec and firmware: verified before building
c265fdfc), S:2012-2013: READ len is 1..1472, and "A READ reply longer than one block (the 2-byte header + 893 bytes) continues over Data More, exactly as for TCP".f9a39ff3):a6802f40) adds nothing on this.3a1ff9ff:NET_MAX_SOCKET_READ 1472(network_target.h:48).start_read_reply(network_target.cc:483) sends the header plus up toNET_FIRST_BLOCK_PAYLOAD= 893 B. The status queue stays empty on intermediate blocks.get_more_data(:756) sends payload only, up to 895 B, with the status only on the last block.get_more_data.tls_readreturns at most one engine step's plaintext. A step is at most 1024 B (NET_TLS_PT_MAX=TLS_STEP_OUT_MAX). On hardware, a 1472 B request returns 960 B, not 1472. The win is limited to removing the ~67 B tail READs, which cost about 1.2 ms each.Model + mutation
Model changes in
check_m3_client.py:Six new tests:
test_read_continues_over_data_moretest_continuation_after_short_block_is_a_holetest_short_continuation_is_a_holetest_long_continuation_is_a_holetest_unowed_continuation_is_a_hole(also covers a second Data More after a short continuation)test_continuation_timeout_aborts(taken at accept + 11 s;$89+ ABORT + CLOSE when it never comes)On one-block images the continuation tests return early with no assertions. Those cases are not applicable there.
Results:
477e1f04: 58/58 passed.M3_READ_ONE_BLOCK=1(44648860): 58/58 passed.M3_READ_FENCE=1(f5d9278b): 58/58 passed.mutate_m3_client.py: 77/77 killed. The new mutants and what they produced:I also wrote a "no second continuation" guard. It turned out to be equivalent:
m3_blk_endstays 893, so a second Data More can never match it. I deleted it and gave the case a test instead of keeping dead code.Other profiles are unchanged:
e1ad289d375f948074a7d358b4e4e6fbHardware: three arms
Setup:
3a1ff9ff, FPGA 126, core 1.50, 48 MHz.rig_https_m3.py timed. The clock runs from 'G' until the whole body is in the REU.HTTPS_BODY_TO_REU=1 HTTPS_HOST=en.wikipedia.org HTTPS_PATH=/wiki/Commodore_64.3b3685c9.Stage 2 makes no measurable difference on the large page (18.98 vs 18.97 s). The small page shows −0.4 s at n=3, inside the session-to-session spread.
Body oracles:
net_last_error $00.9C298DA4and differs from the fresh host render only inside the parser report.m3_eof_code0.Demo disk at this branch (PRG
df0b1b9a,rig_https_m3_demo.py), n=1:94.Per-READ round trip (M3_TRACE, build
313412b4, wiki page, 879 READs, all recorded)READs per page fell from 1,666 to 879, but each 960 B READ costs the same ~5.2 ms to its first block that an 893 B READ did. Per-READ firmware time follows the engine step, not the command count. That is why removing about half the commands saved nothing: the time per command scaled with the payload.
$DF1Cbit 3 after every PUSH: 900 pushes on the large page, 57 on robots.txt. Never set.Open finding (pre-existing, not caused by either PR)
1 of 7 fenced-arm (
a3c67976, i.e. master's client code) large fetches entered the REU viewer at 360,448 of 751,823 B, with HTTP 200 andnet_last_error $00(22:04:55).wgTestKitchenUserExperiments, so it was probably a cache miss.0or a short Content-Length) or the client misjudged it. The rig now records the client's framing verdict andm3_eof_codeon every attempt.http.sverdict is the same code in all three arms.🤖 Generated with Claude Code