mirror of
https://github.com/golang/go
synced 2024-11-06 08:36:14 -07:00
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>
This commit is contained in:
parent
3b091bf6cc
commit
05166bf54d
@ -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}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user