diff options
| author | Martin Möhrmann <moehrmann@google.com> | 2018-10-16 00:27:42 +0200 |
|---|---|---|
| committer | Martin Möhrmann <martisch@uos.de> | 2018-10-23 07:23:15 +0000 |
| commit | 05166bf54d053fcc833cf862b7cfb1fbf05b42ba (patch) | |
| tree | a1f19084b450d42dabb1cc18d499a86d32392463 /src/runtime | |
| parent | 3b091bf6cceca868e2063a2c8b3cec90411ea18e (diff) | |
| download | go-05166bf54d053fcc833cf862b7cfb1fbf05b42ba.tar.xz | |
runtime: use multiplication with overflow check for makeslice
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>
Diffstat (limited to 'src/runtime')
| -rw-r--r-- | src/runtime/slice.go | 24 | ||||
| -rw-r--r-- | src/runtime/slice_test.go | 64 |
2 files changed, 68 insertions, 20 deletions
diff --git a/src/runtime/slice.go b/src/runtime/slice.go index 2c5c52a6e6..095ddc5bbd 100644 --- a/src/runtime/slice.go +++ b/src/runtime/slice.go @@ -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} } diff --git a/src/runtime/slice_test.go b/src/runtime/slice_test.go index c2dfb7afd1..0463fc70a7 100644 --- a/src/runtime/slice_test.go +++ b/src/runtime/slice_test.go @@ -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) |
