Clang vs GCC - 产生更好的二进制文件?

时间:2010-07-06 15:01:51

标签: optimization gcc compiler-construction clang benchmarking

我目前正在使用GCC,但最近我发现了Clang而且我正在考虑切换。但是有一个决定因素 - 它产生的二进制文件的质量(速度,内存占用,可靠性) - 如果gcc -O3可以生成运行速度快1%或内存减少1%的二进制文件,那么它就是一个交易破坏者。 / p>

Clang拥有比GCC更好的编译速度和更低的编译时内存占用空间,但我真的对基准测试/比较结果编译软件感兴趣 - 你能指点我一些或描述你的经历吗?

7 个答案:

答案 0 :(得分:223)

以下是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比较附加于此。

我维护了一个为Linux和GCC以及Clang构建的OSS工具, 以及Microsoft的Windows编译器。工具coan是一个预处理器 和分析器的C / C ++源文件和代码行: 计算简介主要介绍递归下降解析和文件处理。 开发分支(这些结果属于) 目前包含约11K LOC约90个文件。它是编码的, 现在,在C ++中,它具有丰富的多态性和模板,但仍然存在 由于其不那么遥远的过去在黑客攻击中陷入困境。 移动语义没有被明确利用。它是单线程的。一世 并没有认真努力优化它,而#34;架构" 仍然是如此大的ToDo。

我在3.2之前使用Clang仅作为实验编译器 因为,尽管它具有出色的编译速度和诊断功能 C ++ 11标准支持落后于当代GCC版本 由coan行使的尊重。在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.

我将测试线束性能比作GCC 4.7.2和 Clang 3.2,除编译器外,所有事情都是平等的。截至Clang 3.2, 我不再需要代码之间的任何预处理器区分 GCC将编译和Clang替代品。我建立了 在每种情况下都使用相同的C ++库(GCC' s)并运行所有比较 连续进入同一终端会议。

我的发布版本的默认优化级别是-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|

任何特定应用程序都很可能具有特征 对编译器的优点或缺点不公平。严谨的基准测试 采用多种应用。考虑到这一点,值得注意的是 这些数据的特征是:

  1. -O3优化对GCC略有不利
  2. -O3优化对Clang来说非常有益
  3. 在-O2优化时,GCC比只用胡须的Clang更快
  4. 在-O3优化方面,Clang比GCC更快。
  5. 两个编译器的另一个有趣的比较是偶然出现的 在那些发现后不久。 Coan自由地使用智能指针和 其中一个在文件处理中大量运用。这个特别 为了便于使用,智能指针类型在之前的版本中已经被typedef&#39; d 编译器区分,如果是std::unique_ptr<X> 配置的编译器对其用法有足够成熟的支持 那个,以及std::shared_ptr<X>。对std::unique_ptr的偏见是 愚蠢,因为这些指针实际上转移了, 但是std::unique_ptr看起来像是替换的更合适的选择 {C> 11变体对我来说是新颖的std::auto_ptr

    在实验构建过程中,以衡量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 |
    

    这里的注意事项是:

    1. 这两种编译器现在都没有从-O3优化中受益。
    2. Clang在每个优化级别上都非常重视GCC。
    3. GCC的性能仅受智能指针类型的轻微影响 更改。
    4. Clang的-O2性能受智能指针类型的影响很大 变化。
    5. 在智能指针类型更改之前和之后,Clang能够构建一个 在-O3优化时可执行的快速可执行程序,它可以 在那时在-O2和-O3构建一个同样更快的可执行文件 指针类型是最好的 - std::shared_ptr<X> - 用于工作。

      我无权评论的一个明显问题是为什么 Clang应该能够在我的应用程序中找到25%-O2的加速时间 一个使用频繁的智能指针类型从唯一变为共享, 海湾合作委员会对同一变化漠不关心。我也不知道自己是否应该这样做 为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 |
      

      现在所有四个可执行文件的平均时间比以前要多得多 1个文件反映最新的编译器&#39;性能。这是由于 事实上,测试应用程序的后期开发分支已经采用了很多 在此期间解析复杂性并以速度为其付出代价。只有比例是 显著。

      现在的注意事项并不是新颖的:

      • GCC对-O3优化无动于衷
      • clang从-O3优化中获益很少
      • clang在每个优化级别上以同样重要的优势击败海湾合作委员会。

      将这些结果与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进行进一步更新。但我决定了 而是在最新的开发上测试该快照(rev.301) 快照我通过它的测试套件(修订版619)。这给出了结果a 经度,我有另一个动机:

      我原来的帖子指出,我一直在努力优化coan for 速度。转发时仍然如此。但是,在我建成之后 每次我运行测试套件时,计时装置进入coan测试工具 最新变化对性能的影响让我盯着我。我看到了 它经常出人意料地大,而且这种趋势的负面影响要大得多 我觉得因功能性的提高而受到赞赏。

      通过rev。 308测试套件中每个输入文件的平均处理时间 自从第一次发布以来,这一数字翻了一倍多。那时我做了一个 重新考虑我不打扰表现的10年政策。在密集 大约619次演出的修订总是一个考虑因素和一个 他们中的很多人纯粹是为了从根本上改写关键的负载承载者 更快的行(虽然没有使用任何非标准的编译器功能)。看到每个编译器对此的反应会很有趣 U形转弯,

      这是最近两个编译器现在熟悉的时序矩阵&#39; rev.301的版本:

      coan - rev.301 results

                | -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|
      

      这里的故事与GCC-4.8.1和Clang-3.3略有不同。海湾合作委员会的表现 是一件好事。 Clang的情况更糟糕。噪音很可能解释了这一点。 Clang仍然以-O2-O3边距排在前面,这在大多数情况下并不重要 应用程序但很重要。

      这是rev的矩阵。 619。

      coan - rev.619 results

                | -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|
      

      将301和619数字并排,有几点可以说出来。

      • 我的目标是编写更快的代码,两个编译器都强调维护 我的努力。但是:

      • 海湾合作委员会比克朗更慷慨地回报这些努力。在-O2 优化Clang的619版本比其301版本快46%:在-O3 Clang&#39; s 改善率为31%。很好,但在每个优化级别GCC的619版本都是 速度是301的两倍多。

      • GCC不仅取消了Clang之前的优势。并在每次优化 海湾合作委员会现在比克朗高出17%。

      • Clang在301版本中的能力比-O3优化中的GCC更具杠杆作用 已经在619版本中消失了。两个编译器都没有从-O3获得有意义的收益。

      我对我怀疑的财富逆转感到非常惊讶 可能不小心制造了一个蹩脚的clang 3.4本身(自从我建造以来) 它来自源头)。所以我用我的发行公司Clang 3.3重新进行了619测试。该 结果几乎与3.4相同。

      关于掉头的反应:在这里的数字,Clang做了很多 当我没有给它时,我的C ++代码的速度比GCC更好 救命。当我全神贯注地帮助时,海湾合作委员会做得比克朗好得多。

      我没有将这个观察提升为一个原则,但我认为 &#34;哪个编译器产生更好的二进制文件的教训?&#34;是个问题 即使您指定了答案相对的测试套件, 仅仅定时二进制文件仍然不是一个明确的问题。

      你的二进制文件是最快的二进制文件,还是最好的二进制文件 补偿廉价制作的代码?或者最好地补偿昂贵的 精心设计的代码,优先考虑可维护性和重用速度?这取决于 生产二元的动机的性质和相对权重,以及 你这样做的限制因素。

      无论如何,如果你非常关心建设&#34;最好的&#34;二进制文件然后你 最好继续检查编译器的连续迭代如何实现 &#34;最好的&#34;在代码的连续迭代中。

答案 1 :(得分:46)

Phoronix对此做了一些benchmarks,但它是关于几个月前Clang / LLVM的快照版本。结果是事情或多或少是推动;在所有情况下,GCC和Clang都没有明确的优势。

由于您使用的是最新的Clang,因此它可能不那么相关。然后,GCC 4.6显然会为Core 2和i7提供一些major optimizations,显然。

我认为Clang更快的编译速度对于原始开发人员来说会更好,然后当你将代码推向世界时,Linux发行版/ BSD /等等。最终用户将使用GCC来获得更快的二进制文件。

答案 2 :(得分:15)

Clang编译代码的速度可能不如生成的二进制文件的速度那么重要。但是,这是一个series of benchmarks

答案 3 :(得分:12)

在得到的二进制文件的速度方面,GCC 4.8和clang 3.3之间的总体差异非常小。在大多数情况下,两个编译器生成的代码执行类似。这两个编译器都不支配另一个编译器。

基准测试表明GCC和clang之间存在显着的性能差距是巧合。

程序性能受编译器选择的影响。如果开发人员或一组开发人员专门使用GCC,那么使用GCC可以使程序运行速度略快于使用GCC,反之亦然。

从开发人员的角度来看,GCC 4.8+和clang 3.3之间的显着差异在于GCC具有-Og命令行选项。此选项启用不会干扰调试的优化,因此例如始终可以获得准确的堆栈跟踪。 clang中没有这个选项使得clang更难用作一些开发人员的优化编译器。

答案 4 :(得分:9)

确定这一点的唯一方法是尝试它。 FWIW我已经看到使用Apple的LLVM gcc 4.2与常规gcc 4.2(对于具有相当多SSE的x86-64代码)相比有一些非常好的改进,但YMMV用于不同的代码库。假设你正在使用x86 / x86-64并且你确实关心最后几个百分比,那么你也应该尝试英特尔的ICC,因为这通常可以击败gcc - 你可以从intel.com获得30天的评估许可并尝试一下。

答案 5 :(得分:7)

我在gcc 5.2.1和clang 3.6.2上注意到的一个独特的区别是 如果你有一个像:

这样的关键循环
for (;;) {
    if (!visited) {
        ....
    }
    node++;
    if (!*node) break;
  }

然后gcc将在推测时使用-O3-O2进行编译 展开循环八次。 Clang根本不会展开它。通过 试验和错误我发现在我的程序数据的具体情况下, 适当数量的展开是五个所以gcc打捞和铿锵 下颚。但是,过度投资对绩效的影响更大 gcc在这里表现得更糟。

如果展开差异是一般趋势,我不知道 只是特定于我的场景的东西。

前段时间我写了few garbage collectors来自学更多 关于C中的性能优化。我得到的结果是在我的 心里想要略微偏爱铿锵。特别是因为垃圾 集合主要是关于指针追逐和复制内存。

结果是(以秒为单位的数字):

+---------------------+-----+-----+
|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|
+---------------------+-----+-----+

这是纯粹的C代码,我对这两个编译器都没有任何说法 编译C ++代码时的性能。

在Ubuntu 15.10,x86.64和AMD Phenom(tm)II X6 1090T处理器上。

答案 6 :(得分:4)

基本上,答案是:它取决于。 有许多基准专注于不同类型的应用。

我的应用程序的基准是:gcc&gt; icc&gt;铛。

有很少的IO,但很多CPU浮动和数据结构操作。

编译标志是-Wall -g -DNDEBUG -O3。

https://github.com/zhangyafeikimi/ml-pack/blob/master/gbdt/profile/benchmark