【问题标题】:Overhead of ASM-function-call in gogo 中 ASM 函数调用的开销
【发布时间】:2015-04-11 19:57:24
【问题描述】:

我目前正在玩 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,$0-0
    RET

结果(go test -bench .):

BenchmarkEmpty        2000000000               0.30 ns/op
BenchmarkNop  2000000000               1.73 ns/op

我不习惯 Go 的组装和/或内部结构。 go 编译器/链接器可以内联程序集中定义的函数吗?我可以以某种方式给链接器一个提示吗?对于一些简单的函数,比如“添加两个 R3 向量”,这会消耗所有可能的性能提升。

(转到 1.4.2,amd64)

【问题讨论】:

  • 你确定 Go 不只是优化 BenchmarkEmpty() 中的循环吗?如果是这样,将 BenchmarkEmpty 与 BenchmarkNop 进行比较就不算什么了。
  • 是的,我确定。我已经查看了反汇编,并且循环仍然存在。顺便说一句,doNop (func doNopGeneric(){}) 的通用实现已被优化掉。

标签: performance optimization assembly go


【解决方案1】:

汇编函数没有内联。您可以尝试以下 3 件事:

  1. 将您的循环移动到程序集中。以这个函数为例:

    func Sum(xs []int64) int64
    

    你可以这样做:

    #include "textflag.h"
    
    TEXT ·Sum(SB),NOSPLIT,$0-24
        MOVQ  xs+0(FP),DI
        MOVQ  xs+8(FP),SI
        MOVQ  $0,CX
        MOVQ  $0,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

【讨论】:

  • 我希望在 ASM 中内联一些原始函数,并且仍然在 go 中构建我的算法。但是否定的答案仍然是答案;)
猜你喜欢
  • 1970-01-01
  • 2011-11-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多