]> Cypherpunks.ru repositories - gostls13.git/commitdiff
runtime: add fastrand64
authorzhangyunhao <zhangyunhao@bytedance.com>
Mon, 18 Apr 2022 07:23:20 +0000 (15:23 +0800)
committerGopher Robot <gobot@golang.org>
Wed, 20 Apr 2022 22:50:33 +0000 (22:50 +0000)
Support fastrand64 in the runtime, although fastrand uses wyrand to generate 64-bit random number, it still returns uint32. In some cases, we need to generate a 64-bit random number, the new API would be faster and easier to use, and at least we can use the new function in these places:

src/net/dnsclient.go:randInt()
src/hash/maphash/maphash.go:MakeSeed()
src/runtime/map.go:mapiterinit()

name                 time/op
Fastrand-16          0.09ns ± 5%
Fastrand64-16        0.09ns ± 6%

Change-Id: Ibb97378c7ca59bc7dc15535d4872fa58ea112e6a
Reviewed-on: https://go-review.googlesource.com/c/go/+/400734
Reviewed-by: Keith Randall <khr@golang.org>
Run-TryBot: Keith Randall <khr@golang.org>
Auto-Submit: Keith Randall <khr@golang.org>
Reviewed-by: Keith Randall <khr@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@google.com>
src/runtime/export_test.go
src/runtime/rand_test.go
src/runtime/stubs.go

index af27050bfd0a609c9b3492bb87dca4adcf39699e..8a81f42ca09d6f8c12d10729d52df0430c276f2b 100644 (file)
@@ -277,6 +277,7 @@ func CountPagesInUse() (pagesInUse, counted uintptr) {
 }
 
 func Fastrand() uint32          { return fastrand() }
+func Fastrand64() uint64        { return fastrand64() }
 func Fastrandn(n uint32) uint32 { return fastrandn(n) }
 
 type ProfBuf profBuf
index 1b84c79d24fb0aa8fd64de7d292a68a98c60ecd4..92d07ebadac95c2377e661d542eb61f871d5296b 100644 (file)
@@ -18,6 +18,14 @@ func BenchmarkFastrand(b *testing.B) {
        })
 }
 
+func BenchmarkFastrand64(b *testing.B) {
+       b.RunParallel(func(pb *testing.PB) {
+               for pb.Next() {
+                       Fastrand64()
+               }
+       })
+}
+
 func BenchmarkFastrandHashiter(b *testing.B) {
        var m = make(map[int]int, 10)
        for i := 0; i < 10; i++ {
index 8c4ab3ed4e6cb41afa7438ba913ee16abeb4315c..ca0cd1ba25eb1f69d6b21b76ccfb46016bf0be28 100644 (file)
@@ -157,6 +157,45 @@ func fastrandn(n uint32) uint32 {
        return uint32(uint64(fastrand()) * uint64(n) >> 32)
 }
 
+func fastrand64() uint64 {
+       mp := getg().m
+       // Implement wyrand: https://github.com/wangyi-fudan/wyhash
+       // Only the platform that math.Mul64 can be lowered
+       // by the compiler should be in this list.
+       if goarch.IsAmd64|goarch.IsArm64|goarch.IsPpc64|
+               goarch.IsPpc64le|goarch.IsMips64|goarch.IsMips64le|
+               goarch.IsS390x|goarch.IsRiscv64 == 1 {
+               mp.fastrand += 0xa0761d6478bd642f
+               hi, lo := math.Mul64(mp.fastrand, mp.fastrand^0xe7037ed1a0b428db)
+               return hi ^ lo
+       }
+
+       // Implement xorshift64+: 2 32-bit xorshift sequences added together.
+       // Xorshift paper: https://www.jstatsoft.org/article/view/v008i14/xorshift.pdf
+       // This generator passes the SmallCrush suite, part of TestU01 framework:
+       // http://simul.iro.umontreal.ca/testu01/tu01.html
+       t := (*[2]uint32)(unsafe.Pointer(&mp.fastrand))
+       s1, s0 := t[0], t[1]
+       s1 ^= s1 << 17
+       s1 = s1 ^ s0 ^ s1>>7 ^ s0>>16
+       r := uint64(s0 + s1)
+
+       s0, s1 = s1, s0
+       s1 ^= s1 << 17
+       s1 = s1 ^ s0 ^ s1>>7 ^ s0>>16
+       r += uint64(s0+s1) << 32
+
+       t[0], t[1] = s0, s1
+       return r
+}
+
+func fastrandu() uint {
+       if goarch.PtrSize == 4 {
+               return uint(fastrand())
+       }
+       return uint(fastrand64())
+}
+
 //go:linkname sync_fastrandn sync.fastrandn
 func sync_fastrandn(n uint32) uint32 { return fastrandn(n) }