Skip to content

feat: support with_low_memory TCP storage policy - #3

Open
TokenPLS wants to merge 1 commit into
MetaCubeX:masterfrom
TokenPLS:tcp-low-memory
Open

TokenPLS wants to merge 1 commit into
MetaCubeX:masterfrom
TokenPLS:tcp-low-memory

Conversation

@TokenPLS

Copy link
Copy Markdown

Hako already uses with_low_memory for its iOS/tvOS core slices. Its iOS
packet-tunnel extension targets a 50 MiB engineering budget, but shrinking
configured TCP window limits alone does not release backing retained by
idle connections. This change makes MIPS honor the existing build tag for
TCP storage retention, without adding a runtime API.

Changes

  • Reduce the minimum first send allocation from 2 KiB to 1 KiB.
  • Retain at most one 16 KiB acknowledged send chunk instead of 32 KiB.
  • Retain at most 32 drained receive-metadata slots instead of 64.
  • Avoid reusing an undersized small spare when that would require another
    16 KiB chunk for a small write's tail. Allocate one fitted first chunk instead.

Automatic receive/send growth, advertised windows, active data, socket
options and retransmission behavior retain their existing semantics.
Common payload/metadata reuse remains enabled. Ordinary builds keep the
existing constants; the extra small-spare condition compiles out.

iPad evidence

An independent Debug App on a physical iPad Pro ran three fresh-process
repetitions per build, with alternating baseline/candidate order. Two MIPS
stacks maintained 256 connection pairs using Hako's 32 KiB initial / 128 KiB
maximum socket settings. The workload included tiny messages, ordinary small
messages, repeated 32 KiB messages, latency samples, and an identical 1 GiB
bidirectional payload transfer. All six runs completed and all connections
still transferred after the stream.

Median measurement Baseline with_low_memory
Idle live Go heap after small messages 4.68 MiB 4.31 MiB
Idle live Go heap after repeated 32 KiB messages 16.19 MiB 8.08 MiB
Physical footprint at the latter boundary 51.74 MiB 40.19 MiB
Fixed-byte stream throughput, both directions combined 2.61 Gbps 2.71 Gbps
Process CPU seconds per GB 2.324 2.418
Small-request p95 round-trip latency 47.67 us 43.29 us

Throughput uses decimal Gbps (10^9 bits/s) and counts both echoed payload
directions. For this symmetric echo workload, each direction therefore
accounts for approximately 1.31 and 1.35 Gbps, respectively. These are not
separate upload/download saturation tests and cannot be compared directly
with one-way benchmark charts.

The approximately 8.11 MiB live-heap saving is specific to the repeated-32-KiB
workload and its 512 TCP endpoints. CPU cost and allocation traffic per byte
increased by about 4%. The throughput/latency sample does not establish a speed
improvement. Both arms used explicit GC for idle accounting; the implementation
never forces GC. This is App process evidence, not NetworkExtension, PacketFlow,
Internet, battery, or extension termination-risk evidence.

Validation

  • Root race suite and vet, ordinary and low-memory builds: passed.
  • Linux/Windows amd64 builds, both variants: passed.
  • Full gVisor interoperability suite, both variants, GOMAXPROCS=2: passed
    in serial, non-race runs (rechecked during review).
  • Regression tests first reproduced excessive idle backing and the undersized
    spare edge case, then passed with the implementation.
  • Fifteen affected ordinary-build functions matched baseline instructions
    after address-relocation normalization on Go 1.26.5 darwin/arm64.
    No stack or connection fields were added. This is not whole-binary identity
    or a performance guarantee for every compiler/architecture.

During the latest review, both complete gVisor race suites were run
concurrently with GOMAXPROCS=4. Both encountered IPv4 MTU-68 and some
custom-congestion-control timeouts and eventually exceeded the three-minute
suite limit. The root-module race suites passed for both builds. The complete
interop race result is unresolved and is not reported as green.

Earlier MTU-68 instability also reproduced on the unmodified baseline. This
does not establish the cause of the latest failures; this patch does not
claim to resolve them. Serial non-race passes are not a substitute for race
passes.

See LOW_MEMORY.md for the policy, reproduction details, measurements and
limitations. Baseline: ba762df4c91d6f9bddf82062afb0d40aa1352687.

Reduce idle TCP backing retention and the minimum first-send allocation
under the existing with_low_memory build convention. Preserve default-build
constants, flow control, live payload ownership and automatic growth.
Avoid an undersized small spare creating a 16 KiB tail allocation.

Add focused cache/reuse regression coverage, memory-profile benchmarks and
physical-iPad comparison results with their workload and CPU-cost limits.

Validation: root race and vet pass in both build modes. Full gVisor interop
passes serially without race at GOMAXPROCS=2. Concurrent full interop race
runs at GOMAXPROCS=4 timed out in both modes; this remains unresolved and
is documented rather than counted as a pass.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant