From 6c59355acc89a59c90b73e4c29541d8d9d373732 Mon Sep 17 00:00:00 2001 From: Sahil Sojitra Date: Sat, 11 Jul 2026 15:12:45 +0530 Subject: [PATCH 1/2] perf: preallocate slices on swarm and protocol hot paths --- core/protocol/id.go | 12 ++++++------ p2p/host/autonat/dialpolicy.go | 2 +- p2p/host/autorelay/addrsplosion.go | 3 ++- p2p/host/basic/addrs_manager.go | 6 ++++++ p2p/net/swarm/dial_ranker.go | 3 ++- p2p/net/swarm/dial_worker.go | 5 ++--- p2p/net/swarm/swarm.go | 5 ++++- p2p/net/swarm/swarm_dial.go | 6 +++--- p2p/protocol/identify/id.go | 3 +++ 9 files changed, 29 insertions(+), 16 deletions(-) diff --git a/core/protocol/id.go b/core/protocol/id.go index 9df3b5bcf1..78f9edf78c 100644 --- a/core/protocol/id.go +++ b/core/protocol/id.go @@ -11,9 +11,9 @@ const ( // ConvertFromStrings is a convenience function that takes a slice of strings and // converts it to a slice of protocol.ID. func ConvertFromStrings(ids []string) (res []ID) { - res = make([]ID, 0, len(ids)) - for _, id := range ids { - res = append(res, ID(id)) + res = make([]ID, len(ids)) + for i, id := range ids { + res[i] = ID(id) } return res } @@ -21,9 +21,9 @@ func ConvertFromStrings(ids []string) (res []ID) { // ConvertToStrings is a convenience function that takes a slice of protocol.ID and // converts it to a slice of strings. func ConvertToStrings(ids []ID) (res []string) { - res = make([]string, 0, len(ids)) - for _, id := range ids { - res = append(res, string(id)) + res = make([]string, len(ids)) + for i, id := range ids { + res[i] = string(id) } return res } diff --git a/p2p/host/autonat/dialpolicy.go b/p2p/host/autonat/dialpolicy.go index 9615229559..06cb015bba 100644 --- a/p2p/host/autonat/dialpolicy.go +++ b/p2p/host/autonat/dialpolicy.go @@ -58,7 +58,7 @@ func (d *dialPolicy) skipDial(addr ma.Multiaddr) bool { // public addresses in the list. func (d *dialPolicy) skipPeer(addrs []ma.Multiaddr) bool { localAddrs := d.host.Addrs() - localHosts := make([]net.IP, 0) + localHosts := make([]net.IP, 0, len(localAddrs)) for _, lAddr := range localAddrs { if _, err := lAddr.ValueForProtocol(ma.P_CIRCUIT); err != nil && manet.IsPublicAddr(lAddr) { lIP, err := manet.ToIP(lAddr) diff --git a/p2p/host/autorelay/addrsplosion.go b/p2p/host/autorelay/addrsplosion.go index 13e6274b71..b4c5756b14 100644 --- a/p2p/host/autorelay/addrsplosion.go +++ b/p2p/host/autorelay/addrsplosion.go @@ -13,7 +13,8 @@ import ( // best address for the relay. Instead we should rely on the addresses provided by the // relay in response to the reservation request. func cleanupAddressSet(addrs []ma.Multiaddr) []ma.Multiaddr { - var public, private []ma.Multiaddr + public := make([]ma.Multiaddr, 0, len(addrs)) + private := make([]ma.Multiaddr, 0, len(addrs)) for _, a := range addrs { if isRelayAddr(a) { diff --git a/p2p/host/basic/addrs_manager.go b/p2p/host/basic/addrs_manager.go index c160291b4a..63558d243c 100644 --- a/p2p/host/basic/addrs_manager.go +++ b/p2p/host/basic/addrs_manager.go @@ -704,6 +704,12 @@ func areAddrsDifferent(prev, current []ma.Multiaddr) bool { // diffAddrs diffs prev and current addrs and returns added, maintained, and removed addrs. // Both prev and current are expected to be sorted using ma.Compare() func diffAddrs(prev, current []ma.Multiaddr) (added, maintained, removed []ma.Multiaddr) { + added = make([]ma.Multiaddr, 0, len(current)) + removed = make([]ma.Multiaddr, 0, len(prev)) + + minLen := min(len(current), len(prev)) + maintained = make([]ma.Multiaddr, 0, minLen) + i, j := 0, 0 for i < len(prev) && j < len(current) { cmp := prev[i].Compare(current[j]) diff --git a/p2p/net/swarm/dial_ranker.go b/p2p/net/swarm/dial_ranker.go index 302838e638..f7326ef734 100644 --- a/p2p/net/swarm/dial_ranker.go +++ b/p2p/net/swarm/dial_ranker.go @@ -79,6 +79,7 @@ func NoDelayDialRanker(addrs []ma.Multiaddr) []network.AddrDelay { // // We dial lowest ports first as they are more likely to be the listen port. func DefaultDialRanker(addrs []ma.Multiaddr) []network.AddrDelay { + totalAddrs := len(addrs) relay, addrs := filterAddrs(addrs, isRelayAddr) pvt, addrs := filterAddrs(addrs, manet.IsPrivateAddr) public, addrs := filterAddrs(addrs, func(a ma.Multiaddr) bool { return isProtocolAddr(a, ma.P_IP4) || isProtocolAddr(a, ma.P_IP6) }) @@ -89,7 +90,7 @@ func DefaultDialRanker(addrs []ma.Multiaddr) []network.AddrDelay { relayOffset = RelayDelay } - res := make([]network.AddrDelay, 0, len(addrs)) + res := make([]network.AddrDelay, 0, totalAddrs) res = append(res, getAddrDelay(pvt, PrivateTCPDelay, PrivateQUICDelay, PrivateOtherDelay, 0)...) res = append(res, getAddrDelay(public, PublicTCPDelay, PublicQUICDelay, PublicOtherDelay, 0)...) res = append(res, getAddrDelay(relay, PublicTCPDelay, PublicQUICDelay, PublicOtherDelay, relayOffset)...) diff --git a/p2p/net/swarm/dial_worker.go b/p2p/net/swarm/dial_worker.go index 88017325a1..0b29a2d21e 100644 --- a/p2p/net/swarm/dial_worker.go +++ b/p2p/net/swarm/dial_worker.go @@ -208,9 +208,8 @@ loop: // If they have errored, record the error in pr. If they have succeeded, // respond with the connection. // If they are pending, add them to tojoin. - // If we haven't seen any of the addresses before, add them to todial. - var todial []ma.Multiaddr - var tojoin []*addrDial + todial := make([]ma.Multiaddr, 0, len(addrRanking)) + tojoin := make([]*addrDial, 0, len(addrRanking)) for _, adelay := range addrRanking { ad, ok := w.trackedDials[string(adelay.Addr.Bytes())] diff --git a/p2p/net/swarm/swarm.go b/p2p/net/swarm/swarm.go index d73709ef07..7afcdcba1b 100644 --- a/p2p/net/swarm/swarm.go +++ b/p2p/net/swarm/swarm.go @@ -896,7 +896,6 @@ func (r ResolverFromMaDNS) ResolveDNSAddr(ctx context.Context, expectedPeerID pe if recursionLimit <= 0 { return []ma.Multiaddr{maddr}, nil } - var resolved, toResolve []ma.Multiaddr addrs, err := r.Resolve(ctx, maddr) if err != nil { return nil, err @@ -905,6 +904,10 @@ func (r ResolverFromMaDNS) ResolveDNSAddr(ctx context.Context, expectedPeerID pe addrs = addrs[:outputLimit] } + resolved := make([]ma.Multiaddr, 0, len(addrs)) + toResolve := make([]ma.Multiaddr, 0, len(addrs)) + + for _, addr := range addrs { if startsWithDNSADDR(addr) { toResolve = append(toResolve, addr) diff --git a/p2p/net/swarm/swarm_dial.go b/p2p/net/swarm/swarm_dial.go index b180bf489e..1b23a17013 100644 --- a/p2p/net/swarm/swarm_dial.go +++ b/p2p/net/swarm/swarm_dial.go @@ -352,7 +352,7 @@ type resolveErr struct { func chainResolvers(ctx context.Context, addrs []ma.Multiaddr, outputLimit int, resolvers []resolver) ([]ma.Multiaddr, []resolveErr) { nextAddrs := make([]ma.Multiaddr, 0, len(addrs)) - errs := make([]resolveErr, 0) + errs := make([]resolveErr, 0, len(addrs)) for _, r := range resolvers { for _, a := range addrs { if !r.canResolve(a) { @@ -388,7 +388,7 @@ func (s *Swarm) resolveAddrs(ctx context.Context, pi peer.AddrInfo) []ma.Multiad }, } - var skipped []ma.Multiaddr + skipped := make([]ma.Multiaddr, 0, len(pi.Addrs)) skipResolver := resolver{ canResolve: func(addr ma.Multiaddr) bool { tpt := s.TransportForDialing(addr) @@ -486,7 +486,7 @@ var quicDraft29DialMatcher = mafmt.And(mafmt.IP, mafmt.Base(ma.P_UDP), mafmt.Bas // know are going to fail or for which we have a better alternative. func (s *Swarm) filterKnownUndialables(p peer.ID, addrs []ma.Multiaddr) (goodAddrs []ma.Multiaddr, addrErrs []TransportError) { lisAddrs, _ := s.InterfaceListenAddresses() - var ourAddrs []ma.Multiaddr + ourAddrs := make([]ma.Multiaddr, 0, len(lisAddrs)) for _, addr := range lisAddrs { // we're only sure about filtering out /ip4 and /ip6 addresses, so far ma.ForEach(addr, func(c ma.Component) bool { diff --git a/p2p/protocol/identify/id.go b/p2p/protocol/identify/id.go index 4fde9cd331..bc66402127 100644 --- a/p2p/protocol/identify/id.go +++ b/p2p/protocol/identify/id.go @@ -703,6 +703,9 @@ func (ids *idService) getSignedRecord(snapshot *identifySnapshot) []byte { // diff takes two slices of strings (a and b) and computes which elements were added and removed in b func diff(a, b []protocol.ID) (added, removed []protocol.ID) { + added = make([]protocol.ID, 0, len(b)) + removed = make([]protocol.ID, 0, len(a)) + // This is O(n^2), but it's fine because the slices are small. for _, x := range b { var found bool From bb0dfa6786aa238e3c94c181b06c3c8468cde4f0 Mon Sep 17 00:00:00 2001 From: Sahil Sojitra Date: Sat, 11 Jul 2026 15:38:11 +0530 Subject: [PATCH 2/2] fix lint --- p2p/net/swarm/swarm.go | 1 - 1 file changed, 1 deletion(-) diff --git a/p2p/net/swarm/swarm.go b/p2p/net/swarm/swarm.go index 7afcdcba1b..9300936ff3 100644 --- a/p2p/net/swarm/swarm.go +++ b/p2p/net/swarm/swarm.go @@ -907,7 +907,6 @@ func (r ResolverFromMaDNS) ResolveDNSAddr(ctx context.Context, expectedPeerID pe resolved := make([]ma.Multiaddr, 0, len(addrs)) toResolve := make([]ma.Multiaddr, 0, len(addrs)) - for _, addr := range addrs { if startsWithDNSADDR(addr) { toResolve = append(toResolve, addr)