https://gitlab.synchro.net/main/sbbs/-/commit/34af5f34b57436e1430bdf80
Modified Files:
src/sbbs3/sexyz.c
Log Message:
sexyz: buffer the ZMODEM streaming send path (#1195)
The send bottleneck was never the two output threads or the ring -- it
was feeding the ring one byte at a time. send_byte() took the ring mutex
twice per byte while output_thread hot-looped on it, so a 256 MB send
cost 44 CPU-seconds and 1.46 million voluntary context switches and
topped out near 11 MB/s on localhost.
Accumulate bytes into a 4 KB buffer and hand whole spans to the ring
instead. The two-thread architecture, flow control and error handling
are all unchanged; the producer just stops trickling. A 256 MB send now
runs at ~115 MB/s using 0.85 CPU-seconds and 64 K context switches -- the
same throughput a single-threaded rewrite would give, for a fraction of
the change and none of the risk.
Buffering only applies to full ZMODEM streaming. A transmit window or segmented mode (-w, -s) depends on the receiver's acks flowing back as
data is sent; bursty buffered output would fill the window before any ack returns and stall the transfer, so those modes fall through to the
original byte-at-a-time path and are byte-for-byte unchanged.
A fast streaming sender also fills the socket's auto-tuned, possibly multi-megabyte send buffer, so a single line error would cost a ZRPOS retransmission of everything in flight and break error recovery. Bound SO_SNDBUF to the ring size to cap the in-flight backlog (streaming only --
a window already bounds it, and a socket buffer smaller than the window
would fight it). This is applied outside the stdio guard so it takes
effect for a piped socket as well, and [sockopts] can override it for a
high bandwidth-delay link.
Verified against lrz over the bench harness: 256 MB streaming MATCH at
~115 MB/s; the 3x error-injection gate passes 5/5; windowed (-w8192
through -w65536), segmented (-s) and the receive path are unchanged from before; an 8 MB transfer over a 25 ms link matches the byte-at-a-time
sender (both link-bound). No zmodem.c change, so SyncTERM is untouched
(and it already has a buffered send path of its own).
Co-Authored-By: Claude Opus 4.8 (1M context) <
[email protected]>
--- SBBSecho 3.37-Linux
* Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)