From b0835fab5e832f444f8cf4f434bfe44e6d905802 Mon Sep 17 00:00:00 2001 From: Tom Thorogood Date: Sun, 30 Dec 2018 20:58:48 +1030 Subject: [PATCH] Reduce allocations in ReverseAddr (#872) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add ReverseAddr benchmarks * Eliminate buffer allocation in ReverseAddr for v6 When the size of a slice is constant it can be allocated on the stack rather than the heap. name old time/op new time/op delta ReverseAddr/IP4-12 175ns ± 5% 173ns ± 4% ~ (p=0.323 n=10+10) ReverseAddr/IP6-12 364ns ±14% 218ns ±24% -40.12% (p=0.000 n=10+10) name old alloc/op new alloc/op delta ReverseAddr/IP4-12 51.0B ± 0% 51.0B ± 0% ~ (all equal) ReverseAddr/IP6-12 176B ± 0% 96B ± 0% -45.45% (p=0.000 n=10+10) name old allocs/op new allocs/op delta ReverseAddr/IP4-12 3.00 ± 0% 3.00 ± 0% ~ (all equal) ReverseAddr/IP6-12 3.00 ± 0% 2.00 ± 0% -33.33% (p=0.000 n=10+10) * Reduce allocations in ReverseAddr for v4 name old time/op new time/op delta ReverseAddr/IP4-12 173ns ± 4% 140ns ±13% -18.97% (p=0.000 n=10+10) ReverseAddr/IP6-12 218ns ±24% 218ns ±22% ~ (p=0.838 n=10+10) name old alloc/op new alloc/op delta ReverseAddr/IP4-12 51.0B ± 0% 48.0B ± 0% -5.88% (p=0.000 n=10+10) ReverseAddr/IP6-12 96.0B ± 0% 96.0B ± 0% ~ (all equal) name old allocs/op new allocs/op delta ReverseAddr/IP4-12 3.00 ± 0% 2.00 ± 0% -33.33% (p=0.000 n=10+10) ReverseAddr/IP6-12 2.00 ± 0% 2.00 ± 0% ~ (all equal) * Compare returned address in BenchmarkReverseAddr --- defaults.go | 15 +++++++++++---- dns_bench_test.go | 26 ++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/defaults.go b/defaults.go index 1778b1ca..15fd8c02 100644 --- a/defaults.go +++ b/defaults.go @@ -244,12 +244,19 @@ func ReverseAddr(addr string) (arpa string, err error) { if ip == nil { return "", &Error{err: "unrecognized address: " + addr} } - if ip.To4() != nil { - return strconv.Itoa(int(ip[15])) + "." + strconv.Itoa(int(ip[14])) + "." + strconv.Itoa(int(ip[13])) + "." + - strconv.Itoa(int(ip[12])) + ".in-addr.arpa.", nil + if v4 := ip.To4(); v4 != nil { + buf := make([]byte, 0, net.IPv4len*4+len("in-addr.arpa.")) + // Add it, in reverse, to the buffer + for i := len(v4) - 1; i >= 0; i-- { + buf = strconv.AppendInt(buf, int64(v4[i]), 10) + buf = append(buf, '.') + } + // Append "in-addr.arpa." and return (buf already has the final .) + buf = append(buf, "in-addr.arpa."...) + return string(buf), nil } // Must be IPv6 - buf := make([]byte, 0, len(ip)*4+len("ip6.arpa.")) + buf := make([]byte, 0, net.IPv6len*4+len("ip6.arpa.")) // Add it, in reverse, to the buffer for i := len(ip) - 1; i >= 0; i-- { v := ip[i] diff --git a/dns_bench_test.go b/dns_bench_test.go index d1f1002a..a34fe994 100644 --- a/dns_bench_test.go +++ b/dns_bench_test.go @@ -342,3 +342,29 @@ func BenchmarkIdGeneration(b *testing.B) { _ = id() } } + +func BenchmarkReverseAddr(b *testing.B) { + b.Run("IP4", func(b *testing.B) { + for n := 0; n < b.N; n++ { + addr, err := ReverseAddr("192.0.2.1") + if err != nil { + b.Fatal(err) + } + if expect := "1.2.0.192.in-addr.arpa."; addr != expect { + b.Fatalf("invalid reverse address, expected %q, got %q", expect, addr) + } + } + }) + + b.Run("IP6", func(b *testing.B) { + for n := 0; n < b.N; n++ { + addr, err := ReverseAddr("2001:db8::68") + if err != nil { + b.Fatal(err) + } + if expect := "8.6.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa."; addr != expect { + b.Fatalf("invalid reverse address, expected %q, got %q", expect, addr) + } + } + }) +}