Skip to content

perf(tunnel): avoid temporary IP strings in UDP map lookups - #3444

Closed
Tunglies wants to merge 1 commit into
MetaCubeX:Alphafrom
Tunglies:perf/udp-lookup-key
Closed

Tunglies wants to merge 1 commit into
MetaCubeX:Alphafrom
Tunglies:perf/udp-lookup-key

Conversation

@Tunglies

Copy link
Copy Markdown

Pure-IP UDP packets currently allocate a temporary address string for each lookup in packetSender.originToTarget. Format the address with netip.Addr.AppendTo into local scratch space and convert it directly in the map lookup, removing that temporary allocation for ordinary IP addresses.

Host precedence, invalid-address handling, persistent map keys, locking, and packet ownership remain unchanged. Long IPv6 zones can grow the temporary slice without truncation. The change is limited to tunnel/connection.go; it adds no pool, cache, dependency, or public API.

Measurements

Measured against 478af2a57c48bdb8e85f6ed93b2c3735e90ceabd on macOS 27.2 / Apple M5 Pro / Go 1.27.3, with identical dependencies. Four paired rounds alternated baseline/candidate order; all measurements ran serially and profiles were collected separately.

The fixture calls the actual processPacket with warmed mappings and a simulated PacketConn. It excludes DNS, socket I/O, and payload copying. The figures below describe processing cost, not end-to-end network throughput.

GOMAXPROCS=4, one worker cycling through 10 destination keys:

Workload Baseline ns/packet, median [range] Patched ns/packet, median [range] Paired time change, median [range] B/packet Allocations/packet
IPv4 64.25 [63.17–65.62] 56.52 [56.03–57.57] −12.0% [−13.3% to −10.3%] 64 → 52 3 → 2
IPv6 82.73 [81.38–83.52] 76.15 [75.90–77.04] −7.4% [−8.8% to −6.7%] 80 → 64 3 → 2
Domain 49.03 [48.12–50.05] 48.90 [47.67–50.03] −0.4% [−3.4% to +2.7%] 52 → 52 2 → 2
Mixed 66.02 [65.17–67.81] 61.11 [60.50–61.65] −7.5% [−10.1% to −5.9%] 64 → 54 —*

Pure workloads use 1400-byte payloads. Mixed traffic is 60% IPv4, 20% IPv6, and 20% domain targets, with 80% 1400-byte, 10% 512-byte, and 10% 64-byte payloads. The smaller payloads belong to the domain cases. Go's integer allocation count truncates the mixed-workload average, so it is omitted here.

Additional runs varied GOMAXPROCS between 1 and 4 and worker count independently between 1 and 4. An initial four-worker domain result was noisy; four longer paired runs gave time changes from −3.0% to +0.2%, without a consistent regression. No domain-path improvement is claimed.

For 30 million mixed packets, three fixed-count paired runs reduced median whole-test-process user+system CPU time from 2.05 s to 1.87 s (−8.8%). Maximum RSS ranges overlapped: 18.64–19.07 MB baseline vs. 18.50–19.14 MB patched. This demonstrates reduced allocation churn, not a demonstrated resident-memory reduction or a general mihomo throughput improvement.

Validation

Baseline and patched semantic fixtures passed for IPv4, IPv6, IPv4-mapped IPv6, ordinary and long zones, host precedence, invalid-address fallback, mapping misses, retained output addresses, reverse mapping, and packet drop/deadline behavior. The patched fixtures passed the race detector; the complete application built successfully for native darwin/arm64.

@Tunglies
Tunglies marked this pull request as ready for review November 10, 2026 07:24
@Tunglies
Tunglies marked this pull request as draft November 10, 2026 07:27
@Tunglies Tunglies closed this Nov 10, 2026
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