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 件事:

  1. 将您的循环移动到汇编中。例如这个函数:

    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
    

    如果您查看标准库,您会看到这样的示例。

  2. 用 c 编写一些代码,利用它对内部函数或内联汇编的支持,并使用 cgo 从 go 调用它。

  3. 使用 gccgo 做与 #2 相同的事情,除了你可以直接做:

    //extern open
    func c_open(name *byte, mode int, perm int) int
    

    https://golang.org/doc/install/gccgo#Function_names