在这种特殊情况下,为啥 gccgo 比 gc 慢?

Posted

技术标签:

【中文标题】在这种特殊情况下,为啥 gccgo 比 gc 慢?【英文标题】:Why is gccgo slower than gc in that particular case?在这种特殊情况下,为什么 gccgo 比 gc 慢? 【发布时间】:2013-02-25 17:41:17 【问题描述】:

我相信知道golang 的每个人都知道blog post 在这里。

再读一遍,我想知道使用gccgo 代替go build 是否会提高速度。在我的典型用例(科学计算)中,gccgo 生成的二进制文件总是比go build 生成的二进制文件快。

所以,只需获取这个文件:havlak6.go 并编译它:

go build havlak6.go -O havlak6_go
gccgo -o havlak6_gccgo -march=native -Ofast havlak6.go

惊喜!

$/usr/bin/time ./havlak6_go
5.45user 0.06system 0:05.54elapsed 99%CPU

$/usr/bin/time ./havlak6_gccgo
11.38user 0.16system 0:11.74elapsed 98%CPU

我很好奇,想知道为什么“优化”编译器会产生较慢的代码。

我尝试在gccgo 生成的二进制文件上使用gprof

gccgo -pg -march=native -Ofast havlak6.go
./a.out
gprof a.out gmon.out

没有运气:

Flat profile:

Each sample counts as 0.01 seconds.
 no time accumulated

如您所见,代码实际上并未被分析。

当然,我读过this,但正如你所见,程序执行需要10+秒...样本数应该> 1000。

我也试过了:

rm a.out gmon.out
LDFLAGS='-g -pg' gccgo -g -pg -march=native -Ofast havlak6.go
./a.out
gprof

也没有成功。

你知道有什么问题吗?在这种情况下,您知道为什么 gccgo 及其所有优化例程都不能比 gc 快吗?

go 版本:1.0.2 gcc 版本:4.7.2

编辑:

哦,我完全忘了提...我显然在gccgo生成的二进制文件上尝试了pprof...这是top10

Welcome to pprof!  For help, type 'help'.
(pprof) top10
Total: 1143 samples
    1143 100.0% 100.0%     1143 100.0% 0x00007fbfb04cf1f4
       0   0.0% 100.0%      890  77.9% 0x00007fbfaf81101e
       0   0.0% 100.0%        4   0.3% 0x00007fbfaf8deb64
       0   0.0% 100.0%        1   0.1% 0x00007fbfaf8f2faf
       0   0.0% 100.0%        3   0.3% 0x00007fbfaf8f2fc5
       0   0.0% 100.0%        1   0.1% 0x00007fbfaf8f2fc9
       0   0.0% 100.0%        1   0.1% 0x00007fbfaf8f2fd6
       0   0.0% 100.0%        1   0.1% 0x00007fbfaf8f2fdf
       0   0.0% 100.0%        2   0.2% 0x00007fbfaf8f4a2f
       0   0.0% 100.0%        1   0.1% 0x00007fbfaf8f4a33

这就是我寻找其他东西的原因。

EDIT2:

由于似乎有人希望我的问题被关闭,我没有尝试使用 gprof 出乎意料:https://groups.google.com/d/msg/golang-nuts/1xESoT5Xcd0/bpMvxQeJguMJ

【问题讨论】:

人们仍然believe in gprof as the canonical profiler.。几点: 1) gprof 仅对具有浅调用堆栈的 CPU 绑定程序有用,没有递归,它具有所有符号。 2) 编译器优化只对紧密的内部循环或在您的代码中调用很多的例程产生影响,这些例程本身并不调用函数(如内存分配等)。编译器优化不仅仅是让一切变得更快。 是的,我为 gprof 得到了它。我同意你对编译器优化的看法。但是,我不希望使用具有优化能力的编译器获得更差的性能。性能应该相等或更好。如果没有,还有改进的余地,我想了解原因:) 我唯一做过的时间是端到端的,可能重复 10^n 次并除以它,我不寻找超过 3 位数的准确度。有噪音,我不在乎。然后我使用随机暂停来寻找让它更快的方法。除非它已经像海绵一样被挤压了,否则我会想办法,然后我可以从头再来。当几个周期后我遇到收益递减,并且 pc 最常出现在我生成的指令中时,然后我打开优化器,这可能使其速度提高 10%。哎呀。 【参考方案1】:

在 Valgrind 下运行 gccgo 生成的二进制文件似乎表明 gccgo 的内存分配器效率低下。这可能是gccgo 4.7.2 比go 1.0.2 慢的原因之一。在 Valgrind 下运行 go 1.0.2 生成的二进制文件是不可能的,因此很难确定内存分配是否是 gccgo 在这种情况下的主要性能问题。

【讨论】:

感谢您提及Valgrind。那是我第一次深入研究分析,虽然 gprof 是分析器...我错了 :) 但是似乎 Valgrind 是一个仅限 C 的分析器/分析框架。它抱怨未初始化的值,似乎根本没有“得到”……你能详细说明一下吗? 我使用 valgrind --tool=callgrind 和 KCacheGrind 来检查 gccgo 生成的代码的行为。 Valgrind 的 callgrind 也能够运行许多非 C 代码,但不幸的是,它所做的假设违反了 go1.0.2 生成的二进制文件。 code.google.com/p/go/issues/detail?id=782【参考方案2】:

请记住,go build 也默认为静态链接,因此对于苹果与苹果的比较,您应该为 gccgo 提供 -static-static-libgo 选项。

【讨论】:

以上是关于在这种特殊情况下,为啥 gccgo 比 gc 慢?的主要内容,如果未能解决你的问题,请参考以下文章

为啥在我的情况下快速排序总是比冒泡排序慢?

在这种情况下,为啥串行代码比 concurrent.futures 快?

为啥在这种特殊情况下 git revert 后我会发生冲突

Serializable 是如何工作的,为啥使用起来比 Parcelable 慢? [复制]

为啥 renderInContext 比绘制到屏幕慢得多?

php 中的时间为啥慢8个小时