Skip to content

Commit 39fcf8b

Browse files
erikdubbelboerbradfitz
authored andcommitted
net: use bytes.Equal instead of bytesEqual
bytes.Equal is written in assembly and is slightly faster than the current Go bytesEqual from the net package. benchcmp: benchmark old ns/op new ns/op delta BenchmarkIPCompare4-8 7.74 7.01 -9.43% BenchmarkIPCompare6-8 8.47 6.86 -19.01% Change-Id: I2a7ad35867489b46f0943aef5776a2fe1b46e2df Reviewed-on: https://go-review.googlesource.com/36850 Reviewed-by: Brad Fitzpatrick <[email protected]> Run-TryBot: Brad Fitzpatrick <[email protected]> TryBot-Result: Gobot Gobot <[email protected]>
1 parent 61bf0d1 commit 39fcf8b

File tree

2 files changed

+35
-11
lines changed

2 files changed

+35
-11
lines changed

src/net/ip.go

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
package net
1414

15+
import _ "unsafe" // for go:linkname
16+
1517
// IP address lengths (bytes).
1618
const (
1719
IPv4len = 4
@@ -381,17 +383,9 @@ func (ip IP) Equal(x IP) bool {
381383
return false
382384
}
383385

384-
func bytesEqual(x, y []byte) bool {
385-
if len(x) != len(y) {
386-
return false
387-
}
388-
for i, b := range x {
389-
if y[i] != b {
390-
return false
391-
}
392-
}
393-
return true
394-
}
386+
// bytes.Equal is implemented in runtime/asm_$goarch.s
387+
//go:linkname bytesEqual bytes.Equal
388+
func bytesEqual(x, y []byte) bool
395389

396390
func (ip IP) matchAddrFamily(x IP) bool {
397391
return ip.To4() != nil && x.To4() != nil || ip.To16() != nil && ip.To4() == nil && x.To16() != nil && x.To4() == nil

src/net/ip_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package net
66

77
import (
88
"bytes"
9+
"math/rand"
910
"reflect"
1011
"runtime"
1112
"testing"
@@ -645,3 +646,32 @@ func TestIPAddrScope(t *testing.T) {
645646
}
646647
}
647648
}
649+
650+
func BenchmarkIPEqual(b *testing.B) {
651+
b.Run("IPv4", func(b *testing.B) {
652+
benchmarkIPEqual(b, IPv4len)
653+
})
654+
b.Run("IPv6", func(b *testing.B) {
655+
benchmarkIPEqual(b, IPv6len)
656+
})
657+
}
658+
659+
func benchmarkIPEqual(b *testing.B, size int) {
660+
ips := make([]IP, 1000)
661+
for i := range ips {
662+
ips[i] = make(IP, size)
663+
rand.Read(ips[i])
664+
}
665+
// Half of the N are equal.
666+
for i := 0; i < b.N/2; i++ {
667+
x := ips[i%len(ips)]
668+
y := ips[i%len(ips)]
669+
x.Equal(y)
670+
}
671+
// The other half are not equal.
672+
for i := 0; i < b.N/2; i++ {
673+
x := ips[i%len(ips)]
674+
y := ips[(i+1)%len(ips)]
675+
x.Equal(y)
676+
}
677+
}

0 commit comments

Comments
 (0)