Skip to content

Reduce allocations in concurrent forwarder selection#2061

Open
zs311521 wants to merge 1 commit into
TechnitiumSoftware:masterfrom
zs311521:perf/forwarder-selection-allocations
Open

Reduce allocations in concurrent forwarder selection#2061
zs311521 wants to merge 1 commit into
TechnitiumSoftware:masterfrom
zs311521:perf/forwarder-selection-allocations

Conversation

@zs311521

Copy link
Copy Markdown

Summary

  • snapshot configured forwarders once per concurrent/no-proxy resolution
  • avoid allocating the two selection lists and async resolution closures when every endpoint is already fresh
  • retain the existing stale-endpoint resolution path unchanged

This is deliberately separate from #2060: it is a hot-path allocation optimization, not a statistics-retention fix.

Why

The global forwarding path currently allocates newForwarders and resolveTasks for every concurrent resolution, even when the configured endpoints are already resolved. That is the common case for long-running forwarders, including concurrent DNS-over-QUIC upstream configurations.

The candidate takes one typed array snapshot first, preserving per-query membership, source order, duplicates, and object identity. It scans that snapshot for stale endpoints. Fresh snapshots pass directly to the existing DnsClient path; if any endpoint is stale—or the configuration is empty—the stock resolution/error path runs with the snapshot.

Proxy and sequential branches are untouched.

Allocation measurement

Release, .NET SDK 10.0.302, selection fragment only (before DnsClient):

Forwarders Current Candidate Saved
2 176 B/op 40 B/op 136 B/op
8 272 B/op 88 B/op 184 B/op
64 1,168 B/op 536 B/op 632 B/op

For the ordinary two-forwarder case this removes 136 B/op from this fragment. It is not presented as a percentage reduction for the whole resolver request.

Verification

  • documented Linux Release publish succeeds
  • equivalence harness covers empty, single and multiple inputs
  • configured order, duplicates, null behavior and object identity preserved
  • membership is stable after caller-owned source mutation
  • mutation during source enumeration still fails rather than promising unsupported concurrent mutation
  • stale ordering and failure behavior preserved
  • proxy and sequential branches bypass the new path
  • git diff --check passes

The stale case pays for the initial snapshot before entering the unchanged resolution path. That small rare-path cost is the tradeoff for a single source observation and stable per-query membership.

@ShreyasZare

Copy link
Copy Markdown
Member

Thanks for the PR. Will evaluate this soon.

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.

2 participants