Skip to content

p2p: cache per-message ingress gauges to avoid allocs in Peer.handle#21920

Merged
AskAlexSharov merged 2 commits into
mainfrom
alex/p2p_gaug_36
Jun 25, 2026
Merged

p2p: cache per-message ingress gauges to avoid allocs in Peer.handle#21920
AskAlexSharov merged 2 commits into
mainfrom
alex/p2p_gaug_36

Conversation

@AskAlexSharov

Copy link
Copy Markdown
Collaborator

Problem

Peer.handle runs in the per-peer read loop for every inbound subprotocol message. With metrics enabled it did, per message:

m := fmt.Sprintf("%s_%s_%d_%#02x", ingressMeterName, proto.Name, proto.Version, msg.Code-proto.offset)
metrics.GetOrCreateGauge(m).SetUint32(msg.meterSize)
metrics.GetOrCreateGauge(m + "_packets").Set(1)

That allocated, per message: the Sprintf string, the + "_packets" string, two &gauge{} wrappers from GetOrCreateGauge, and the variadic arg boxing — and each GetOrCreateGauge also took a mutex + map lookup. The gauge identity only depends on (proto.Name, proto.Version, relativeCode), all stable for the lifetime of a protoRW.

Change

Cache the gauges per protoRW, indexed by the protocol-relative message code. The first message for a code creates and caches the gauges (preserving the original lazy registration — no zero-valued metrics for codes that never arrive); subsequent messages just index the slice and call Set.

Behavior is identical: same gauge names, same values. Safe without locking because handle only runs in the single per-peer read-loop goroutine and each peer owns its own protoRW instances (confirmed under -race).

Numbers

Benchmarked on the actual code path (benchmem, Apple M4 Max):

allocs/op bytes/op ns/op
Before 5 128 B ~152 ns
After (cache warm) 0 0 B ~3.3 ns

5 allocations → 0 per inbound message, ~46× faster per call.

Tests

  • TestProtoRWMeterIngress — verifies the byte/packet gauges still receive the correct values.
  • TestProtoRWMeterIngressNoAllocs — asserts 0 allocs/op after warmup (regression guard).

@anacrolix anacrolix self-assigned this Jun 22, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to reduce per-inbound-message overhead in Peer.handle when metrics are enabled by caching ingress byte/packet gauges on protoRW and updating them via a helper (meterIngress) rather than performing per-message metric lookup/registration work.

Changes:

  • Replace direct per-message gauge updates in Peer.handle with a protoRW.meterIngress helper.
  • Add protoRW.meterIngress to lazily allocate/cache per-message-code ingress gauges.
  • Add tests verifying gauge values and asserting zero allocations after cache warm-up.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
p2p/peer.go Routes ingress metering through protoRW.meterIngress and adds the caching/lazy-init helper.
p2p/peer_test.go Adds correctness + allocation regression tests for meterIngress.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread p2p/peer.go
@AskAlexSharov AskAlexSharov added this pull request to the merge queue Jun 25, 2026
Merged via the queue into main with commit 0386404 Jun 25, 2026
92 checks passed
@AskAlexSharov AskAlexSharov deleted the alex/p2p_gaug_36 branch June 25, 2026 01:32
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.

4 participants