我目前正在使用GCC,但我最近发现了Clang,我正在考虑切换。但是有一个决定因素——它生成的二进制文件的质量(速度、内存占用、可靠性)——如果gcc - o3可以生成运行速度快1%的二进制文件,或者Clang二进制文件占用更多内存,或者由于编译器错误而失败,这是一个交易破坏者。

Clang拥有比GCC更好的编译速度和更低的编译时内存占用,但我真正感兴趣的是最终编译软件的基准测试/比较——您能给我指出一些已有的资源或您自己的基准测试吗?


当前回答

基本上来说,答案是:视情况而定。 有很多针对不同类型应用程序的基准测试。

我的应用程序的基准是:GCC > ICC > Clang。

很少有I/O,但有很多CPU浮动和数据结构操作。

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

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

其他回答

Clang编译代码更快的事实可能没有生成二进制代码的速度重要。不过,这里有一系列基准测试。

我注意到GCC 5.2.1和Clang 3.6.2的一个特殊区别是 如果你有一个关键循环,比如:

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

当使用-O3或-O2编译时,GCC会推测 展开这个循环八次。叮当根本无法展开它。通过 我发现,在我的程序数据的特定情况下, 正确的展开量是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 (Wily Werewolf), x86.64, AMD Phenom II X6 1090T处理器。

基本上来说,答案是:视情况而定。 有很多针对不同类型应用程序的基准测试。

我的应用程序的基准是:GCC > ICC > Clang。

很少有I/O,但有很多CPU浮动和数据结构操作。

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

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

Phoronix对此做了一些基准测试,但它是关于几个月前Clang/LLVM的快照版本。结果是,事情或多或少是一种推动;GCC和Clang在所有情况下都不是更好的。

因为你使用的是最新的Clang,所以它可能不太相关。显然,GCC 4.6将对Core 2和Core i7进行一些重大优化。

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

以下是我对GCC 4.7.2的一些最新发现,尽管范围不大 Clang 3.2用于c++。

更新:GCC 4.8.1 v clang 3.3比较附加在下面。

更新:GCC 4.8.2 v clang 3.4比较附加到此。

I maintain an OSS tool that is built for Linux with both GCC and Clang, and with Microsoft's compiler for Windows. The tool, coan, is a preprocessor and analyser of C/C++ source files and codelines of such: its computational profile majors on recursive-descent parsing and file-handling. The development branch (to which these results pertain) comprises at present around 11K LOC in about 90 files. It is coded, now, in C++ that is rich in polymorphism and templates and but is still mired in many patches by its not-so-distant past in hacked-together C. Move semantics are not expressly exploited. It is single-threaded. I have devoted no serious effort to optimizing it, while the "architecture" remains so largely ToDo.

在3.2之前,我只使用Clang作为实验性编译器 因为,尽管它具有卓越的编译速度和诊断能力,但它 c++ 11标准的支持落后于当代GCC版本 尊重coan的行为。在3.2版本中,这一差距已经缩小。

我的Linux测试工具大致适用于当前coan开发过程 70K源文件混合在一个文件解析器测试用例中,强调 测试消耗1000个文件,场景测试消耗小于1K个文件。

在报告测试结果的同时,线束也会累积和 显示coan中消耗的文件总数和消耗的运行时间(它只是将每个coan命令行传递给Linux time命令,并捕获并相加报告的数字)。任何测试所花费的可测量时间为0的测试加起来都是0,这一事实美化了计时,但这样的测试的贡献可以忽略不计。定时统计数据在检查结束时显示如下:

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个结果的平均值,如下 结果。数据单元格中的数字是的平均值 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|

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

-O3优化对GCC不利 -O3优化对Clang有重要的帮助 在-O2优化时,GCC比Clang快一点点 在-O3优化时,Clang明显快于GCC。

A further interesting comparison of the two compilers emerged by accident shortly after those findings. Coan liberally employs smart pointers and one such is heavily exercised in the file handling. This particular smart-pointer type had been typedef'd in prior releases for the sake of compiler-differentiation, to be an std::unique_ptr<X> if the configured compiler had sufficiently mature support for its usage as that, and otherwise an std::shared_ptr<X>. The bias to std::unique_ptr was foolish, since these pointers were in fact transferred around, but std::unique_ptr looked like the fitter option for replacing std::auto_ptr at a point when the C++11 variants were novel to me.

在测试构建的过程中,以衡量Clang 3.2的持续需求 对于这种和类似的分化,我不经意间就建立起来了 当我打算构建std::unique_ptr<X>时,std::shared_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 |

这里需要注意的是:

这两个编译器现在都不能从-O3优化中获益。 Clang在每个优化级别上都击败了GCC。 GCC的性能只受到智能指针类型的轻微影响 改变。 Clang的-O2性能受到智能指针类型的重要影响 改变。

在智能指针类型更改前后,Clang能够构建一个 实质上更快的coan可执行在-O3优化,它可以 在-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 |

事实上,现在处理所有四个可执行文件的平均时间比以前要长得多 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的更新,说我愿意 继续使用相同的coan snaphot进行进一步更新。但我决定 而是在快照(版本301)和最新开发上进行测试 我拥有的快照通过了它的测试套件(rev. 619)。这给出了结果a 一点经度,我还有另一个动机:

我最初的帖子指出,我没有花任何精力优化coan for 速度。在第301章中仍然是这样。然而,在我建成之后 每次我运行测试套件时,都要把计时装置放进coan测试装置中 最新更改对性能的影响一目了然。我看到了 它往往惊人的大,而且趋势比 我觉得在功能上的进步是值得的。

By rev. 308 the average processing time per input file in the test suite had well more than doubled since the first posting here. At that point I made a U-turn on my 10 year policy of not bothering about performance. In the intensive spate of revisions up to 619 performance was always a consideration and a large number of them went purely to rewriting key load-bearers on fundamentally faster lines (though without using any non-standard compiler features to do so). It would be interesting to see each compiler's reaction to this U-turn,

下面是我们现在熟悉的最新两个编译器版本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|

这里的故事与GCC-4.8.1和Clang-3.3相比仅略有变化。GCC的显示 好一点。Clang的稍微差一点。噪音可以很好地解释这一点。 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|

把301数字和619数字放在一起比较,有几点是显而易见的。

I was aiming to write faster code, and both compilers emphatically vindicate my efforts. But: GCC repays those efforts far more generously than Clang. At -O2 optimization Clang's 619 build is 46% faster than its 301 build: at -O3 Clang's improvement is 31%. Good, but at each optimization level GCC's 619 build is more than twice as fast as its 301. GCC more than reverses Clang's former superiority. And at each optimization level GCC now beats Clang by 17%. Clang's ability in the 301 build to get more leverage than GCC from -O3 optimization is gone in the 619 build. Neither compiler gains meaningfully from -O3.

我对这种命运的逆转感到十分惊讶,我怀疑我 可能会意外地使clang 3.4本身的构建变得缓慢(因为我构建了 它来自源代码)。所以我用发行版的Clang 3.3重新运行了619测试。的 结果实际上与3.4相同。

至于对这种180度大转弯的反应:在数据方面,Clang已经做了很多 比GCC在压榨速度从我的c++代码,当我给它没有 的帮助。当我用心去帮助时,GCC做得比Clang好得多。

我并没有把这个观点提升为原则,但我认为 “哪个编译器生成的二进制文件更好?”是一个问题 那就是,即使你指定了与答案相关的测试套件, 对于双星的计时还不是一个明确的问题。

你更好的二进制是最快的二进制,还是最好的二进制 补偿廉价的代码?或者是最好的补偿 精心设计的代码优先考虑可维护性和重用而不是速度?这取决于 你产生二进制的动机的性质和相对权重,以及 你这样做的约束条件。

在任何情况下,如果您非常关心构建“最好的”二进制文件,那么您应该 最好继续检查编译器的连续迭代是如何交付您的 在代码的连续迭代中追求“最好”的理念。