我一直在尝试在 Go 中使用汇编语言,并编写了一个汉明权函数作为练习。我已经在这个 SO 答案上建立了一个本地 Go 版本,程序集版本基于来自 AMD (page 180) 的这个文档。在对这两个函数进行基准测试后,我发现原生 Go 版本比汇编版本快 1.5 到 2 倍,尽管手写汇编版本几乎与go tool 6g -S popcount.go.输出 go test -bench=.PASSBenchmarkPopCount 100000000 19.4 ns/op BenchmarkPopCount_g 200000000 8.97 ns/opok popcount 4.777spopcount.gopackage popcountfunc popCount(i uint32) uint32 // Defined in popcount_amd64.sfunc popCount_g(i uint32) uint32 { i = i - ((i >> 1) & 0x55555555) i = (i & 0x33333333) + ((i >> 2) & 0x33333333) return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24}popcount_test.gopackage popcountimport "testing"func TestPopcount(t *testing.T) { for i := uint32(0); i < uint32(100); i++ { if popCount(i) != popCount_g(i) { t.Fatalf("failed on input = %v", i) } }}func BenchmarkPopCount(b *testing.B) { for i := 0; i < b.N; i++ { popCount(uint32(i)) }}func BenchmarkPopCount_g(b *testing.B) { for i := 0; i < b.N; i++ { popCount_g(uint32(i)) }}popcount_amd64.s// func popCount(i uint32) uint32TEXT ·popCount(SB),$0 MOVL i+0(FP), BP // i MOVL BP, BX // i SHRL $1, BX // i >> 1 ANDL $0x055555555, BX // (i >> 1) & 0x55555555 SUBL BX, BP // w = i - ((i >> 1) & 0x55555555) MOVL BP, AX // w SHRL $2, BP // w >> 2 ANDL $0x033333333, AX // w & 0x33333333 ANDL $0x033333333, BP // (w >> 2) & 0x33333333输出 go tool 6g -S popcount.go我从这里知道这些FUNCDATA行包含垃圾收集器的信息,但除此之外我没有看到任何明显的差异。什么可能导致这两个功能之间的速度差异如此大?
1 回答
- 1 回答
- 0 关注
- 179 浏览
添加回答
举报
0/150
提交
取消