From aee71dd70b3779c66950ce6a952deca13d48e55e Mon Sep 17 00:00:00 2001 From: Martin Möhrmann Date: Fri, 27 Apr 2018 21:58:59 +0200 Subject: cmd/compile: optimize map-clearing range idiom MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit replace map clears of the form: for k := range m { delete(m, k) } (where m is map with key type that is reflexive for ==) with a new runtime function that clears the maps backing array with a memclr and reinitializes the hmap struct. Map key types that for example contain floats are not replaced by this optimization since NaN keys cannot be deleted from maps using delete. name old time/op new time/op delta GoMapClear/Reflexive/1 92.2ns ± 1% 47.1ns ± 2% -48.89% (p=0.000 n=9+9) GoMapClear/Reflexive/10 108ns ± 1% 48ns ± 2% -55.68% (p=0.000 n=10+10) GoMapClear/Reflexive/100 303ns ± 2% 110ns ± 3% -63.56% (p=0.000 n=10+10) GoMapClear/Reflexive/1000 3.58µs ± 3% 1.23µs ± 2% -65.49% (p=0.000 n=9+10) GoMapClear/Reflexive/10000 28.2µs ± 3% 10.3µs ± 2% -63.55% (p=0.000 n=9+10) GoMapClear/NonReflexive/1 121ns ± 2% 124ns ± 7% ~ (p=0.097 n=10+10) GoMapClear/NonReflexive/10 137ns ± 2% 139ns ± 3% +1.53% (p=0.033 n=10+10) GoMapClear/NonReflexive/100 331ns ± 3% 334ns ± 2% ~ (p=0.342 n=10+10) GoMapClear/NonReflexive/1000 3.64µs ± 3% 3.64µs ± 2% ~ (p=0.887 n=9+10) GoMapClear/NonReflexive/10000 28.1µs ± 2% 28.4µs ± 3% ~ (p=0.247 n=10+10) Fixes #20138 Change-Id: I181332a8ef434a4f0d89659f492d8711db3f3213 Reviewed-on: https://go-review.googlesource.com/110055 Reviewed-by: Keith Randall --- test/codegen/maps.go | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) (limited to 'test/codegen') diff --git a/test/codegen/maps.go b/test/codegen/maps.go index 57e219ca06..d167715898 100644 --- a/test/codegen/maps.go +++ b/test/codegen/maps.go @@ -36,3 +36,60 @@ func AccessString2(m map[string]int) bool { _, ok := m["abc"] return ok } + +// ------------------- // +// Map Clear // +// ------------------- // + +// Optimization of map clear idiom (Issue #20138). + +func MapClearReflexive(m map[int]int) { + // amd64:`.*runtime\.mapclear` + // amd64:-`.*runtime\.mapiterinit` + for k := range m { + delete(m, k) + } +} + +func MapClearIndirect(m map[int]int) { + s := struct{ m map[int]int }{m: m} + // amd64:`.*runtime\.mapclear` + // amd64:-`.*runtime\.mapiterinit` + for k := range s.m { + delete(s.m, k) + } +} + +func MapClearPointer(m map[*byte]int) { + // amd64:`.*runtime\.mapclear` + // amd64:-`.*runtime\.mapiterinit` + for k := range m { + delete(m, k) + } +} + +func MapClearNotReflexive(m map[float64]int) { + // amd64:`.*runtime\.mapiterinit` + // amd64:-`.*runtime\.mapclear` + for k := range m { + delete(m, k) + } +} + +func MapClearInterface(m map[interface{}]int) { + // amd64:`.*runtime\.mapiterinit` + // amd64:-`.*runtime\.mapclear` + for k := range m { + delete(m, k) + } +} + +func MapClearSideEffect(m map[int]int) int { + k := 0 + // amd64:`.*runtime\.mapiterinit` + // amd64:-`.*runtime\.mapclear` + for k = range m { + delete(m, k) + } + return k +} -- cgit v1.3