• docs/zmodem_comparison.md

    From Rob Swindell (on Debian Linux)@VERT to Git commit to main/sbbs/master on Thursday, July 23, 2026 23:03:46
    https://gitlab.synchro.net/main/sbbs/-/commit/7471d1b776cb2d7ea274a41e
    Added Files:
    docs/zmodem_comparison.md
    Log Message:
    docs: add ZMODEM implementation comparison (sexyz vs lrzsz vs rzsz)

    A performance, scalability, and robustness analysis of Synchronet's ZMODEM (sexyz + the shared zmodem.c, which SyncTERM also uses) benchmarked against lrzsz 0.12.21rc and Chuck Forsberg's final rzsz 3.73 (modern branch).

    Headline findings, all empirically measured:

    - sexyz's sender is ~25x slower than lrzsz's lsz on a fast link (~8 vs
    ~204 MB/s), from two stacked overheads isolated by linking the real
    zmodem.o behind two send paths: zmodem.c's per-byte callback + escape +
    CRC design caps any sender at ~26 MB/s (shared, so SyncTERM inherits it),
    and sexyz.c's ring-buffer + output-thread drops that a further ~3x to
    ~8 MB/s (sexyz-only; a futex storm + ~84-byte writes). SyncTERM avoids
    the second layer, so its upload runs ~26 MB/s.
    - A windowed (-w) send hangs the instant the file offset crosses 2 GiB:
    zmodem.c narrows transmit-window/ACK positions to signed int32_t. Shared
    with SyncTERM. The data path (fseeko/int64) is otherwise 64-bit clean;
    4 GiB is a hard protocol ceiling (32-bit wire position field).
    - sexyz's receiver is fine past 2 GB; Forsberg's sender runs ~92 MB/s but
    its receiver won't complete headlessly (serial-tty assumptions).

    Includes a conditions matrix (block size, CRC, latency, bandwidth
    asymmetry, injected errors) and per-finding attribution to sexyz.c vs the shared zmodem.c vs SyncTERM's term.c. Relates to the sexyz-throughput and 2-GiB-window GitLab issues.

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian Linux)@VERT to Git commit to main/sbbs/master on Thursday, July 23, 2026 23:03:46
    https://gitlab.synchro.net/main/sbbs/-/commit/f29244a40663ce7f99d3e4e6
    Modified Files:
    docs/zmodem_comparison.md
    Log Message:
    docs: note the sexyz SINGLE_THREADED build is not a throughput fix

    Document that sexyz.c:84 still carries a source-level
    `#define SINGLE_THREADED FALSE` (no makefile toggle), but its
    single-threaded send_byte (sexyz.c:682) writes one byte per write()
    syscall via sendbuf() Ä trading the two-thread futex storm for a
    write-syscall storm, generally worse. Add a three-way send-architecture
    table (threaded / single-threaded / buffered) and a recommendation caveat:
    the fix is output buffering (flush per subpacket, as SyncTERM's term.c
    does), not thread count.

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian Linux)@VERT to Git commit to main/sbbs/master on Thursday, July 23, 2026 23:03:46
    https://gitlab.synchro.net/main/sbbs/-/commit/5c0e802235bfc797afbdadb1
    Modified Files:
    docs/zmodem_comparison.md
    Log Message:
    docs/zmodem: correct throughput magnitudes to steady-state; version-tag

    The initial throughput figures were measured on 32 MB transfers whose
    short duration was dominated by per-transfer startup, which deflated and distorted the rates. Re-measured at 256 MB steady-state:

    - sexyz sender was ~18x (not ~25x) slower than lsz: ~11 vs ~204 MB/s.
    - The two layers are ~7.5x sexyz.c (ring per-byte, 85->11, now fixed by
    the send-batching change -> ~66 MB/s) and ~2.4x zmodem.c (per-byte send
    design, 204->85, shared with SyncTERM), not the ~3x/~8x quoted before.
    - The SyncTERM-model (ztx_buf) sender runs ~85 MB/s, not ~26; sexyz
    receiver ~130; Forsberg sender ~107.

    The mechanism findings (futex storm, ~84-byte writes, ring-per-byte) were unaffected -- only the magnitudes changed.

    Also: tag every number to a component version (sexyz.c revision 3.3->3.4, zmodem.c rev 2.2->2.3) since Synchronet's side is actively changing, and
    mark the recommendations with status (Fix A and the 2 GB fix done, Fix B
    and the adaptive-block-length model pending).

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian Linux)@VERT to Git commit to main/sbbs/master on Thursday, July 23, 2026 23:03:46
    https://gitlab.synchro.net/main/sbbs/-/commit/9c73c787d0f036e0eff35085
    Modified Files:
    docs/zmodem_comparison.md
    Log Message:
    docs/zmodem: record that the send-batching fixes were reverted

    Multi-run error-recovery testing showed both batching prototypes regress
    error recovery under heavy injected corruption: the shipped per-byte
    sender passes 3/3 (~50 s), the Fix A prototype (batch spans into the ring, sexyz.c) timed out 0/3, and the Fix B prototype (send_buf span callback, zmodem.c) hard-failed 1/3. Root cause: batching a whole subpacket before
    one blocking flush starves the back-channel during retransmit storms (the sender is stuck in the flush and can't service ZRPOS), stalling the
    transfer; the original per-byte-to-ring keeps the pipeline draining and
    stays responsive.

    Both prototypes were reverted. The only shipped code change remains the
    2 GB signed-position fix in zmodem.c (rev 2.3, GitLab #1196); sexyz.c is unchanged (stays 3.3). The ~66/~88 MB/s figures are retained in the doc, relabeled as reverted prototypes, because the root-cause analysis (ring per-byte -> futex storm / 84-byte writes) is still valid and the eventual
    fix must service the back-channel while sending.

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net