From f2cd6d60aee86f5dd582a4abf26a70cff44589b7 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 4 May 2022 21:45:02 +0200 Subject: [PATCH] net/netip: reduce allocations in Addr.String for v4-in-v6 addresses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ip.Unmap will always return an Addr with ip.z == z4 in case of an v4-in-v6 address. Thus, Addr.string4 can be called directly without the additional indirection. name old time/op new time/op delta IPString/v6_v4-4 108ns ± 3% 74ns ± 4% -31.23% (p=0.000 n=9+10) IPStringExpanded/v6_v4-4 89.6ns ± 6% 77.2ns ± 3% -13.91% (p=0.000 n=10+10) AddrPortString/v6_v4-4 253ns ± 8% 197ns ± 3% -22.13% (p=0.000 n=10+10) name old alloc/op new alloc/op delta IPString/v6_v4-4 40.0B ± 0% 24.0B ± 0% -40.00% (p=0.000 n=10+10) IPStringExpanded/v6_v4-4 48.0B ± 0% 48.0B ± 0% ~ (all equal) AddrPortString/v6_v4-4 77.0B ± 0% 61.0B ± 0% -20.78% (p=0.000 n=10+10) name old allocs/op new allocs/op delta IPString/v6_v4-4 2.00 ± 0% 1.00 ± 0% -50.00% (p=0.000 n=10+10) IPStringExpanded/v6_v4-4 1.00 ± 0% 1.00 ± 0% ~ (all equal) AddrPortString/v6_v4-4 4.00 ± 0% 3.00 ± 0% -25.00% (p=0.000 n=10+10) Change-Id: Id4affaf7a493aa11579c48721294f2e5889a8bef Reviewed-on: https://go-review.googlesource.com/c/go/+/403914 Run-TryBot: Tobias Klauser TryBot-Result: Gopher Robot Reviewed-by: Dmitri Shuralyov Reviewed-by: Damien Neil Auto-Submit: Tobias Klauser --- src/net/netip/netip.go | 5 ++--- src/net/netip/netip_test.go | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/net/netip/netip.go b/src/net/netip/netip.go index 2c21715af1..5bbab951c5 100644 --- a/src/net/netip/netip.go +++ b/src/net/netip/netip.go @@ -768,11 +768,10 @@ func (ip Addr) String() string { return ip.string4() default: if ip.Is4In6() { - // TODO(bradfitz): this could alloc less. if z := ip.Zone(); z != "" { - return "::ffff:" + ip.Unmap().String() + "%" + z + return "::ffff:" + ip.Unmap().string4() + "%" + z } else { - return "::ffff:" + ip.Unmap().String() + return "::ffff:" + ip.Unmap().string4() } } return ip.string6() diff --git a/src/net/netip/netip_test.go b/src/net/netip/netip_test.go index 35f7cd69e1..9fe7cae6ec 100644 --- a/src/net/netip/netip_test.go +++ b/src/net/netip/netip_test.go @@ -1894,6 +1894,31 @@ func TestNoAllocs(t *testing.T) { test("IPPRefix.Masked", func() { sinkPrefix = MustParsePrefix("1.2.3.4/16").Masked() }) } +func TestAddrStringAllocs(t *testing.T) { + tests := []struct { + name string + ip Addr + wantAllocs int + }{ + {"zero", Addr{}, 0}, + {"ipv4", MustParseAddr("192.168.1.1"), 1}, + {"ipv6", MustParseAddr("2001:db8::1"), 1}, + {"ipv6+zone", MustParseAddr("2001:db8::1%eth0"), 1}, + {"ipv4-in-ipv6", MustParseAddr("::ffff:192.168.1.1"), 1}, + {"ipv4-in-ipv6+zone", MustParseAddr("::ffff:192.168.1.1%eth0"), 1}, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + allocs := int(testing.AllocsPerRun(1000, func() { + sinkString = tc.ip.String() + })) + if allocs != tc.wantAllocs { + t.Errorf("allocs=%d, want %d", allocs, tc.wantAllocs) + } + }) + } +} + func TestPrefixString(t *testing.T) { tests := []struct { ipp Prefix