]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: speed up growslice by avoiding divisions 2
authorMarvin Stenger <marvin.stenger94@gmail.com>
Thu, 24 Mar 2016 16:42:01 +0000 (17:42 +0100)
committerIan Lance Taylor <iant@golang.org>
Fri, 25 Mar 2016 16:47:56 +0000 (16:47 +0000)
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>

src/runtime/append_test.go
src/runtime/slice.go

index 4b647f70a03a5c0f0efd2ba4669999f1e93d2278..3170870b0e559770dbb34a5929cf969c10c69ed1 100644 (file)
@@ -9,7 +9,7 @@ const N = 20
 
 func BenchmarkGrowSliceBytes(b *testing.B) {
        b.StopTimer()
-       var x = make([]byte, 8)
+       var x = make([]byte, 9)
        b.StartTimer()
        for i := 0; i < b.N; i++ {
                _ = append([]byte(nil), x...)
@@ -18,13 +18,33 @@ func BenchmarkGrowSliceBytes(b *testing.B) {
 
 func BenchmarkGrowSliceInts(b *testing.B) {
        b.StopTimer()
-       var x = make([]int, 8)
+       var x = make([]int, 9)
        b.StartTimer()
        for i := 0; i < b.N; i++ {
                _ = 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) {
        b.StopTimer()
        x := make([]int, 0, N)
index d35ecadb16aaaa3407dde1118546d5ab707f7ee6..0bc0299f7201604bc234b90a78c23655dfab75b4 100644 (file)
@@ -56,11 +56,6 @@ func growslice(t *slicetype, old slice, cap int) slice {
                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
        doublecap := newcap + newcap
        if cap > doublecap {
@@ -73,17 +68,30 @@ func growslice(t *slicetype, old slice, cap int) slice {
                                newcap += newcap / 4
                        }
                }
-               if uintptr(newcap) > maxcap {
-                       panic(errorString("growslice: cap out of range"))
-               }
        }
 
-       lenmem := uintptr(old.len) * et.size
-       capmem := roundupsize(uintptr(newcap) * et.size)
-       if et.size == 1 {
+       var lenmem, capmem, maxcap uintptr
+       const ptrSize = unsafe.Sizeof((*byte)(nil))
+       switch et.size {
+       case 1:
+               lenmem = uintptr(old.len)
+               capmem = roundupsize(uintptr(newcap))
                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)
+               maxcap = _MaxMem / et.size
+       }
+
+       if cap < old.cap || uintptr(newcap) > maxcap {
+               panic(errorString("growslice: cap out of range"))
        }
 
        var p unsafe.Pointer