为什么使用gccgo构建的二进制文件更小(除其他差异外?)

为什么使用gccgo构建的二进制文件更小(除其他差异外?),go,gccgo,Go,Gccgo,我一直在试验gc和gccgo,我遇到了一些奇怪的行为 使用我曾经写过的一个测试定理,我得到了以下结果:(为了可读性,我删除了不必要的信息) $time go build-compiler gc-o checkprog\u gc checkprog.go(x 3) go构建0.13s用户0.02s系统100%cpu总计0.149 go构建0.13s用户0.01s系统99%cpu 0.148总计 go build 0.14s用户0.03s系统100%cpu总计0.162 -->平均值:0.13秒用户

我一直在试验gc和gccgo,我遇到了一些奇怪的行为

使用我曾经写过的一个测试定理,我得到了以下结果:(为了可读性,我删除了不必要的信息)

$time go build-compiler gc-o checkprog\u gc checkprog.go(x 3)
go构建0.13s用户0.02s系统100%cpu总计0.149
go构建0.13s用户0.01s系统99%cpu 0.148总计
go build 0.14s用户0.03s系统100%cpu总计0.162
-->平均值:0.13秒用户0.02秒系统100%cpu总计0.153
$time go build-编译器gccgo-o checkprog\u gccgo checkprog.go(x 3)
go构建0.10s用户0.03s系统96%cpu 0.135总计
go构建0.12s用户0.01s系统96%cpu 0.131总计
go构建0.10s用户0.01s系统92%cpu 0.123总计
-->平均值:0.11s用户0.02s系统95%cpu总计0.130
$strip-s-o checkprog\u gc\u stripped checkprog\u gc
$strip-s-o checkprog\u gccgo\u剥离checkprog\u gccgo
$ls-l
1834504 checkprog_gc*
1336992检查程序气相色谱仪*
35072检查程序(gccgo)*
24192检查程序gccgo*
$time./checkprog\u gc
./checkprog_gc 6.68s用户0.01s系统100%cpu 6.674总计
./checkprog_gc 6.75s用户0.01s系统100%cpu 6.741总计
./checkprog_gc 6.66s用户0.00s系统100%cpu 6.643总计
-->平均:6.70秒用户0.01秒系统100%cpu总计6.686
$time./checkprog\u gccgo
./checkprog_gccgo 10.95s用户0.02s系统100%cpu 10.949总计
./checkprog_gccgo 10.98s用户0.01s系统100%cpu 10.964总计
./checkprog_gccgo 10.94s用户0.01s系统100%cpu 10.929总计
-->平均10.96s用户0.01s系统100%cpu总计10.947
我可以看到以下模式:

  • 使用
    gccgo
    构建的二进制文件的大小要小得多(剥离无助于改变这种差异)
  • 使用
    gc
    构建的二进制文件执行速度更快
  • 使用
    gccgo
    构建比使用
    gc
  • 我还测试了其他一些围棋程序(虽然没有那么广泛),它们都表现出相同的行为

    这似乎与以下陈述相矛盾:

    简而言之:gccgo:更多优化,更多处理器。

    我认为更多的优化意味着更快的二进制文件,同时需要更多的时间来编译


    这三种模式的原因是什么?

    大小不同,因为gc生成静态二进制文件,gccgo链接到libgo。这意味着整个运行时(调度程序、垃圾收集器、映射、通道)的代码不是gccgo创建的最终二进制代码

    编译的速度当然有利于gc。GC是在考虑编译速度的情况下构建的。它通常也会生成较少优化的代码,并且需要执行的工作也较少


    现在我们来看看为什么gc速度更快。事实上,两者都不总是比另一个快。例如,尝试md5一个文件,GCCGO将快一个数量级。尝试用很多渠道实现一些东西,gc肯定会赢。你不能总是提前知道哪个会成功。GC倾向于具有更高效的并发性,而gccgo倾向于在数学方面更出色。但是,这是您需要逐个测试的。最好使用go test的基准测试系统,而不是时间。

    有很多不同之处--:

    • gccgo
      可以生成一个二进制文件,动态链接到
      libgo
      ,这使得输出更小,但意味着要在目标机器上安装相关的库。没有cgo的Go二进制文件没有这个要求
    • gccgo
      进行了更多的低级优化,因为它可以使用
      gcc
      的代码生成器和优化器。gccgo编写了一些数据压缩代码,其运行速度明显快于
      gc
      。同样的优化使编译器速度变慢:它正在做更多的工作
    • gccgo
      支持
      gcc
      所支持的目标处理器,因此这是使用SPARC、ARMv8(64位)或POWER等体系结构的唯一方法。(Canonical使用它为arm64和ppc64编译Juju服务编排工具。)
    • gccgo
      gc
      都支持ARMv7(32位),但根据bradfitz的谈话
      gc
      不能生成最有效的ARM代码
    • 只有
      gc
      进行了某些优化。
      • 一个大问题是,编译器确定某些变量永远不会“转义”分配给它们的函数,因此可以进行堆栈分配。(因此,令人惊讶的是,
        new(T)
        如果返回值没有转义,可能不会进行堆分配。)这减少了垃圾收集需要运行的频率
      • 另一个原因是标准库中的
        .s
        汇编文件仅通过
        gc
        链接,因此默认情况下
        gccgo
        不使用英特尔硬件CRC32C之类的东西(您必须提供专门用于gccgo的实现)
    • gc
      首先实现新的语言功能,通常比最新的
      gccgo
      早一两个版本

    很可能是因为它们链接到
    libgo
    ldd
    readelf
    会告诉你(如果你在Linux系统上)。(制作此CW是因为关于gc/gccgo的差异可能有很多话要说,我不是一个真正的专家,我希望了解更多的人能够编辑它。)
    $ time go build -compiler gc -o checkprog_gc checkprog.go (x 3)
    go build <...>    0.13s user 0.02s system 100% cpu 0.149 total
    go build <...>    0.13s user 0.01s system 99%  cpu 0.148 total
    go build <...>    0.14s user 0.03s system 100% cpu 0.162 total
     --> average:     0.13s user 0.02s system 100% cpu 0.153 total
    
    
    $ time go build -compiler gccgo -o checkprog_gccgo checkprog.go (x 3)
    go build <...>    0.10s user 0.03s system 96% cpu 0.135 total
    go build <...>    0.12s user 0.01s system 96% cpu 0.131 total
    go build <...>    0.10s user 0.01s system 92% cpu 0.123 total
     --> average:     0.11s user 0.02s system 95% cpu 0.130 total
    
    
    $ strip -s -o checkprog_gc_stripped checkprog_gc
    $ strip -s -o checkprog_gccgo_stripped checkprog_gccgo
    
    $ ls -l
     1834504 checkprog_gc*
     1336992 checkprog_gc_stripped*
       35072 checkprog_gccgo*
       24192 checkprog_gccgo_stripped*
    
    $ time ./checkprog_gc
    ./checkprog_gc  6.68s user 0.01s system 100% cpu 6.674 total
    ./checkprog_gc  6.75s user 0.01s system 100% cpu 6.741 total
    ./checkprog_gc  6.66s user 0.00s system 100% cpu 6.643 total
     --> average:   6.70s user 0.01s system 100% cpu 6.686 total
    
    $ time ./checkprog_gccgo
    ./checkprog_gccgo  10.95s user 0.02s system 100% cpu 10.949 total
    ./checkprog_gccgo  10.98s user 0.01s system 100% cpu 10.964 total
    ./checkprog_gccgo  10.94s user 0.01s system 100% cpu 10.929 total
     --> average       10.96s user 0.01s system 100% cpu 10.947 total