perf(linux): batch TUN reads and trim message cleanup#139
Open
tionis wants to merge 2 commits into
Open
Conversation
There was a problem hiding this comment.
Pull request overview
This PR improves Linux packet-rate performance by batching TUN reads (blocking for the first packet, then draining immediately available packets) and by reducing per-send cleanup work in the standard UDP bind’s pooled message descriptors.
Changes:
- Refactors Linux TUN packet decoding into a reusable helper and adds a drain loop using
RawConn.Control+ nonblockingunix.Read. - Adds a Linux-only socket-based test to validate one- and multi-packet drain behavior.
- Optimizes
StdNetBindpooled message cleanup to reset only descriptors used by the operation (including across UDP GSO fallback retries).
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| polyamide/tun/tun_linux.go | Adds reusable packet read helper and drains additional immediately-available packets via nonblocking reads. |
| polyamide/tun/tun_linux_test.go | Adds Linux test validating the “read then drain” batching behavior. |
| polyamide/conn/bind_std.go | Limits pooled message cleanup to only the descriptors used by the current send/receive operation. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Improve Linux packet-rate performance by preserving batches across the TUN and
UDP send paths.
The Linux TUN reader now blocks for the first packet and then drains immediately
available packets until the caller's batch is full or the descriptor returns
EAGAIN. This introduces no batching timer.The standard network bind also resets only the pooled message descriptors that
were used by the current operation instead of walking all 128 entries after
every send.
Changes
RawConn.Controlso the descriptorremains valid across concurrent close operations.
error behavior.
retry path.
Performance
Tests ran over a gigabit Ethernet switch from Normandy, an x86_64 Debian laptop,
to Natanus, a Raspberry Pi 5 running Debian, using a direct Nylon route.
Each UDP workload used four iperf3 streams. Delivered throughput accounts for
reported packet loss.
For the 64-byte workload, delivered throughput improved by approximately 221%.
Normal-packet UDP improved by approximately 89%. TCP remained within the
bracketing baseline range.
The changes were also tested separately:
82–93 Mbit/s;
approximately 97–98 Mbit/s.
Latency and CPU
The TUN drain has no timer: after the first blocking read it only consumes
packets already queued by the kernel.
Repeated idle probes remained in the same sub-millisecond range. Stable samples
had average RTTs around 0.5–0.7 ms, with no consistent candidate regression.
The baseline processed only about 30 Mbit/s of the offered small-packet traffic
and used roughly 30% of one CPU core. The optimized path processed approximately
87 Mbit/s during profiling and used roughly 88% of one core. CPU use therefore
scaled with useful delivered traffic rather than remaining idle while packets
were dropped.
The optimized profile showed:
Multiqueue TUN support may be useful beyond the tested packet rate, but it is
more invasive and is intentionally outside this PR.
Validation
go test ./...suite passes.go test -race ./polyamide/tunpasses.available packet boundaries without waiting for future packets.
git diff --checkpasses.