]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: use multiplication with overflow check for makemap
authorMartin Möhrmann <moehrmann@google.com>
Mon, 22 Oct 2018 18:45:04 +0000 (20:45 +0200)
committerMartin Möhrmann <martisch@uos.de>
Tue, 23 Oct 2018 06:31:13 +0000 (06:31 +0000)
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 <martisch@uos.de>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/runtime/map.go
src/runtime/map_benchmark_test.go

index c3fcfbfdbe40579c37a421b8ae1c06d81e0284df..3e368f929fa33c09ed065bd3ddc7359bfc1f0423 100644 (file)
@@ -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++
index 1d9d09c6981477f44a73c775dc201648ecd611cb..5681d5eeb8cfb721f8b093b82d933bf9742b0219 100644 (file)
@@ -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++ {