Skip to content

Commit

Permalink
runtime: avoid memclr call for keys in mapdelete_fast
Browse files Browse the repository at this point in the history
Replace memclrHasPointers calls for keys in mapdelete_fast*
functions with direct writes since the key sizes are known
at compile time.

name                     old time/op  new time/op  delta
MapDelete/Pointer/100    33.7ns ± 1%  23.7ns ± 2%  -29.68%  (p=0.000 n=7+9)
MapDelete/Pointer/1000   41.6ns ± 5%  34.9ns ± 4%  -16.01%  (p=0.000 n=9+10)
MapDelete/Pointer/10000  45.6ns ± 1%  38.2ns ± 2%  -16.34%  (p=0.000 n=8+10)

Change-Id: Icaac43b520b93c2cf9fd192b822fae7203a7bbf7
Reviewed-on: https://go-review.googlesource.com/c/go/+/231737
Run-TryBot: Martin Möhrmann <moehrmann@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
  • Loading branch information
martisch committed Aug 17, 2020
1 parent 99f179f commit f979d07
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 3 deletions.
8 changes: 6 additions & 2 deletions src/runtime/map_fast32.go
Original file line number Diff line number Diff line change
Expand Up @@ -299,8 +299,12 @@ search:
continue
}
// Only clear key if there are pointers in it.
if t.key.ptrdata != 0 {
memclrHasPointers(k, t.key.size)
// This can only happen if pointers are 32 bit
// wide as 64 bit pointers do not fit into a 32 bit key.
if sys.PtrSize == 4 && t.key.ptrdata != 0 {
// The key must be a pointer as we checked pointers are
// 32 bits wide and the key is 32 bits wide also.
*(*unsafe.Pointer)(k) = nil
}
e := add(unsafe.Pointer(b), dataOffset+bucketCnt*4+i*uintptr(t.elemsize))
if t.elem.ptrdata != 0 {
Expand Down
8 changes: 7 additions & 1 deletion src/runtime/map_fast64.go
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,13 @@ search:
}
// Only clear key if there are pointers in it.
if t.key.ptrdata != 0 {
memclrHasPointers(k, t.key.size)
if sys.PtrSize == 8 {
*(*unsafe.Pointer)(k) = nil
} else {
// There are three ways to squeeze at one ore more 32 bit pointers into 64 bits.
// Just call memclrHasPointers instead of trying to handle all cases here.
memclrHasPointers(k, 8)
}
}
e := add(unsafe.Pointer(b), dataOffset+bucketCnt*8+i*uintptr(t.elemsize))
if t.elem.ptrdata != 0 {
Expand Down
22 changes: 22 additions & 0 deletions src/runtime/map_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -993,6 +993,27 @@ func benchmarkMapDeleteStr(b *testing.B, n int) {
}
}

func benchmarkMapDeletePointer(b *testing.B, n int) {
i2p := make([]*int, n)
for i := 0; i < n; i++ {
i2p[i] = new(int)
}
a := make(map[*int]int, n)
b.ResetTimer()
k := 0
for i := 0; i < b.N; i++ {
if len(a) == 0 {
b.StopTimer()
for j := 0; j < n; j++ {
a[i2p[j]] = j
}
k = i
b.StartTimer()
}
delete(a, i2p[i-k])
}
}

func runWith(f func(*testing.B, int), v ...int) func(*testing.B) {
return func(b *testing.B) {
for _, n := range v {
Expand Down Expand Up @@ -1023,6 +1044,7 @@ func BenchmarkMapDelete(b *testing.B) {
b.Run("Int32", runWith(benchmarkMapDeleteInt32, 100, 1000, 10000))
b.Run("Int64", runWith(benchmarkMapDeleteInt64, 100, 1000, 10000))
b.Run("Str", runWith(benchmarkMapDeleteStr, 100, 1000, 10000))
b.Run("Pointer", runWith(benchmarkMapDeletePointer, 100, 1000, 10000))
}

func TestDeferDeleteSlow(t *testing.T) {
Expand Down

0 comments on commit f979d07

Please sign in to comment.