]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: make slice growth formula a bit smoother
authorKeith Randall <khr@golang.org>
Tue, 7 Sep 2021 16:44:29 +0000 (09:44 -0700)
committerKeith Randall <khr@golang.org>
Mon, 27 Sep 2021 20:53:51 +0000 (20:53 +0000)
Instead of growing 2x for < 1024 elements and 1.25x for >= 1024 elements,
use a somewhat smoother formula for the growth factor. Start reducing
the growth factor after 256 elements, but slowly.

starting cap    growth factor
256             2.0
512             1.63
1024            1.44
2048            1.35
4096            1.30

(Note that the real growth factor, both before and now, is somewhat
larger because we round up to the next size class.)

This CL also makes the growth monotonic (larger initial capacities
make larger final capacities, which was not true before). See discussion
at https://groups.google.com/g/golang-nuts/c/UaVlMQ8Nz3o

256 was chosen as the threshold to roughly match the total number of
reallocations when appending to eventually make a very large
slice. (We allocate smaller when appending to capacities [256,1024]
and larger with capacities [1024,...]).

Change-Id: I876df09fdc9ae911bb94e41cb62675229cb10512
Reviewed-on: https://go-review.googlesource.com/c/go/+/347917
Trust: Keith Randall <khr@golang.org>
Trust: Martin Möhrmann <martin@golang.org>
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Martin Möhrmann <martin@golang.org>
src/reflect/value.go
src/runtime/slice.go

index 33b81d72092e19c1020893fb00b7baa8020f07be..786c494166d09a046fcb0c626a8fab6a0ade9a40 100644 (file)
@@ -2487,11 +2487,12 @@ func grow(s Value, extra int) (Value, int, int) {
        if m == 0 {
                m = extra
        } else {
+               const threshold = 256
                for m < i1 {
-                       if i0 < 1024 {
+                       if i0 < threshold {
                                m += m
                        } else {
-                               m += m / 4
+                               m += (m + 3*threshold) / 4
                        }
                }
        }
index e8267be885df1670ed24265c8e5a890709f72a3b..cfa862e047b05ccd7486f5c62cc8031bfcf1764d 100644 (file)
@@ -185,13 +185,17 @@ func growslice(et *_type, old slice, cap int) slice {
        if cap > doublecap {
                newcap = cap
        } else {
-               if old.cap < 1024 {
+               const threshold = 256
+               if old.cap < threshold {
                        newcap = doublecap
                } else {
                        // Check 0 < newcap to detect overflow
                        // and prevent an infinite loop.
                        for 0 < newcap && newcap < cap {
-                               newcap += newcap / 4
+                               // Transition from growing 2x for small slices
+                               // to growing 1.25x for large slices. This formula
+                               // gives a smooth-ish transition between the two.
+                               newcap += (newcap + 3*threshold) / 4
                        }
                        // Set newcap to the requested cap when
                        // the newcap calculation overflowed.