Skip to content

Instantly share code, notes, and snippets.

@aclements
Created March 17, 2017 19:59
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save aclements/daa93116efc7202bb542e34bb229fd82 to your computer and use it in GitHub Desktop.
Benchmark of different ways to guard the POPCNT instruction
// Requires https://go-review.googlesource.com/c/38320
package popcnt
import (
"math/bits"
"testing"
)
var sink interface{}
func BenchmarkUnguarded(b *testing.B) {
var sum int
for i := uint64(0); i < uint64(b.N); i++ {
sum += bits.OnesCount64(i)
}
sink = sum
}
var havePopcount = true
func BenchmarkGlobal(b *testing.B) {
// Test a global with a call as the slow path.
var sum int
for i := uint64(0); i < uint64(b.N); i++ {
var pop int
if havePopcount {
pop = bits.OnesCount64(i)
} else {
pop = slowOnesCount64(i)
}
sum += pop
}
sink = sum
}
var popcountFunc = bits.OnesCount64
func BenchmarkIndirect(b *testing.B) {
// Call through a global function pointer.
var sum int
for i := uint64(0); i < uint64(b.N); i++ {
sum += popcountFunc(i)
}
sink = sum
}
func BenchmarkCodegen(b *testing.B) {
// Simulate calling out to a generated code page.
var sum int
for i := uint64(0); i < uint64(b.N); i++ {
sum += popcountCodePage(i)
}
sink = sum
}
func slowOnesCount64(x uint64) int {
const m = 1<<64 - 1
const m0 = 0x5555555555555555 // 01010101 ...
const m1 = 0x3333333333333333 // 00110011 ...
const m2 = 0x0f0f0f0f0f0f0f0f // 00001111 ...
const m3 = 0x00ff00ff00ff00ff // etc.
const m4 = 0x0000ffff0000ffff
x = x>>1&(m0&m) + x&(m0&m)
x = x>>2&(m1&m) + x&(m1&m)
x = (x>>4 + x) & (m2 & m)
x += x >> 8
x += x >> 16
x += x >> 32
return int(x) & (1<<7 - 1)
}
//go:noinline
func popcountCodePage(x uint64) int {
return bits.OnesCount64(x)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment