Commit 6b0688f7 authored by Marvin Stenger's avatar Marvin Stenger Committed by Ian Lance Taylor

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/21101Reviewed-by: 's avatarIan Lance Taylor <iant@golang.org>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent 1664ff96
...@@ -9,7 +9,7 @@ const N = 20 ...@@ -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) { ...@@ -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 { ...@@ -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 { ...@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment