net: downloads at tens of megabits, not one

Measured against the host fetching the same 67 MB from Alpine's CDN at
11.5 MB/s, SchOS managed about 120 KB/s. Three causes:

- The receive window reopened when data entered the socket buffer,
  before the reader drained it; lwIP then refused segments and the
  sender waited on retransmission timers. It reopens on read now.
- The e1000 receive ring held 16 frames, so a full window arriving back
  to back lost everything past the sixteenth. 256 now.
- Without window scaling the window stops at 64 KB, one window per
  round trip. Scaling on, 256 KB window, 512 KB socket ring (a power of
  two, which the free-running indices need), copied in blocks.

Now 5.8 MB/s for the same file, and apk update in about two seconds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
This commit is contained in:
Nexoniarz 2026-10-24 15:28:32 +02:00
commit 2c5a278d56
3 changed files with 53 additions and 16 deletions

View file

@ -35,10 +35,12 @@
#define MEMP_NUM_UDP_PCB 8
#define MEMP_NUM_TCP_PCB 16
#define MEMP_NUM_TCP_PCB_LISTEN 8
#define MEMP_NUM_TCP_SEG 64
#define MEMP_NUM_TCP_SEG 256 // a window held out of order
#define MEMP_NUM_ARP_QUEUE 16
#define MEMP_NUM_SYS_TIMEOUT 16
#define PBUF_POOL_SIZE 48
// Enough for a full receive window held out of order, plus the frames in
// flight from the driver: a window of TCP_WND below, in pool-sized pieces.
#define PBUF_POOL_SIZE 256
#define PBUF_POOL_BUFSIZE 1536 // one Ethernet frame plus room
// Protocols. IPv4 only: the driver is proven for it, the QEMU test network is
@ -77,7 +79,17 @@
#define TCP_MSS 1460
#define TCP_SND_BUF (8 * TCP_MSS)
#define TCP_WND (8 * TCP_MSS)
// The receive window, and with it the download speed: one window per round
// trip. Eight segments held a transfer from a CDN to well under a megabyte a
// second; thirty-two, the most that fits in TCP's 16-bit window field, held
// it to 1.5 MB/s at 25 ms -- an eighth of a 100 Mbit line, measured against
// the host fetching the same file. Window scaling (RFC 7323) lifts the 64 KB
// ceiling: the field is shifted by TCP_RCV_SCALE, so 256 KB is advertised as
// 16384 << 4. Every socket's buffer in kernel/net/inet.c is larger than this,
// which is what makes the window an honest promise -- see inet_recv_cb.
#define LWIP_WND_SCALE 1
#define TCP_RCV_SCALE 4
#define TCP_WND (256 * 1024)
#define TCP_SND_QUEUELEN ((4 * TCP_SND_BUF) / TCP_MSS)
#define TCP_LISTEN_BACKLOG 1