From: Cuong Manh Le Date: Tue, 7 Apr 2020 20:08:21 +0000 (+0700) Subject: cmd/compile: do not allocate bucket for non-escaping map X-Git-Tag: go1.15beta1~611 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=98b6c6aca6fd4185f97dc40137707f4d8df8aa7c;p=gostls13.git cmd/compile: do not allocate bucket for non-escaping map 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 TryBot-Result: Gobot Gobot Reviewed-by: Keith Randall --- diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index 21658db21d..57d71bf3d4 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -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) } } diff --git a/src/runtime/map_benchmark_test.go b/src/runtime/map_benchmark_test.go index bae1aa0dbd..893cb6c5b6 100644 --- a/src/runtime/map_benchmark_test.go +++ b/src/runtime/map_benchmark_test.go @@ -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) + } +}