From: Keith Randall Date: Tue, 9 Sep 2014 00:42:21 +0000 (-0700) Subject: runtime: on bigger maps, start iterator at a random bucket. X-Git-Tag: go1.4beta1~465 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=55c458e05f35d0d5d539107da07b744ad96f268e;p=gostls13.git runtime: on bigger maps, start iterator at a random bucket. This change brings the iter/delete pattern down to O(n lgn) from O(n^2). Fixes #8412. before: BenchmarkMapPop100 50000 32498 ns/op BenchmarkMapPop1000 500 3244851 ns/op BenchmarkMapPop10000 5 270276855 ns/op after: BenchmarkMapPop100 100000 16169 ns/op BenchmarkMapPop1000 5000 300416 ns/op BenchmarkMapPop10000 300 5990814 ns/op LGTM=iant R=golang-codereviews, iant, khr CC=golang-codereviews https://golang.org/cl/141270043 --- diff --git a/src/runtime/hashmap.go b/src/runtime/hashmap.go index 55287f6ff9..cbcc6c4041 100644 --- a/src/runtime/hashmap.go +++ b/src/runtime/hashmap.go @@ -134,11 +134,12 @@ type hiter struct { h *hmap buckets unsafe.Pointer // bucket ptr at hash_iter initialization time bptr *bmap // current bucket + startBucket uintptr // bucket iteration started at offset uint8 // intra-bucket offset to start from during iteration (should be big enough to hold bucketCnt-1) - done bool + wrapped bool // already wrapped around from end of bucket array to beginning B uint8 + i uint8 bucket uintptr - i uintptr checkBucket uintptr } @@ -560,10 +561,22 @@ func mapiterinit(t *maptype, h *hmap, it *hiter) { it.B = h.B it.buckets = h.buckets + // decide where to start + switch { + case h.B == 0: + it.startBucket = 0 + it.offset = uint8(fastrand1()) & (bucketCnt - 1) + case h.B <= 31: + it.startBucket = uintptr(fastrand1()) & (uintptr(1)<