SF.*_*SF. 228 compiler-construction optimization benchmarking gcc clang
我目前正在使用GCC,但最近我发现了Clang而且我正在考虑切换.但是有一个决定性的因素 - 它产生的二进制文件的质量(速度,内存占用,可靠性) - 如果gcc -O3
能够生成运行速度快1%或内存减少1%的二进制文件,那么它就是一个交易破坏者.
Clang拥有比GCC更好的编译速度和更低的编译时内存占用,但我真的对基准测试/比较结果编译软件感兴趣 - 你能指点我一些或描述你的经历吗?
Mik*_*han 231
以下是GCC 4.7.2和Clang 3.2 for C++的最新结果.
更新:GCC 4.8.1 v clang 3.3比较如下.
更新:GCC 4.8.2 v clang 3.4比较附加于此.
我维护了一个OSS工具,它是为Linux配备GCC和Clang,以及Microsoft的Windows编译器.该工具,coan,是C/C++源文件和代码行的预处理器和分析器:它的计算配置文件主要是递归下降解析和文件处理.开发分支(这些结果所属的)目前包括大约90个文件中的大约11K LOC.现在,它在C++中被编码,它具有丰富的多态性和模板,但是仍然在许多补丁中陷入困境,因为它不是那么遥远的过去的黑客攻击C.移动语义没有被明确地利用.它是单线程的.我没有认真努力优化它,而"架构"仍然是如此大的ToDo.
我在3.2之前使用Clang只是作为一个实验编译器,因为尽管它具有出色的编译速度和诊断功能,但它的C++ 11标准支持在coan所执行的方面落后于当代GCC版本.在3.2中,这个差距已经结束.
我的Linux测试工具用于当前的coan开发过程,大约70K源文件混合使用单文件解析器测试用例,压力测试消耗1000个文件,场景测试消耗<1K文件.除了报告测试结果外,线束还会累积并显示所消耗的文件总数和coan中消耗的运行时间(它只是将每个coan命令行传递给Linux time
命令并捕获并添加报告的数字).由于任何需要0个可测量时间的测试都将加起来为0,但是这些测试的贡献可以忽略不计.时间统计显示在这样的结尾make check
:
coan_test_timer: info: coan processed 70844 input_files.
coan_test_timer: info: run time in coan: 16.4 secs.
coan_test_timer: info: Average processing time per input file: 0.000231 secs.
Run Code Online (Sandbox Code Playgroud)
我比较了GCC 4.7.2和Clang 3.2之间的测试线束性能,除编译器外所有条件都相同.从Clang 3.2开始,我不再需要在GCC编译的代码片段和Clang替代品之间区分任何预处理器.我在每种情况下构建到相同的C++库(GCC)并在同一终端会话中连续运行所有比较.
我的发布版本的默认优化级别是-O2.我还成功地在-O3测试了构建版本.我连续3次测试每个配置并平均3个结果,结果如下.数据单元中的数字是coan可执行文件处理每个~70K输入文件(读取,解析和写入输出和诊断)所消耗的平均微秒数.
| -O2 | -O3 |O2/O3|
----------|-----|-----|-----|
GCC-4.7.2 | 231 | 237 |0.97 |
----------|-----|-----|-----|
Clang-3.2 | 234 | 186 |1.25 |
----------|-----|-----|------
GCC/Clang |0.99 | 1.27|
Run Code Online (Sandbox Code Playgroud)
任何特定的应用程序都很可能具有对编译器的优点或缺点不公平的特性.严格的基准测试采用多种应用.考虑到这一点,这些数据的值得注意的特征是:
两个编译器的进一步有趣的比较是在这些调查结果发生后不久出现的.Coan自由地使用智能指针,其中一个在文件处理中得到了很大的运用.为了编译器区分,这个特定的智能指针类型在之前的版本中已被typedef,std::unique_ptr<X>
如果配置的编译器对其使用具有足够成熟的支持,则为其他std::shared_ptr<X>
.偏见std::unique_ptr
是愚蠢的,因为这些指针实际上转移了,但std::unique_ptr
看起来更适合替换
std::auto_ptr
C++ 11变体对我来说是新颖的点.
在实验构建的过程中,为了衡量Clang 3.2对此和类似差异的持续需求,我无意中构建了
std::shared_ptr<X>
当我打算构建时std::unique_ptr<X>
,并且惊讶地发现生成的可执行文件,默认为-O2优化,是最快的我已经看到,有时达到184毫秒.每个输入文件.通过对源代码的这一改变,相应的结果就是这些;
| -O2 | -O3 |O2/O3|
----------|-----|-----|-----|
GCC-4.7.2 | 234 | 234 |1.00 |
----------|-----|-----|-----|
Clang-3.2 | 188 | 187 |1.00 |
----------|-----|-----|------
GCC/Clang |1.24 |1.25 |
Run Code Online (Sandbox Code Playgroud)
这里的注意事项是:
在智能指针类型更改之前和之后,Clang能够在-O3优化时构建一个速度更快的coan可执行文件,并且当指针类型是最好的时,它可以在-O2和-O3构建同样更快的可执行文件std::shared_ptr<X>
-为了工作.
一个显而易见的问题是,我无权发表评论,为什么 当大量使用的智能指针类型从独特变为共享时,Clang应该能够在我的应用程序中找到25%-O2的加速,而GCC则无动于衷同样的变化.我也不知道是否应该为Clang的-O2优化对我的智能指针选择的智慧具有如此巨大的敏感性的发现而欢呼或嘘声.
更新:GCC 4.8.1 v clang 3.3
相应的结果现在是:
| -O2 | -O3 |O2/O3|
----------|-----|-----|-----|
GCC-4.8.1 | 442 | 443 |1.00 |
----------|-----|-----|-----|
Clang-3.3 | 374 | 370 |1.01 |
----------|-----|-----|------
GCC/Clang |1.18 |1.20 |
Run Code Online (Sandbox Code Playgroud)
现在所有四个可执行文件的平均时间比以前处理1个文件的时间要长得多,这一事实并未反映最新的编译器性能.这是因为测试应用程序的后期开发分支在此期间已经采用了大量的解析复杂性并且在速度上付出了代价.只有比例很重要.
现在的注意事项并不是新颖的:
将这些结果与GCC 4.7.2和clang 3.2的结果进行比较,可以看出海湾合作委员会已经在每个优化级别上挽回了约四分之一的领先优势.但是,由于测试应用程序在此期间得到了大量开发,因此人们不能自信地将其归因于GCC代码生成中的追赶.(这一次,我注意到了获取时间的应用程序快照,可以再次使用它.)
更新:GCC 4.8.2 v clang 3.4
我完成了GCC 4.8.1 v Clang 3.3的更新,说我会坚持使用相同的coan snaphot进行进一步的更新.但我决定测试一下这个快照(版本301)以及我通过其测试套件的最新开发快照(rev.619).这给结果带来了一点经度,我还有另一个动机:
我原来的帖子指出,我一直在努力优化coan以提高速度.转发时仍然如此.301.但是,在我将计时装置安装到测试装置后,每次运行测试套件时,最新变化的性能影响都让我盯着看.我看到它往往出乎意料地大,而且这种趋势比我觉得功能性增加所带来的更为负面.
通过转速.308自第一次发布以来,测试套件中每个输入文件的平均处理时间增加了一倍以上.那时我对我10年不打扰表现的政策大肆转折.在大量修订中,高达619的性能始终是一个考虑因素,其中大量纯粹用于在基本上更快的线路上重写关键负载承载(尽管没有使用任何非标准编译器功能).看到每个编译器对这个掉头的反应会很有趣,
这是最近两个编译器版本rev.301的现在熟悉的时序矩阵:
coan - rev.301结果
| -O2 | -O3 |O2/O3|
----------|-----|-----|-----|
GCC-4.8.2 | 428 | 428 |1.00 |
----------|-----|-----|-----|
Clang-3.4 | 390 | 365 |1.07 |
----------|-----|-----|------
GCC/Clang | 1.1 | 1.17|
Run Code Online (Sandbox Code Playgroud)
这里的故事仅略有改变,从GCC-4.8.1和Clang-3.3.海湾合作委员会的表现更好一点.Clang的情况更糟糕.噪音很可能解释了这一点.锵仍出来进取-O2
和-O3
将不可能在大多数应用中重要,但会事宜,以相当多的利润.
这是转速矩阵.619.
coan - rev.619结果
| -O2 | -O3 |O2/O3|
----------|-----|-----|-----|
GCC-4.8.2 | 210 | 208 |1.01 |
----------|-----|-----|-----|
Clang-3.4 | 252 | 250 |1.01 |
----------|-----|-----|------
GCC/Clang |0.83 | 0.83|
Run Code Online (Sandbox Code Playgroud)
将301和619数字并排,有几点可以说出来.
我的目标是编写更快的代码,两个编译器都强调了我的努力.但:
海湾合作委员会比克朗更慷慨地回报这些努力.在-O2
优化时,Clang的619版本比301版本快46%:-O3
Clang的改进率为31%.很好,但在每个优化级别,GCC的619构建速度是301的两倍多.
GCC不仅取消了Clang之前的优势.在每个优化级别,海湾合作委员会现在击败克朗17%.
-O3
在619版本中,Clang在301版本中从优化中获得比GCC更多的杠杆作用的能力已经消失.两种编译器都没有从中获益-O3
.
我对这种财富的逆转感到非常惊讶,我怀疑我可能会意外地制造了一个缓慢构建的clang 3.4本身(因为我是从源头构建的).所以我用我的发行版的Clang 3.3重新进行了619测试.结果几乎与3.4相同.
关于掉头的反应:在这里的数字上,当我没有给出任何帮助时,Clang在我的C++代码中的速度比GCC做得好得多.当我全神贯注地帮助时,GCC比Clang做得好得多.
我没有把这个观察提升为一个原则,但我接受了"哪个编译器生成更好的二进制文件?"的教训.是一个问题,即使你指定答案应该是相对的测试套件,仍然不是一个明确的问题,只是计时二进制.
你最好的二进制文件是最快的二进制文件,还是最能补偿廉价制作代码的二进制文件?或者最好地补偿昂贵的 代码,优先考虑可维护性和重用速度?它取决于您生成二元的动机的性质和相对权重,以及您这样做的约束条件.
无论如何,如果你非常关心构建"最好的"二进制文件,那么最好继续检查编译器的连续迭代如何在代码的连续迭代中实现"最佳"的概念.
Nie*_*jou 48
Phoronix对此做了一些基准测试,但它是几个月前的Clang/LLVM的快照版本.结果是事情或多或少是推动; 在所有情况下,GCC和Clang都没有明确的优势.
既然你使用的是最新的Clang,那可能就不那么相关了.然后,GCC 4.6显然将对Core 2和i7进行一些重大优化.
我认为Clang更快的编译速度对于原始开发人员来说会更好,然后当你将代码推向世界时,Linux发行版/ BSD /等等.最终用户将使用GCC来获得更快的二进制文件.
小智 12
在得到的二进制文件的速度方面,GCC 4.8和clang 3.3之间的总体差异非常小.在大多数情况下,两个编译器生成的代码执行类似.这两个编译器都不支配另一个编译器.
基准测试表明GCC和clang之间存在显着的性能差距是巧合.
程序性能受编译器选择的影响.如果开发人员或一组开发人员专门使用GCC,那么使用GCC可以使程序运行速度略快于使用GCC,反之亦然.
从开发人员的角度来看,GCC 4.8+和clang 3.3之间的显着差异在于GCC具有-Og
命令行选项.此选项启用不会干扰调试的优化,因此例如始终可以获得准确的堆栈跟踪.clang中没有这个选项使得clang更难用作一些开发人员的优化编译器.
确定这一点的唯一方法是尝试它.FWIW我已经看到使用Apple的LLVM gcc 4.2与常规gcc 4.2(对于具有相当多SSE的x86-64代码)相比有一些非常好的改进,但YMMV用于不同的代码库.假设您正在使用x86/x86-64,并且您确实关心最后几个百分比,那么您也应该尝试使用英特尔的ICC,因为这通常可以胜过gcc - 您可以从intel.com获得30天的评估许可并尝试一下.
我在gcc 5.2.1和clang 3.6.2上注意到的一个独特的区别是,如果你有一个像以下那样的关键循环:
for (;;) {
if (!visited) {
....
}
node++;
if (!*node) break;
}
Run Code Online (Sandbox Code Playgroud)
然后gcc将在用-O3
或编译时-O2
,推测性地将循环展开八次.Clang根本不会展开它.通过反复试验,我发现在我的程序数据的具体情况下,正确的展开量为5,因此gcc打捞并且低位咳嗽.但是,过度投票对绩效的影响更大,所以gcc在这里的表现要差得多.
我不知道展开的差异是一般趋势还是仅仅是我的场景特有的东西.
前段时间我写了一些垃圾收集器来教我自己更多关于C语言中的性能优化.我得到的结果在我的脑海中足以略微赞成clang.特别是因为垃圾收集主要是关于指针追逐和复制存储器.
结果是(以秒为单位的数字):
+---------------------+-----+-----+
|Type |GCC |Clang|
+---------------------+-----+-----+
|Copying GC |22.46|22.55|
|Copying GC, optimized|22.01|20.22|
|Mark & Sweep | 8.72| 8.38|
|Ref Counting/Cycles |15.14|14.49|
|Ref Counting/Plain | 9.94| 9.32|
+---------------------+-----+-----+
Run Code Online (Sandbox Code Playgroud)
这都是纯C代码,在编译C++代码时我对编译器性能没有任何要求.
在Ubuntu 15.10,x86.64和AMD Phenom(tm)II X6 1090T处理器上.
基本上来说,答案是:视情况而定。有许多针对不同类型应用程序的基准测试。
我的应用程序的基准是:GCC > ICC > Clang。
I/O很少,但是CPU浮点和数据结构操作很多。
编译标志为-Wall -g -DNDEBUG -O3。
https://github.com/zhangyafeikimi/ml-pack/blob/master/gbdt/profile/benchmark
归档时间: |
|
查看次数: |
104418 次 |
最近记录: |