]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: use multiplication with overflow check for makeslice
authorMartin Möhrmann <moehrmann@google.com>
Mon, 15 Oct 2018 22:27:42 +0000 (00:27 +0200)
committerMartin Möhrmann <martisch@uos.de>
Tue, 23 Oct 2018 07:23:15 +0000 (07:23 +0000)
This improves performance for slices with an element size larger
than 32 bytes and removes loading a value from the maxElems
array for smaller element sizes.

name                 old time/op  new time/op  delta
MakeSlice/Byte       18.0ns ± 4%  18.0ns ± 2%     ~     (p=0.575 n=20+17)
MakeSlice/Int16      21.8ns ± 2%  21.6ns ± 1%   -0.63%  (p=0.035 n=20+19)
MakeSlice/Int        42.0ns ± 2%  41.6ns ± 1%     ~     (p=0.121 n=20+18)
MakeSlice/Ptr        62.6ns ± 2%  62.4ns ± 2%     ~     (p=0.491 n=20+18)
MakeSlice/Struct/24  57.4ns ± 3%  56.0ns ± 2%   -2.40%  (p=0.000 n=19+19)
MakeSlice/Struct/32  62.1ns ± 2%  60.6ns ± 3%   -2.43%  (p=0.000 n=20+20)
MakeSlice/Struct/40  77.3ns ± 3%  68.9ns ± 3%  -10.91%  (p=0.000 n=20+20)

Updates #21588

Change-Id: Ie12807bf8f77c0e15453413f47e3d7de771b798f
Reviewed-on: https://go-review.googlesource.com/c/142377
Run-TryBot: Martin Möhrmann <martisch@uos.de>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
src/runtime/slice.go
src/runtime/slice_test.go

index 2c5c52a6e63d3c95dd552c0be69a4880418dd218..095ddc5bbd3dbfe0ebfeeeda629980b7345467f4 100644 (file)
@@ -54,21 +54,21 @@ func panicmakeslicecap() {
 }
 
 func makeslice(et *_type, len, cap int) slice {
-       // NOTE: The len > maxElements check here is not strictly necessary,
-       // but it produces a 'len out of range' error instead of a 'cap out of range' error
-       // when someone does make([]T, bignumber). 'cap out of range' is true too,
-       // but since the cap is only being supplied implicitly, saying len is clearer.
-       // See issue 4085.
-       maxElements := maxSliceCap(et.size)
-       if len < 0 || uintptr(len) > maxElements {
-               panicmakeslicelen()
-       }
-
-       if cap < len || uintptr(cap) > maxElements {
+       mem, overflow := math.MulUintptr(et.size, uintptr(cap))
+       if overflow || mem > maxAlloc || len < 0 || len > cap {
+               // NOTE: Produce a 'len out of range' error instead of a
+               // 'cap out of range' error when someone does make([]T, bignumber).
+               // 'cap out of range' is true too, but since the cap is only being
+               // supplied implicitly, saying len is clearer.
+               // See golang.org/issue/4085.
+               mem, overflow := math.MulUintptr(et.size, uintptr(len))
+               if overflow || mem > maxAlloc || len < 0 {
+                       panicmakeslicelen()
+               }
                panicmakeslicecap()
        }
+       p := mallocgc(mem, et, true)
 
-       p := mallocgc(et.size*uintptr(cap), et, true)
        return slice{p, len, cap}
 }
 
index c2dfb7afd19b8f0ad6940ee2aeef0ee9f8157018..0463fc70a764bb8cc8a1de44e5efa6dac046db34 100644 (file)
@@ -10,20 +10,68 @@ import (
 
 const N = 20
 
-func BenchmarkMakeSlice(b *testing.B) {
-       var x []byte
-       for i := 0; i < b.N; i++ {
-               x = make([]byte, 32)
-               _ = x
-       }
-}
-
 type (
        struct24 struct{ a, b, c int64 }
        struct32 struct{ a, b, c, d int64 }
        struct40 struct{ a, b, c, d, e int64 }
 )
 
+func BenchmarkMakeSlice(b *testing.B) {
+       const length = 2
+       b.Run("Byte", func(b *testing.B) {
+               var x []byte
+               for i := 0; i < b.N; i++ {
+                       x = make([]byte, length, 2*length)
+                       _ = x
+               }
+       })
+       b.Run("Int16", func(b *testing.B) {
+               var x []int16
+               for i := 0; i < b.N; i++ {
+                       x = make([]int16, length, 2*length)
+                       _ = x
+               }
+       })
+       b.Run("Int", func(b *testing.B) {
+               var x []int
+               for i := 0; i < b.N; i++ {
+                       x = make([]int, length, 2*length)
+                       _ = x
+               }
+       })
+       b.Run("Ptr", func(b *testing.B) {
+               var x []*byte
+               for i := 0; i < b.N; i++ {
+                       x = make([]*byte, length, 2*length)
+                       _ = x
+               }
+       })
+       b.Run("Struct", func(b *testing.B) {
+               b.Run("24", func(b *testing.B) {
+                       var x []struct24
+                       for i := 0; i < b.N; i++ {
+                               x = make([]struct24, length, 2*length)
+                               _ = x
+                       }
+               })
+               b.Run("32", func(b *testing.B) {
+                       var x []struct32
+                       for i := 0; i < b.N; i++ {
+                               x = make([]struct32, length, 2*length)
+                               _ = x
+                       }
+               })
+               b.Run("40", func(b *testing.B) {
+                       var x []struct40
+                       for i := 0; i < b.N; i++ {
+                               x = make([]struct40, length, 2*length)
+                               _ = x
+                       }
+               })
+
+       })
+}
+
 func BenchmarkGrowSlice(b *testing.B) {
        b.Run("Byte", func(b *testing.B) {
                x := make([]byte, 9)