perf: optimize write polling and kcp interval for lower latency

This commit is contained in:
zarazaex69
2026-05-03 16:10:32 +03:00
parent bca50fa7c9
commit a2234b6a2a
2 changed files with 23 additions and 7 deletions
+15 -2
View File
@@ -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)
+8 -5
View File
@@ -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)