go 中 ASM 函数调用的开销
Overhead of ASM-function-call in go
我目前在玩 go,它是汇编、浮点运算的性能 (float32
) 和纳秒级的优化。我对一个简单函数调用的开销感到有点困惑:
func BenchmarkEmpty(b *testing.B) {
for i := 0; i < b.N; i++ {
}
}
func BenchmarkNop(b *testing.B) {
for i := 0; i < b.N; i++ {
doNop()
}
}
执行doNop:
TEXT ·doNop(SB),0,[=11=]-0
RET
结果(go test -bench .
):
BenchmarkEmpty 2000000000 0.30 ns/op
BenchmarkNop 2000000000 1.73 ns/op
我不习惯汇编和/或 go 的内部结构。 go 编译器/链接器可以内联汇编中定义的函数吗?我能以某种方式给链接器一个提示吗?对于像 'add two R3-vectors' 这样的一些简单函数,这会耗尽所有可能的性能增益。
(转到 1.4.2,amd64)
汇编函数不是内联的。以下是您可以尝试的 3 件事:
将您的循环移动到汇编中。例如这个函数:
func Sum(xs []int64) int64
你可以这样做:
#include "textflag.h"
TEXT ·Sum(SB),NOSPLIT,[=11=]-24
MOVQ xs+0(FP),DI
MOVQ xs+8(FP),SI
MOVQ [=11=],CX
MOVQ [=11=],AX
L1: CMPQ AX,SI // i < len(xs)
JGE Z1
LEAQ (DI)(AX*8),BX // BX = &xs[i]
MOVQ (BX),BX // BX = *BX
ADDQ BX,CX // CX += BX
INCQ AX // i++
JMP L1
Z1: MOVQ CX,ret+24(FP)
RET
如果您查看标准库,您会看到这样的示例。
用 c 编写一些代码,利用它对内部函数或内联汇编的支持,并使用 cgo 从 go 调用它。
使用 gccgo 做与 #2 相同的事情,除了你可以直接做:
//extern open
func c_open(name *byte, mode int, perm int) int
我目前在玩 go,它是汇编、浮点运算的性能 (float32
) 和纳秒级的优化。我对一个简单函数调用的开销感到有点困惑:
func BenchmarkEmpty(b *testing.B) {
for i := 0; i < b.N; i++ {
}
}
func BenchmarkNop(b *testing.B) {
for i := 0; i < b.N; i++ {
doNop()
}
}
执行doNop:
TEXT ·doNop(SB),0,[=11=]-0
RET
结果(go test -bench .
):
BenchmarkEmpty 2000000000 0.30 ns/op
BenchmarkNop 2000000000 1.73 ns/op
我不习惯汇编和/或 go 的内部结构。 go 编译器/链接器可以内联汇编中定义的函数吗?我能以某种方式给链接器一个提示吗?对于像 'add two R3-vectors' 这样的一些简单函数,这会耗尽所有可能的性能增益。
(转到 1.4.2,amd64)
汇编函数不是内联的。以下是您可以尝试的 3 件事:
将您的循环移动到汇编中。例如这个函数:
func Sum(xs []int64) int64
你可以这样做:
#include "textflag.h" TEXT ·Sum(SB),NOSPLIT,[=11=]-24 MOVQ xs+0(FP),DI MOVQ xs+8(FP),SI MOVQ [=11=],CX MOVQ [=11=],AX L1: CMPQ AX,SI // i < len(xs) JGE Z1 LEAQ (DI)(AX*8),BX // BX = &xs[i] MOVQ (BX),BX // BX = *BX ADDQ BX,CX // CX += BX INCQ AX // i++ JMP L1 Z1: MOVQ CX,ret+24(FP) RET
如果您查看标准库,您会看到这样的示例。
用 c 编写一些代码,利用它对内部函数或内联汇编的支持,并使用 cgo 从 go 调用它。
使用 gccgo 做与 #2 相同的事情,除了你可以直接做:
//extern open func c_open(name *byte, mode int, perm int) int