]> Cypherpunks repositories - gostls13.git/commitdiff
net: use bytes.Equal instead of bytesEqual
authorErik Dubbelboer <erik@dubbelboer.com>
Thu, 9 Feb 2017 04:54:25 +0000 (12:54 +0800)
committerBrad Fitzpatrick <bradfitz@golang.org>
Mon, 13 Feb 2017 03:45:47 +0000 (03:45 +0000)
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 <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/net/ip.go
src/net/ip_test.go

index db3364c1b317e18f7ff9b6c59820d0d1a0675149..c482ef63035b390ec6451e720c9a26162a0e776f 100644 (file)
@@ -12,6 +12,8 @@
 
 package net
 
+import _ "unsafe" // for go:linkname
+
 // IP address lengths (bytes).
 const (
        IPv4len = 4
@@ -381,17 +383,9 @@ func (ip IP) Equal(x IP) bool {
        return false
 }
 
-func bytesEqual(x, y []byte) bool {
-       if len(x) != len(y) {
-               return false
-       }
-       for i, b := range x {
-               if y[i] != b {
-                       return false
-               }
-       }
-       return true
-}
+// bytes.Equal is implemented in runtime/asm_$goarch.s
+//go:linkname bytesEqual bytes.Equal
+func bytesEqual(x, y []byte) bool
 
 func (ip IP) matchAddrFamily(x IP) bool {
        return ip.To4() != nil && x.To4() != nil || ip.To16() != nil && ip.To4() == nil && x.To16() != nil && x.To4() == nil
index 46551633ce2369b43600079a289764f1578a34ad..f765582cad49f70368cf910f9954c9c689bfca0d 100644 (file)
@@ -6,6 +6,7 @@ package net
 
 import (
        "bytes"
+       "math/rand"
        "reflect"
        "runtime"
        "testing"
@@ -645,3 +646,32 @@ func TestIPAddrScope(t *testing.T) {
                }
        }
 }
+
+func BenchmarkIPEqual(b *testing.B) {
+       b.Run("IPv4", func(b *testing.B) {
+               benchmarkIPEqual(b, IPv4len)
+       })
+       b.Run("IPv6", func(b *testing.B) {
+               benchmarkIPEqual(b, IPv6len)
+       })
+}
+
+func benchmarkIPEqual(b *testing.B, size int) {
+       ips := make([]IP, 1000)
+       for i := range ips {
+               ips[i] = make(IP, size)
+               rand.Read(ips[i])
+       }
+       // Half of the N are equal.
+       for i := 0; i < b.N/2; i++ {
+               x := ips[i%len(ips)]
+               y := ips[i%len(ips)]
+               x.Equal(y)
+       }
+       // The other half are not equal.
+       for i := 0; i < b.N/2; i++ {
+               x := ips[i%len(ips)]
+               y := ips[(i+1)%len(ips)]
+               x.Equal(y)
+       }
+}