]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: do not allocate bucket for non-escaping map
authorCuong Manh Le <cuong.manhle.vn@gmail.com>
Tue, 7 Apr 2020 20:08:21 +0000 (03:08 +0700)
committerCuong Manh Le <cuong.manhle.vn@gmail.com>
Thu, 9 Apr 2020 03:18:43 +0000 (03:18 +0000)
For map with hint larger than BUCKETSIZE, makemap ignore allocated
bucket and allocate buckets itself. So do not allocate bucket in
this case, save us the cost of zeroing+assignment to the bucket.

name                            old time/op    new time/op    delta
NewEmptyMap-12                    3.89ns ± 4%    3.88ns ± 2%    ~     (p=0.939 n=19+20)
NewSmallMap-12                    23.3ns ± 3%    23.1ns ± 2%    ~     (p=0.307 n=18+17)
NewEmptyMapHintLessThan8-12       6.43ns ± 3%    6.31ns ± 2%  -1.72%  (p=0.000 n=19+18)
NewEmptyMapHintGreaterThan8-12     159ns ± 2%     150ns ± 1%  -5.79%  (p=0.000 n=20+18)

Benchmark run with commit ab7c174 reverted, see #38314.

Fixes #20184

Change-Id: Ic021f57454c3a0dd50601d73bbd77b8faf8d93b6
Reviewed-on: https://go-review.googlesource.com/c/go/+/227458
Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
src/cmd/compile/internal/gc/walk.go
src/runtime/map_benchmark_test.go

index 21658db21dba86347c23e17863bba87e1a6cfa42..57d71bf3d451f31d4cdd93e88e923765bfe1136b 100644 (file)
@@ -1247,12 +1247,23 @@ opswitch:
                        // are stored with an indirection. So max bucket size is 2048+eps.
                        if !Isconst(hint, CTINT) ||
                                hint.Val().U.(*Mpint).CmpInt64(BUCKETSIZE) <= 0 {
+
+                               // In case hint is larger than BUCKETSIZE runtime.makemap
+                               // will allocate the buckets on the heap, see #20184
+                               //
+                               // if hint <= BUCKETSIZE {
+                               //     var bv bmap
+                               //     b = &bv
+                               //     h.buckets = b
+                               // }
+
+                               nif := nod(OIF, nod(OLE, hint, nodintconst(BUCKETSIZE)), nil)
+                               nif.SetLikely(true)
+
                                // var bv bmap
                                bv := temp(bmap(t))
-
                                zero = nod(OAS, bv, nil)
-                               zero = typecheck(zero, ctxStmt)
-                               init.Append(zero)
+                               nif.Nbody.Append(zero)
 
                                // b = &bv
                                b := nod(OADDR, bv, nil)
@@ -1260,8 +1271,11 @@ opswitch:
                                // h.buckets = b
                                bsym := hmapType.Field(5).Sym // hmap.buckets see reflect.go:hmap
                                na := nod(OAS, nodSym(ODOT, h, bsym), b)
-                               na = typecheck(na, ctxStmt)
-                               init.Append(na)
+                               nif.Nbody.Append(na)
+
+                               nif = typecheck(nif, ctxStmt)
+                               nif = walkstmt(nif)
+                               init.Append(nif)
                        }
                }
 
index bae1aa0dbd6d41f2ac842009c5732182228297b1..893cb6c5b6eb31b6c115def9931a6e7496aba299 100644 (file)
@@ -513,3 +513,22 @@ func BenchmarkMapInterfacePtr(b *testing.B) {
                BoolSink = m[key]
        }
 }
+
+var (
+       hintLessThan8    = 7
+       hintGreaterThan8 = 32
+)
+
+func BenchmarkNewEmptyMapHintLessThan8(b *testing.B) {
+       b.ReportAllocs()
+       for i := 0; i < b.N; i++ {
+               _ = make(map[int]int, hintLessThan8)
+       }
+}
+
+func BenchmarkNewEmptyMapHintGreaterThan8(b *testing.B) {
+       b.ReportAllocs()
+       for i := 0; i < b.N; i++ {
+               _ = make(map[int]int, hintGreaterThan8)
+       }
+}