]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: improve work stealing randomness
authorKeith Randall <khr@golang.org>
Tue, 7 Dec 2021 17:22:33 +0000 (09:22 -0800)
committerKeith Randall <khr@golang.org>
Tue, 1 Mar 2022 18:43:08 +0000 (18:43 +0000)
For certain values of GOMAXPROCS, the current code is less random than
it looks. For example with GOMAXPROCS=12, there are 4 coprimes: 1 5 7 11.
That's bad, as 12 and 4 are not relatively prime. So if pos == 2, then we
always pick 7 as the inc. We want to pick pos and inc independently
at random.

Change-Id: I5c7e4f01f9223cbc2db12a685dc0bced2cf39abf
Reviewed-on: https://go-review.googlesource.com/c/go/+/369976
Run-TryBot: Keith Randall <khr@golang.org>
Trust: Keith Randall <khr@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Dmitry Vyukov <dvyukov@google.com>
src/runtime/proc.go
src/runtime/proc_runtime_test.go

index b997a467bab447b58edd9475504a6ab0de8a5614..df16e0f9b63ff4e0a46a5b3c9bf61440840f6fef 100644 (file)
@@ -6138,7 +6138,7 @@ func (ord *randomOrder) start(i uint32) randomEnum {
        return randomEnum{
                count: ord.count,
                pos:   i % ord.count,
-               inc:   ord.coprimes[i%uint32(len(ord.coprimes))],
+               inc:   ord.coprimes[i/ord.count%uint32(len(ord.coprimes))],
        }
 }
 
index a7bde2c6df7c3ea6480303a05a54a4ffa50b24b1..90aed83d46a52ed086f9afdf2a7e756ede7dc9e5 100644 (file)
@@ -30,4 +30,21 @@ func RunStealOrderTest() {
                        }
                }
        }
+       // Make sure that different arguments to ord.start don't generate the
+       // same pos+inc twice.
+       for procs := 2; procs <= 64; procs++ {
+               ord.reset(uint32(procs))
+               checked := make([]bool, procs*procs)
+               // We want at least procs*len(ord.coprimes) different pos+inc values
+               // before we start repeating.
+               for i := 0; i < procs*len(ord.coprimes); i++ {
+                       enum := ord.start(uint32(i))
+                       j := enum.pos*uint32(procs) + enum.inc
+                       if checked[j] {
+                               println("procs:", procs, "pos:", enum.pos, "inc:", enum.inc)
+                               panic("duplicate pos+inc during enumeration")
+                       }
+                       checked[j] = true
+               }
+       }
 }