Skip to content

Commit 05166bf

Browse files
committed
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 <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Keith Randall <[email protected]>
1 parent 3b091bf commit 05166bf

File tree

2 files changed

+68
-20
lines changed

2 files changed

+68
-20
lines changed

src/runtime/slice.go

+12-12
Original file line numberDiff line numberDiff line change
@@ -54,21 +54,21 @@ func panicmakeslicecap() {
5454
}
5555

5656
func makeslice(et *_type, len, cap int) slice {
57-
// NOTE: The len > maxElements check here is not strictly necessary,
58-
// but it produces a 'len out of range' error instead of a 'cap out of range' error
59-
// when someone does make([]T, bignumber). 'cap out of range' is true too,
60-
// but since the cap is only being supplied implicitly, saying len is clearer.
61-
// See issue 4085.
62-
maxElements := maxSliceCap(et.size)
63-
if len < 0 || uintptr(len) > maxElements {
64-
panicmakeslicelen()
65-
}
66-
67-
if cap < len || uintptr(cap) > maxElements {
57+
mem, overflow := math.MulUintptr(et.size, uintptr(cap))
58+
if overflow || mem > maxAlloc || len < 0 || len > cap {
59+
// NOTE: Produce a 'len out of range' error instead of a
60+
// 'cap out of range' error when someone does make([]T, bignumber).
61+
// 'cap out of range' is true too, but since the cap is only being
62+
// supplied implicitly, saying len is clearer.
63+
// See golang.org/issue/4085.
64+
mem, overflow := math.MulUintptr(et.size, uintptr(len))
65+
if overflow || mem > maxAlloc || len < 0 {
66+
panicmakeslicelen()
67+
}
6868
panicmakeslicecap()
6969
}
70+
p := mallocgc(mem, et, true)
7071

71-
p := mallocgc(et.size*uintptr(cap), et, true)
7272
return slice{p, len, cap}
7373
}
7474

src/runtime/slice_test.go

+56-8
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,68 @@ import (
1010

1111
const N = 20
1212

13-
func BenchmarkMakeSlice(b *testing.B) {
14-
var x []byte
15-
for i := 0; i < b.N; i++ {
16-
x = make([]byte, 32)
17-
_ = x
18-
}
19-
}
20-
2113
type (
2214
struct24 struct{ a, b, c int64 }
2315
struct32 struct{ a, b, c, d int64 }
2416
struct40 struct{ a, b, c, d, e int64 }
2517
)
2618

19+
func BenchmarkMakeSlice(b *testing.B) {
20+
const length = 2
21+
b.Run("Byte", func(b *testing.B) {
22+
var x []byte
23+
for i := 0; i < b.N; i++ {
24+
x = make([]byte, length, 2*length)
25+
_ = x
26+
}
27+
})
28+
b.Run("Int16", func(b *testing.B) {
29+
var x []int16
30+
for i := 0; i < b.N; i++ {
31+
x = make([]int16, length, 2*length)
32+
_ = x
33+
}
34+
})
35+
b.Run("Int", func(b *testing.B) {
36+
var x []int
37+
for i := 0; i < b.N; i++ {
38+
x = make([]int, length, 2*length)
39+
_ = x
40+
}
41+
})
42+
b.Run("Ptr", func(b *testing.B) {
43+
var x []*byte
44+
for i := 0; i < b.N; i++ {
45+
x = make([]*byte, length, 2*length)
46+
_ = x
47+
}
48+
})
49+
b.Run("Struct", func(b *testing.B) {
50+
b.Run("24", func(b *testing.B) {
51+
var x []struct24
52+
for i := 0; i < b.N; i++ {
53+
x = make([]struct24, length, 2*length)
54+
_ = x
55+
}
56+
})
57+
b.Run("32", func(b *testing.B) {
58+
var x []struct32
59+
for i := 0; i < b.N; i++ {
60+
x = make([]struct32, length, 2*length)
61+
_ = x
62+
}
63+
})
64+
b.Run("40", func(b *testing.B) {
65+
var x []struct40
66+
for i := 0; i < b.N; i++ {
67+
x = make([]struct40, length, 2*length)
68+
_ = x
69+
}
70+
})
71+
72+
})
73+
}
74+
2775
func BenchmarkGrowSlice(b *testing.B) {
2876
b.Run("Byte", func(b *testing.B) {
2977
x := make([]byte, 9)

0 commit comments

Comments
 (0)