From 98b6c6aca6fd4185f97dc40137707f4d8df8aa7c Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Wed, 8 Apr 2020 03:08:21 +0700 Subject: [PATCH] cmd/compile: do not allocate bucket for non-escaping map MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 --- src/cmd/compile/internal/gc/walk.go | 24 +++++++++++++++++++----- src/runtime/map_benchmark_test.go | 19 +++++++++++++++++++ 2 files changed, 38 insertions(+), 5 deletions(-) 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) + } +} -- 2.50.0