mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
runtime: speed up growslice by avoiding divisions 2
This is a follow-up of https://go-review.googlesource.com/#/c/20653/ Special case computation for slices with elements of byte size or pointer size. name old time/op new time/op delta GrowSliceBytes-4 86.2ns ± 3% 75.4ns ± 2% -12.50% (p=0.000 n=20+20) GrowSliceInts-4 161ns ± 3% 136ns ± 3% -15.59% (p=0.000 n=19+19) GrowSlicePtr-4 239ns ± 2% 233ns ± 2% -2.52% (p=0.000 n=20+20) GrowSliceStruct24Bytes-4 258ns ± 3% 256ns ± 3% ~ (p=0.134 n=20+20) Change-Id: Ice5fa648058fe9d7fa89dee97ca359966f671128 Reviewed-on: https://go-review.googlesource.com/21101 Reviewed-by: Ian Lance Taylor <iant@golang.org> Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
1664ff96f7
commit
6b0688f742
2 changed files with 42 additions and 14 deletions
|
|
@ -9,7 +9,7 @@ const N = 20
|
||||||
|
|
||||||
func BenchmarkGrowSliceBytes(b *testing.B) {
|
func BenchmarkGrowSliceBytes(b *testing.B) {
|
||||||
b.StopTimer()
|
b.StopTimer()
|
||||||
var x = make([]byte, 8)
|
var x = make([]byte, 9)
|
||||||
b.StartTimer()
|
b.StartTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = append([]byte(nil), x...)
|
_ = append([]byte(nil), x...)
|
||||||
|
|
@ -18,13 +18,33 @@ func BenchmarkGrowSliceBytes(b *testing.B) {
|
||||||
|
|
||||||
func BenchmarkGrowSliceInts(b *testing.B) {
|
func BenchmarkGrowSliceInts(b *testing.B) {
|
||||||
b.StopTimer()
|
b.StopTimer()
|
||||||
var x = make([]int, 8)
|
var x = make([]int, 9)
|
||||||
b.StartTimer()
|
b.StartTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = append([]int(nil), x...)
|
_ = append([]int(nil), x...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkGrowSlicePtr(b *testing.B) {
|
||||||
|
b.StopTimer()
|
||||||
|
var x = make([]*byte, 9)
|
||||||
|
b.StartTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_ = append([]*byte(nil), x...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type struct24 struct{ a, b, c int64 }
|
||||||
|
|
||||||
|
func BenchmarkGrowSliceStruct24Bytes(b *testing.B) {
|
||||||
|
b.StopTimer()
|
||||||
|
var x = make([]struct24, 9)
|
||||||
|
b.StartTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_ = append([]struct24(nil), x...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func BenchmarkAppend(b *testing.B) {
|
func BenchmarkAppend(b *testing.B) {
|
||||||
b.StopTimer()
|
b.StopTimer()
|
||||||
x := make([]int, 0, N)
|
x := make([]int, 0, N)
|
||||||
|
|
|
||||||
|
|
@ -56,11 +56,6 @@ func growslice(t *slicetype, old slice, cap int) slice {
|
||||||
return slice{unsafe.Pointer(&zerobase), old.len, cap}
|
return slice{unsafe.Pointer(&zerobase), old.len, cap}
|
||||||
}
|
}
|
||||||
|
|
||||||
maxcap := _MaxMem / et.size
|
|
||||||
if cap < old.cap || uintptr(cap) > maxcap {
|
|
||||||
panic(errorString("growslice: cap out of range"))
|
|
||||||
}
|
|
||||||
|
|
||||||
newcap := old.cap
|
newcap := old.cap
|
||||||
doublecap := newcap + newcap
|
doublecap := newcap + newcap
|
||||||
if cap > doublecap {
|
if cap > doublecap {
|
||||||
|
|
@ -73,17 +68,30 @@ func growslice(t *slicetype, old slice, cap int) slice {
|
||||||
newcap += newcap / 4
|
newcap += newcap / 4
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if uintptr(newcap) > maxcap {
|
|
||||||
panic(errorString("growslice: cap out of range"))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lenmem := uintptr(old.len) * et.size
|
var lenmem, capmem, maxcap uintptr
|
||||||
capmem := roundupsize(uintptr(newcap) * et.size)
|
const ptrSize = unsafe.Sizeof((*byte)(nil))
|
||||||
if et.size == 1 {
|
switch et.size {
|
||||||
|
case 1:
|
||||||
|
lenmem = uintptr(old.len)
|
||||||
|
capmem = roundupsize(uintptr(newcap))
|
||||||
newcap = int(capmem)
|
newcap = int(capmem)
|
||||||
} else {
|
maxcap = _MaxMem
|
||||||
|
case ptrSize:
|
||||||
|
lenmem = uintptr(old.len) * ptrSize
|
||||||
|
capmem = roundupsize(uintptr(newcap) * ptrSize)
|
||||||
|
newcap = int(capmem / ptrSize)
|
||||||
|
maxcap = _MaxMem / ptrSize
|
||||||
|
default:
|
||||||
|
lenmem = uintptr(old.len) * et.size
|
||||||
|
capmem = roundupsize(uintptr(newcap) * et.size)
|
||||||
newcap = int(capmem / et.size)
|
newcap = int(capmem / et.size)
|
||||||
|
maxcap = _MaxMem / et.size
|
||||||
|
}
|
||||||
|
|
||||||
|
if cap < old.cap || uintptr(newcap) > maxcap {
|
||||||
|
panic(errorString("growslice: cap out of range"))
|
||||||
}
|
}
|
||||||
|
|
||||||
var p unsafe.Pointer
|
var p unsafe.Pointer
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue