From a2234b6a2ae2eba7ae95d57c9d90a7facc553844 Mon Sep 17 00:00:00 2001 From: zarazaex69 Date: Sun, 3 May 2026 16:10:32 +0300 Subject: [PATCH] perf: optimize write polling and kcp interval for lower latency --- internal/muxconn/conn.go | 17 +++++++++++++++-- internal/transport/vp8channel/kcp.go | 13 ++++++++----- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/internal/muxconn/conn.go b/internal/muxconn/conn.go index 3f651a5..c5d6088 100644 --- a/internal/muxconn/conn.go +++ b/internal/muxconn/conn.go @@ -19,6 +19,7 @@ import ( "errors" "fmt" "io" + "runtime" "sync" "time" @@ -81,14 +82,26 @@ func (c *Conn) Read(p []byte) (int, error) { // Write encrypts p and ships it to the link as a single message. Blocks while // the link signals back-pressure. func (c *Conn) Write(p []byte) (int, error) { - for { + // Spin briefly first - on a healthy link CanSend usually clears within + // well under a millisecond, so a 10ms sleep adds visible per-frame + // latency to interactive request/response traffic. Fall back to a + // modest sleep only if the link is truly congested. + const ( + fastSpinAttempts = 200 + slowPollDelay = 2 * time.Millisecond + ) + for attempt := 0; ; attempt++ { if c.isClosed() { return 0, ErrClosed } if c.ln.CanSend() { break } - time.Sleep(10 * time.Millisecond) + if attempt < fastSpinAttempts { + runtime.Gosched() + continue + } + time.Sleep(slowPollDelay) } enc, err := c.cipher.Encrypt(p) diff --git a/internal/transport/vp8channel/kcp.go b/internal/transport/vp8channel/kcp.go index f3988ef..9140586 100644 --- a/internal/transport/vp8channel/kcp.go +++ b/internal/transport/vp8channel/kcp.go @@ -65,11 +65,14 @@ func startKCP(out chan<- []byte, onData func([]byte), epochHdr [epochHdrLen]byte return nil, fmt.Errorf("kcp new conn: %w", err) } - // Aggressive ARQ tuning: nodelay=1, interval=10ms, fast resend=2, no - // congestion control. This is the standard "turbo" preset used by KCP - // tunnels on lossy networks (shadowsocks, kcptun) and is the whole point - // of choosing KCP over SCTP. - sess.SetNoDelay(1, 10, 2, 1) + // Aggressive ARQ tuning: nodelay=1, interval=5ms, fast resend=2, no + // congestion control. The 5ms tick (vs the kcptun-default 10ms) halves + // the worst-case scheduling latency in each direction, which matters a + // lot for interactive workloads (SOCKS5 + HTTP request needs ~3 RTTs + // before the first byte of the response shows up). Below 5ms the + // CPU cost of the KCP update loop starts climbing without much + // additional latency benefit. + sess.SetNoDelay(1, 5, 2, 1) sess.SetWindowSize(kcpSndWnd, kcpRcvWnd) sess.SetMtu(kcpMTU) sess.SetACKNoDelay(true)