So it could be inlined.
Using bit-tricks it could be implemented without condition
(improved trick version by Minux Ma).
Simple benchmark shows it is faster on i386 and x86_64, though
I don't know will it be faster on other architectures?
benchmark old ns/op new ns/op delta
BenchmarkFastrand-3 2.79 1.48 -46.95%
BenchmarkFastrandHashiter-3 25.9 24.9 -3.86%
Change-Id: Ie2eb6d0f598c0bb5fac7f6ad0f8b5e3eddaa361b
Reviewed-on: https://go-review.googlesource.com/34782
Reviewed-by: Minux Ma <minux@golang.org>
Run-TryBot: Minux Ma <minux@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
MOVL BX, (AX)
RET
-TEXT runtime·fastrand(SB), NOSPLIT, $0-4
- get_tls(CX)
- MOVL g(CX), AX
- MOVL g_m(AX), AX
- MOVL m_fastrand(AX), DX
- ADDL DX, DX
- MOVL DX, BX
- XORL $0x88888eef, DX
- JPL 2(PC)
- MOVL BX, DX
- MOVL DX, m_fastrand(AX)
- MOVL DX, ret+0(FP)
- RET
-
TEXT runtime·return0(SB), NOSPLIT, $0
MOVL $0, AX
RET
MOVB $0, ret+48(FP)
RET
-TEXT runtime·fastrand(SB), NOSPLIT, $0-4
- get_tls(CX)
- MOVQ g(CX), AX
- MOVQ g_m(AX), AX
- MOVL m_fastrand(AX), DX
- ADDL DX, DX
- MOVL DX, BX
- XORL $0x88888eef, DX
- CMOVLMI BX, DX
- MOVL DX, m_fastrand(AX)
- MOVL DX, ret+0(FP)
- RET
-
TEXT runtime·return0(SB), NOSPLIT, $0
MOVL $0, AX
RET
MOVB AX, ret+24(FP)
RET
-TEXT runtime·fastrand(SB), NOSPLIT, $0-4
- get_tls(CX)
- MOVL g(CX), AX
- MOVL g_m(AX), AX
- MOVL m_fastrand(AX), DX
- ADDL DX, DX
- MOVL DX, BX
- XORL $0x88888eef, DX
- CMOVLMI BX, DX
- MOVL DX, m_fastrand(AX)
- MOVL DX, ret+0(FP)
- RET
-
TEXT runtime·return0(SB), NOSPLIT, $0
MOVL $0, AX
RET
MOVW R0, ret+12(FP)
RET
-TEXT runtime·fastrand(SB),NOSPLIT,$-4-4
- MOVW g_m(g), R1
- MOVW m_fastrand(R1), R0
- ADD.S R0, R0
- EOR.MI $0x88888eef, R0
- MOVW R0, m_fastrand(R1)
- MOVW R0, ret+0(FP)
- RET
-
TEXT runtime·return0(SB),NOSPLIT,$0
MOVW $0, R0
RET
MOVB R0, ret+48(FP)
RET
-TEXT runtime·fastrand(SB),NOSPLIT,$-8-4
- MOVD g_m(g), R1
- MOVWU m_fastrand(R1), R0
- ADD R0, R0
- CMPW $0, R0
- BGE notneg
- EOR $0x88888eef, R0
-notneg:
- MOVW R0, m_fastrand(R1)
- MOVW R0, ret+0(FP)
- RET
-
TEXT runtime·return0(SB), NOSPLIT, $0
MOVW $0, R0
RET
MOVV R1, ret+24(FP)
RET
-TEXT runtime·fastrand(SB), NOSPLIT, $0-4
- MOVV g_m(g), R2
- MOVWU m_fastrand(R2), R1
- ADDU R1, R1
- BGEZ R1, 2(PC)
- XOR $0x88888eef, R1
- MOVW R1, m_fastrand(R2)
- MOVW R1, ret+0(FP)
- RET
-
TEXT runtime·return0(SB), NOSPLIT, $0
MOVW $0, R1
RET
MOVW R8, ret+24(FP)
RET
-TEXT runtime·fastrand(SB),NOSPLIT,$0-4
- MOVW g_m(g), R2
- MOVW m_fastrand(R2), R1
- ADDU R1, R1
- BGEZ R1, 2(PC)
- XOR $0x88888eef, R1
- MOVW R1, m_fastrand(R2)
- MOVW R1, ret+0(FP)
- RET
-
TEXT runtime·return0(SB),NOSPLIT,$0
MOVW $0, R1
RET
BR cmpbodyBE<>(SB)
#endif
-TEXT runtime·fastrand(SB), NOSPLIT, $0-4
- MOVD g_m(g), R4
- MOVWZ m_fastrand(R4), R3
- ADD R3, R3
- CMPW R3, $0
- BGE 2(PC)
- XOR $0x88888eef, R3
- MOVW R3, m_fastrand(R4)
- MOVW R3, ret+0(FP)
- RET
-
TEXT runtime·return0(SB), NOSPLIT, $0
MOVW $0, R3
RET
CLC $1, 0(R3), 0(R5)
RET
-TEXT runtime·fastrand(SB), NOSPLIT, $0-4
- MOVD g_m(g), R4
- MOVWZ m_fastrand(R4), R3
- ADD R3, R3
- CMPW R3, $0
- BGE 2(PC)
- XOR $0x88888eef, R3
- MOVW R3, m_fastrand(R4)
- MOVW R3, ret+0(FP)
- RET
-
TEXT bytes·IndexByte(SB),NOSPLIT|NOFRAME,$0-40
MOVD s+0(FP), R3 // s => R3
MOVD s_len+8(FP), R4 // s_len => R4
return
}
+
+func Fastrand() uint32 { return fastrand() }
--- /dev/null
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime_test
+
+import (
+ . "runtime"
+ "testing"
+)
+
+func BenchmarkFastrand(b *testing.B) {
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ Fastrand()
+ }
+ })
+}
+
+func BenchmarkFastrandHashiter(b *testing.B) {
+ var m = make(map[int]int, 10)
+ for i := 0; i < 10; i++ {
+ m[i] = i
+ }
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ for _ = range m {
+ break
+ }
+ }
+ })
+}
// exported value for testing
var hashLoad = loadFactor
-// in asm_*.s
-func fastrand() uint32
+//go:nosplit
+func fastrand() uint32 {
+ mp := getg().m
+ fr := mp.fastrand
+ fr <<= 1
+ fr ^= uint32(int32(fr)>>31) & 0x88888eef
+ mp.fastrand = fr
+ return fr
+}
//go:linkname sync_fastrand sync.fastrand
func sync_fastrand() uint32 { return fastrand() }