Clang vs GCC-产生更好的二进制文件?[关闭]


238

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

与GCC相比,Clang具有更好的编译速度和更低的编译时内存占用空间,但是我对生成的编译软件的基准测试/比较非常感兴趣-您能指出我的观点还是描述您的经验?


5
似乎仍然是一个有价值的问题和回应,许多人对此感兴趣。
YasserAsmi '16

9
@YasserAsmi:两个指标-内存占用和执行速度-绝不是随意的,也不是“意见”。但是似乎Physics.SE的疾病在这里传播开来,人们也开始投票关闭,而这里也没有阅读问题的详细信息。
SF。

12
该问题要求进行基准测试和比较,答案均同时给出...为什么使用此观点而不是事实比较?
oemb1905

2
不明白为什么这个问题被关闭了。无论是基于观点还是基于事实,我们都想知道答案,并将其标记为“已关闭”会给人负面的色彩,不应有一个色彩。
蒂莫西·马科布

2
@TomZych:如果您想了解这些因素,请提出不同的问题。这是非常具体且明确的-要求执行速度和内存占用。您可能对其他对您有利的因素感兴趣,这并不意味着这个问题无效,只是不符合您的个人利益。就像您是Java程序员一样,您想关闭每个C#问题,因为它没有谈论Java。
SF。

Answers:


239

这是我最新的一些信息,尽管我在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 ++具有丰富的多态性和模板,但是由于其在被砍在一起的C语言中的不那么遥远的过去而仍然陷入许多补丁中。移动语义未得到明确利用。它是单线程的。尽管“架构”仍然主要是待办事项,但我并未花大力气对其进行优化。

我在3.2之前只使用Clang作为实验性编译器,因为尽管Clang 11具有出色的编译速度和诊断功能,但其C ++ 11标准支持在coan方面落后于当代的GCC版本。在3.2版本中,这个差距已经缩小。

我的用于当前coan开发的Linux测试工具在一个文件解析器测试用例,压力测试(消耗1000个文件)和方案测试(小于1K文件)的混合中,大约处理了70K个源文件。除了报告测试结果之外,该工具还累积并显示消耗的文件总数和用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)上,并在同一终端会话中连续运行所有比较。

我的发行版的默认优化级别是-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更快。

在发现之后不久,偶然地出现了两个编译器的进一步有趣的比较。Coan自由地使用智能指针,并且在文件处理中经常使用这种智能指针。为了编译器的差异化,该特定的智能指针类型在先前的发行版中已进行类型定义,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 |

这里的要点是:

  1. 现在,两个编译器都没有从-O3优化中受益。
  2. 在每个优化级别上,Clang击败GCC都同样重要。
  3. GCC的性能仅受智能指针类型更改的影响很小。
  4. Clang的-O2性能受智能指针类型更改的影响很大。

在更改智能指针类型之前和之后,Clang能够在优化-O3的情况下构建速度显着更快的coan可执行文件,并且当该指针类型是最佳指针类型时,它可以在-O2和-O3处构建同样更快的可执行文件std::shared_ptr<X>--为了工作。

我无法评论的一个显而易见的问题是, 当频繁使用的智能指针类型从唯一更改为共享,而GCC却无动于衷时,为什么 Clang应该能够在我的应用程序中将O2速度提高25%进行相同的更改。我也不知道我该为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个文件大得多,这一事实并不能反映最新编译器的性能。这是由于以下事实:测试应用程序的后续开发分支同时进行了大量解析,并为此付出了高昂的代价。只有比率才有意义。

现在,值得注意的地方并不是新颖的:

  • GCC对-O3优化无动于衷
  • clang从-O3优化中获得的收益很小
  • 在每个优化级别上,clang都以同样重要的优势击败了GCC。

将这些结果与GCC 4.7.2和clang 3.2的结果进行比较,可以看出,GCC在每个优化级别上已经收回了clang领先优势的四分之一。但是,由于测试应用程序是在此期间进行了大量开发的,因此无法自信地将其归因于GCC代码生成的赶超。(这一次,我注意到从中获取了时序的应用程序快照,可以再次使用它。)

更新:GCC 4.8.2 v clang 3.4

我完成了GCC 4.8.1 v Clang 3.3的更新,说我将继续使用相同的工具进行进一步的更新。但我决定,而不是在该快照测试(修订版301)最新开发快照我有通过其测试套件(REV。619)。这使结果有点经度,而我还有另一个动机:

我的原始帖子指出,我没有投入任何精力来优化速度。截至转速仍然如此。301.但是,当我将计时装置内置到普通测试装置中后,每次运行测试套件时,最新变化的性能影响使我无所适从。我发现它通常大得令人惊讶,而且趋势比我认为功能增强带来的负面影响要严重得多。

通过转。308自从第一次发布这里以来,测试套件中每个输入文件的平均处理时间已增加了一倍以上。那时,我对10年不打扰性能的政策做了个大转变。在大量的修订中,始终要考虑到高达619个性能,并且其中许多纯粹用于在根本上更快的行上重写关键的负载承受力(尽管这样做没有使用任何非标准的编译器功能)。看到每个编译器对这次掉头的反应都会很有趣,

这是最新熟悉的两个编译器版本rev.301的时序矩阵:

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

此处的故事与GCC-4.8.1和Clang-3.3相比仅有一点变化。GCC的表现要好得多。lang声更糟。噪音很可能造成了这种情况。Clang仍然遥遥领先,-O2-O3利润在大多数应用程序中并不重要,但对很多应用程序而言却至关重要。

这是转速表。619。

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

并列使用301和619数字,可以说出几点。

  • 我的目标是编写更快的代码,并且两个编译器都着力证明我的努力。但:

  • GCC比Clang更慷慨地回报了这些努力。在-O2 优化时,Clang的619版本比其301版本快46%:在-O3Clang的情况下提高31%。不错,但是在每个优化级别,GCC 619的构建速度都是其301的两倍以上。

  • GCC不仅扭转了Clang以前的优势。现在,在每个优化级别,GCC都比Clang高出17%。

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

运气的逆转让我感到十分惊讶,以至于我怀疑自己可能不小心制造了c铛3.4本身(因为我是从源头构建的)。因此,我使用发行版的股票Clang 3.3重新运行了619测试。结果实际上与3.4相同。

因此,对于掉头的反应:在这里的数字上,当我没有提供帮助时,Clang的工作速度比GCC快得多,比我的C ++代码快得多。当我下定决心要提供帮助时,GCC的工作要比Clang好得多。

我没有将这种观察提升为原理,但是我上了一个课,“哪个编译器生成更好的二进制文件?” 这是一个问题,即使您指定答案相对应的测试套件,仅对二进制文件进行计时也不是明确的问题。

更好的二进制文件是最快的二进制文件,还是最能补偿廉价制作代码的二进制文件?还是最好地补偿昂贵的 制作代码,这些代码优先考虑可维护性和重用性而不是速度?它取决于生成二进制文件的动机的性质和相对权重,以及生成二进制文件的限制条件。

在任何情况下,如果您非常关心构建“最佳”二进制文件,则最好继续检查编译器的连续迭代如何在代码的连续迭代中实现“最佳”思想。


9
为什么c更快?例如,intel编译器使用intel芯片的特殊功能。c用来获得优势的是什么?可以重写代码以使gcc具有相同的性能吗?
kirill_igum 2013年

27
@krill_igum GCC和clang是由不同的程序员小组编写的不同(非常复杂)的程序,它们可以完成相同的工作:将源代码转换为目标代码。几乎不可避免的是,在任何选定的测试中,在任何时间点,其中一个都会比另一个做得更好。获胜者不必使用任何特殊的“东西”来“获得优势”,而且由于这两个程序都是开源的,所以彼此之间没有秘密。
Mike Kinghan 2013年

3
可以用来kcachegrind查明所生成的可执行文件性能不同的功能。

4
-1:这更像是一部小说(或博客文章),而不是答案。
约翰·桑德斯

60
@JohnSaunders:对一个人来说,是一个详尽而深入的答案,对另一个人来说,是一部不值得他们注意的小说。告诉我是什么使这两个人分开。
SF。

48

Phoronix对此进行了一些基准测试,但是它是几个月前Clang / LLVM的快照版本。结果是事情或多或少地得到了推动。在所有情况下,GCC和Clang都没有绝对更好的选择。

由于您将使用最新的Clang,因此相关性可能会降低一些。再说一次,GCC 4.6显然将对Core 2和i7进行一些重大优化

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


2
就在今天,我在Clang编译速度上运行了一些基准测试,对于纯C语言来说非常令人失望。使用270 KLOC clang编译35 C文件的速度仅快25%。当我看到linux上tinycc的运行速度有多快时,对于一个新的书面编译器来说是一个不好的结果。当使用优化-O2 / -O3时,它会变得更好,但由于它们用于发行版本,因此在这种情况下编译器的性能无关紧要。
Lothar

7
@mcandre也许Nietzche-jou是用Clang编译的,而您是用GCC编译的。
Mateen Ulhaq 2011年

18

Clang更快地编译代码的事实可能并不像生成二进制文件的速度那么重要。但是,这是一系列基准


12
实际上确实如此。在开发过程中,编译时间(以及由于编译而导致的资源消耗)比二进制性能更多地是瓶颈。毕竟,我们在此阶段以Debug模式进行编译。只有在进入测试和发布阶段时,您才切换到发布模式,并尝试尽快获取二进制文件。
Matthieu M.

3
// @ Matthieu M:我发誓这个回答说“可以。我想也许值得一提,因为它与OP有关。
JM Becker

同意,尽管这里有很多优点。我宁愿放入第二个或第三个RAID 0驱动器,SSD或更多更快的RAM,并获得最佳的.exe性能-只要这些措施可以使您达到同等或相近的水平。有时使用多个编译器进行开发也很有帮助。它可以使您了解不可移植的功能,并捕获原本不会被发现的错误,或者浪费大量时间尝试调试代码,而更好的编译器将警告/错误提示。

我今天尝试比较我编写的一些严格的性能关键整数代码,并且同时使用-O2和-O3来使GCC运行更快(22S clang-llvm 25S)。认为使用编译器开关(gcc或clang)涵盖了大多数非标准功能和静态警告。在您自己的大型项目中,而不是批量编译其他ppl的代码,如果编译时间主导了链接时间,那么您在构建系统中就做错了。有一些工具,例如ccache.samba.org,可以帮助您经常清洁。不断变化的编译器的另一个问题是,始终浪费在测试/验证上的投资。
Rob11311

code.google.com/p/distcc是另一个项目,如果整个库由于数据结构更改或出于验证/验证目的而需要重新编译,则该项目可以加快批量编译时间
Rob11311

11

就生成二进制文件的速度而言,GCC 4.8和clang 3.3之间的总体差异很小。在大多数情况下,两个编译器生成的代码执行情况相似。这两个编译器都不能控制另一个。

基准测试表明,GCC和clang之间存在明显的性能差距是偶然的。

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

从开发人员的角度来看,GCC 4.8+和clang 3.3之间的显着区别是GCC具有-Og命令行选项。此选项启用了不干扰调试的优化,因此例如始终可以获取准确的堆栈跟踪。在clang中缺少此选项使clang难以用作某些开发人员的优化编译器。


最近,(3.3和4.8)我认为编译时间之间没有太大的区别。(在“我的”程序中,其编译时间在10秒到30秒之间)。
alfC

9

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


8

我在gcc 5.2.1和clang 3.6.2上注意到的一个特殊区别是,如果您有一个关键循环,例如:

for (;;) {
    if (!visited) {
        ....
    }
    node++;
    if (!*node) break;
  }

然后gcc将在使用-O3或进行编译时-O2推测性地将循环展开八次。Clang根本不会展开它。通过反复试验,我发现在我的程序数据特定情况下,正确的展开量为5,因此gcc超出了上限,clang低于了上限。但是,过度射击对性能更有害,因此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|
+---------------------+-----+-----+

这全是纯C代码,在编译C ++代码时,我对任何一个编译器的性能都没有要求。

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


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.