From: Martin Möhrmann Date: Mon, 22 Oct 2018 18:45:04 +0000 (+0200) Subject: runtime: use multiplication with overflow check for makemap X-Git-Tag: go1.12beta1~687 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=e85b8db604bd6dd84502708434a19596b54468b5;p=gostls13.git runtime: use multiplication with overflow check for makemap This improves performance for maps with a bucket size (key+value*8 bytes) larger than 32 bytes and removes loading a value from the maxElems array for smaller bucket sizes. name old time/op new time/op delta MakeMap/[Byte]Byte 93.5ns ± 1% 91.8ns ± 1% -1.83% (p=0.000 n=10+10) MakeMap/[Int]Int 134ns ± 1% 127ns ± 2% -5.61% (p=0.000 n=9+10) Updates #21588 Change-Id: I53f77186769c4bd0f2b90f3c6c17df643b060e39 Reviewed-on: https://go-review.googlesource.com/c/143797 Run-TryBot: Martin Möhrmann TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- diff --git a/src/runtime/map.go b/src/runtime/map.go index c3fcfbfdbe..3e368f929f 100644 --- a/src/runtime/map.go +++ b/src/runtime/map.go @@ -55,6 +55,7 @@ package runtime import ( "runtime/internal/atomic" + "runtime/internal/math" "runtime/internal/sys" "unsafe" ) @@ -296,7 +297,8 @@ func makemap_small() *hmap { // If h != nil, the map can be created directly in h. // If h.buckets != nil, bucket pointed to can be used as the first bucket. func makemap(t *maptype, hint int, h *hmap) *hmap { - if hint < 0 || hint > int(maxSliceCap(t.bucket.size)) { + mem, overflow := math.MulUintptr(uintptr(hint), t.bucket.size) + if overflow || mem > maxAlloc { hint = 0 } @@ -306,7 +308,8 @@ func makemap(t *maptype, hint int, h *hmap) *hmap { } h.hash0 = fastrand() - // find size parameter which will hold the requested # of elements + // Find the size parameter B which will hold the requested # of elements. + // For hint < 0 overLoadFactor returns false since hint < bucketCnt. B := uint8(0) for overLoadFactor(hint, B) { B++ diff --git a/src/runtime/map_benchmark_test.go b/src/runtime/map_benchmark_test.go index 1d9d09c698..5681d5eeb8 100644 --- a/src/runtime/map_benchmark_test.go +++ b/src/runtime/map_benchmark_test.go @@ -228,6 +228,23 @@ func benchmarkRepeatedLookup(b *testing.B, lookupKeySize int) { func BenchmarkRepeatedLookupStrMapKey32(b *testing.B) { benchmarkRepeatedLookup(b, 32) } func BenchmarkRepeatedLookupStrMapKey1M(b *testing.B) { benchmarkRepeatedLookup(b, 1<<20) } +func BenchmarkMakeMap(b *testing.B) { + b.Run("[Byte]Byte", func(b *testing.B) { + var m map[byte]byte + for i := 0; i < b.N; i++ { + m = make(map[byte]byte, 10) + } + hugeSink = m + }) + b.Run("[Int]Int", func(b *testing.B) { + var m map[int]int + for i := 0; i < b.N; i++ { + m = make(map[int]int, 10) + } + hugeSink = m + }) +} + func BenchmarkNewEmptyMap(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ {