hbits.morePointers and hbits.isPointer both
do a load and a shift. Do it only once.
Benchmarks using compilebench (because it is
the benchmark I have the most tooling around),
on a quiet machine.
name old time/op new time/op delta
Template 291ms ±14% 290ms ±15% ~ (p=0.702 n=100+99)
Unicode 143ms ± 9% 142ms ± 9% ~ (p=0.126 n=99+98)
GoTypes 934ms ± 4% 933ms ± 4% ~ (p=0.937 n=100+100)
Compiler 4.92s ± 2% 4.90s ± 1% -0.28% (p=0.003 n=98+98)
name old user-ns/op new user-ns/op delta
Template 360user-ms ± 5% 355user-ms ± 4% -1.37% (p=0.000 n=97+96)
Unicode 178user-ms ± 6% 176user-ms ± 6% -1.24% (p=0.001 n=96+99)
GoTypes 1.22user-s ± 5% 1.21user-s ± 5% -0.94% (p=0.000 n=100+100)
Compiler 6.50user-s ± 2% 6.44user-s ± 3% -0.94% (p=0.000 n=96+98)
On amd64, before:
"".scanobject t=1 size=581 args=0x10 locals=0x78
After:
"".scanobject t=1 size=540 args=0x10 locals=0x78
Change-Id: I420ac3704549d484a5d85e19fea82c85da389514
Reviewed-on: https://go-review.googlesource.com/22712
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
Reviewed-by: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
// Avoid needless hbits.next() on last iteration.
hbits = hbits.next()
}
+ // Load bits once. See CL 22712 and issue 16973 for discussion.
+ bits := hbits.bits()
// During checkmarking, 1-word objects store the checkmark
// in the type bit for the one word. The only one-word objects
// are pointers, or else they'd be merged with other non-pointer
// data into larger allocations.
- if i != 1*sys.PtrSize && !hbits.morePointers() {
+ if i != 1*sys.PtrSize && bits&bitScan == 0 {
break // no more pointers in this object
}
- if !hbits.isPointer() {
+ if bits&bitPointer == 0 {
continue // not a pointer
}