我一直在嘗試在 Go 中使用匯編語言,并編寫了一個(gè)漢明權(quán)函數(shù)作為練習(xí)。我已經(jīng)在這個(gè) SO 答案上建立了一個(gè)本地 Go 版本,程序集版本基于來自 AMD (page 180) 的這個(gè)文檔。在對這兩個(gè)函數(shù)進(jìn)行基準(zhǔn)測試后,我發(fā)現(xiàn)原生 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行包含垃圾收集器的信息,但除此之外我沒有看到任何明顯的差異。什么可能導(dǎo)致這兩個(gè)功能之間的速度差異如此大?
編譯與手寫程序集的性能差異
慕無忌1623718
2021-08-10 17:15:09