• docs/zmodem_comparison.md src/bench/zmodem/README.md

    From Rob Swindell (on Debian Linux)@1:103/705 to Git commit to main/sbbs/master on Thu Jul 23 23:03:46 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/142d6aa509d91e348bd28dd2
    Modified Files:
    docs/zmodem_comparison.md src/bench/zmodem/README.md
    Log Message:
    docs/zmodem, bench: correct SyncTERM/localhost/recall claims (per Deuce)

    Deuce (SyncTERM's author) corrected three framings; retained with caveats:

    - "SyncTERM ~85 MB/s (faithful ztx_buf model)" is wrong. ztx_buf models the
    SHAPE of SyncTERM's send path but under-measures its throughput ~3x
    (Python-relay harness + poll-per-subpacket). SyncTERM's speed is a
    deliberate BDP / socket-buffer choice (~75% of a 1Gb LAN), not an emergent
    send-path fact. Relabelled ztx_buf as a "buffered floor (harness)" and
    flagged ~85 as a localhost floor, not SyncTERM, throughout.
    - The "recall stale bytes / abort-aware purge on ZRPOS" root-cause framing
    (bench README) was a wrong garden path: you can't recall bytes once they
    hit the network buffers, and lrz doesn't either yet recovers. The batched-
    sender failures were implementation bugs, not inherent to batching.
    - These are localhost CPU microbenchmarks; below ~8ms RTT the socket buffer
    dominates the send loop. Optimizing it for localhost is largely beside the
    point; the send-loop rewrite pays off only on fast LANs.

    Also fixed a stale "fixed" on the ring-per-byte row (the batching prototype
    was reverted, not shipped).

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Debian Linux)@1:103/705 to Git commit to main/sbbs/master on Fri Jul 24 11:06:26 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/9627d6504cecd3c53ff66c47
    Modified Files:
    docs/zmodem_comparison.md src/bench/zmodem/README.md
    Log Message:
    docs/zmodem, bench: re-measure after Deuce's send-path work; root-cause sexyz

    Every throughput figure is re-measured in one interleaved batch (256 MB,
    three passes, spread under 2%) so the tables are internally consistent
    instead of splicing runs from different days: lrzsz 203.9, zmodem.c
    rev 2.3 buffered floor 115.8, sexyz receiving 113.3, Forsberg 96.9,
    zmodem.c rev 2.2 buffered floor 91.9, sexyz sending 11.5 MB/s.

    Deuce's 2026-07-24 work on the shared send path (class-table byte
    classifier, slicing-by-4 CRC-32, hoisted escape mask with noinline cold
    paths, buffered fcrc32) moved the buffered floor 91.9 -> 115.8, +26%,
    which SyncTERM inherits. The doc's old "second, shared lever, pending"
    framing is replaced with what actually shipped.

    Root-cause the sexyz sender properly rather than asserting it.
    send_byte() takes the ring mutex twice per byte while output_thread
    hot-loops on the same mutex: 44 CPU-seconds per 256 MB against lsz's
    0.95, 1,464,130 voluntary context switches against 1,402, one futex per
    17 bytes with 37% contended, and ~94-byte socket writes. A full sweep
    of OutbufSize, OutbufHighwaterMark and OutbufDrainTimeout is flat inside
    noise, so this is not a tuning problem and should not be chased as one.

    Record the prototype ladder and what each one proved. Buffering the
    producer removes the entire sexyz-specific penalty -- 115.8 MB/s at 1.0 CPU-second, exactly the engine ceiling -- but six variants now fail the
    3x error-injection gate that the shipped per-byte sender passes. Two
    results are worth keeping: rate-capping the batched sender to the
    shipped sender's own 11 MB/s still fails while the shipped sender passes
    3/3, so it is not an artifact of the higher data rate; and going single-threaded with a buffered send_byte holds full speed, drops
    context switches to lsz's level, and reaches 2/3, leaving blocking
    sendbuf() as the one missing piece. The recommendation is now what lrz actually is: single-threaded, buffered, non-blocking output with select
    on both directions.

    Also note the failure modes that cost time to rediscover (a void flush
    callback swallowing a failed write, a sticky error latch spinning on zmodem_send_raw ERROR, position accounting desync) and that a
    single-stream localhost benchmark cannot see per-byte CPU wins above
    ~100 MB/s -- two of Deuce's optimizations measure zero here because his
    six interleaved 1 GiB transfers are CPU-saturated and this is not.

    No code changes: all prototypes were measured out-of-tree and discarded.
    Refs #1195, #1196.

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)