基于C++ 语言库的GCC和Clang编译器基准测试报告(ETL)

简介:

从我使用 C++ 代码完成了不同编译器的基准测试到现在,已经有一段时间了。由于我最近发布了 ETL 项目的 1.1 版(一个具有表达式模板的优化矩阵/向量计算库),所以我决定使用它作为我的基准测试的基版本。它是一个带有大量模板的 C++ 14 库。我要编译完整的测试套件(124 个测试用例)。这是直接在最新版本(1.1)的代码上完成的。我将在调试模式下编译一次,并在 release_debug(release + debug 符号和断言)下进行一次编译,并记录每个编译器的执行时间。该测试将使用支持 ETL 中的每个选项的配置进行编译,以此计算最大的编译时间。每次编译都使用四个线程(make -j4)。 我还做了一些基准测试,以了解每个编译器生成的代码间的运行时的性能差异。基准测试将编译为发布模式,并记录其编译时间。

我将测试以下编译器:

  • GCC-4.9.4
  • GCC-5.4.0
  • GCC-6.3.0
  • GCC-7.1.0
  • clang-3.9.1
  • clang-4.0.1
  • zapcc-1.0 (商业版,基于 clang-5.0 主分支)

所有这些都是直接使用 Portage(Gentoo 软件包管理器)安装的,除了从源代码安装的 clang-4.0.1 以及没有 Gentoo 软件包的 zapcc。由于 Gentoo 上的 clang 包不支持多进程,所以我不得不从源代码中安装一个版本,从包管理器中安装另一个版本。这也是我测试较少版本的 clang 的原因,更实用点。

为了实现这些测试的目标,所有编译器都使用了完全相同的选项。通常,我在 clang 上使用比 GCC 更多不同的选项(主要是考虑到在 clang 上更严格的向量化选项)。这可能不会使得每个编译器达到最佳性能,但可以对使用默认优化级别的输出之间进行比较。以下是使用的主要选项:

  • 调试模式下: -g
  • 发布+调试模式下: -g -O2
  • 发布模式下: -g -O3 -DNDEBUG -fomit-frame-pointer

每种情况都启用了许多警告,ETL 选项也是一样的。

所有的测试结果都是运行在 Intel Core i7-2600(Sandy Bridge ...)@ 3.4GHz 上的 Gentoo 机器上收集的,该机器具有 4 核和 8 线程、12G 的 RAM 和一个 SSD。我尽可能地从干扰项中分离出基准数据,并且我的基准代码是相当健全的,但是有些结果可能并不完全准确。此外,一些基准测试是在使用多线程,这可能会增加一些干扰和不可预测性。当我对测试结果不太确定时,我会多次运行基准测试以对此确认,并且总体而言,我对结果很有信心。

编译时间

让我们从编译器自身的性能结果开始:

基于C++ 语言库的GCC和Clang编译器基准测试报告(ETL)

注: 在 Release_Debug 和 Benchmark,我对 zapcc 只使用了三个线程, 因为 12Go 的内存对于四个线程并不足够。

不同的编译器之间有一些非常重要的区别。总地来说,clang-4.0.1 是迄今为止调试模式下最快的免费编译器。然而,当测试代码被添加优化选项加以编译,clang 就落后了。在调试模式和发布模式下,clang-4.0.1 比 clang-3.9.1 快得多,这一点令人印象深刻。在这一点上 clang 团队干得不错!这些优化,使得 clang-4.0.1 在发布模式下几乎与 gcc-7.1 平分秋色。对于 GCC 来说,优化的成本似乎一直在显著地上升。然而, GCC 7.1 似乎使得优化加快,也使得标准编译快了许多。如果我们考虑 zapcc,这是调试模式下最快的编译器,但它的速度在发布模式下比几个 gcc 版本要慢。

总地来说,我对 clang-4.0.1 的性能印象深刻,它看起来真快!在不久的将来,我一定会用这个新版本做更多的测试。看到 g++-7.1 的编译速度确实快于 gcc-6.3,也同样令人欣慰。然而,对优化而言,最快的 gcc 版本仍然是 gcc-4.9.4 ,这已经是一个对 C++ 标准低支持的老版本。

运行时性能

现在来看看生成的代码的质量。对于一些基准测试,我已经包含了两个版本的算法。 std 是最简单的算法(原始版),vec 是手工向量化和优化的实现版本。所有的测试都是在单精度浮点上完成的。

点乘

运行的第一个基准是计算两个向量之间的点积。让我们先看看原始版的性能:

基于C++ 语言库的GCC和Clang编译器基准测试报告(ETL)

不同的编译器之间的差异不是很大。基于 clang 的编译器似乎是生成速度最快代码的编译器。有趣的是,gcc-6.3 似乎在大数据量的容器中有一个很大的性能衰减,但在 gcc-7.1 中已经解决了。

基于C++ 语言库的GCC和Clang编译器基准测试报告(ETL)

如果我们查看优化版本的结果,其中差异更小。同样,基于 clang 的编译器生成的可执行文件是最快的,但紧随其后的是 gcc,除了 gcc-6.3 之外,我们仍然可以看到与之前相同的性能衰退。

Logistic Sigmoid

下一个测试是检查 sigmoid 操作的性能。在这种情况下,库的评估者将尝试使用并行化和向量化来计算。让我们看看不同编译器的开销如何:

基于C++ 语言库的GCC和Clang编译器基准测试报告(ETL)

有趣的是,我们可以看到,gcc-7.1 在少量数据时是最快的,而 clang-4.0 最适合生成较大数据时的代码。然而,除了最大的向量大小,差异并不是很明显。显然,zapcc(或 clang-5.0)有一个回归,因为它比 clang-4.0 慢,并与 clang-3.9 相同速度。

Y = Alpha * X + Y (axpy)

第三个基准是著名的 axpy(y = alpha * x + y)。这是完全由库中的表达式模板决定的,没有使用特定的算法。我们来看看结果:

基于C++ 语言库的GCC和Clang编译器基准测试报告(ETL)

即使是最大的 vector,一旦向量化和并行化之后,这也是一个非常快速的操作。以这种速度,观察到的一些差异可能不是很重要。再次,基于 clang 的版本是这段代码中最快的版本,但差异还是很小。在 gcc-7.1 中似乎还有一点回归,但这也是相当小的。

矩阵间的乘法 (GEMM)

下一个基准测试是测试 Matrix-Matrix 乘法的性能,这是在 BLAS 命名中被称为 GEMM 的操作。在这种情况下,我们同时测试原始的和优化的向量化实现。为了节省一些横向空间,我把表分成两部分。

基于C++ 语言库的GCC和Clang编译器基准测试报告(ETL)

这一次,不同编译器之间的性能差异非常大。clang 编译器现在是大幅度领先,其中 clang-4.0 是他们中最快的(也有不错的提升幅度)。事实上,clang-4.0.1 生成代码,平均比最好的 GCC 编译器生成的代码速度快两倍。非常有趣的是,从 GCC-5.4 开始,我们可以看到一个巨大的性能衰退,而且这种衰退还在 GCC-7.1 中。事实上,测试版本中最好的 GCC 版本依然是 GCC-4.9.4。Clang 真的在编译 GEMM 代码方面做得很好。

基于C++ 语言库的GCC和Clang编译器基准测试报告(ETL)

至于优化的版本,这两大家族是相反的。的确,GCC 在这方面做的工作比 clang 要好,尽管差距没有以前那么大了,但还是值得注意。我们还是可以观察到 GCC 版本中的一个小回归,因为 4.9 版本依然是最快的。至于 clang 版本,似乎 clang-5.0 (在 zapcc 中使用)在这个例子中有了很多的性能改进。

在这个例子中矩阵相乘,它是非常令人印象深刻的,优化与非优化代码在性能上差异非常巨大。并且,令人印象深刻的是,每种类型的编译器都有它们的长处,clang 看起来更适合处理没优化过的代码,而 GCC 更适合处理向量化的代码。


作者:佚名

来源:51CTO

相关文章
|
3月前
|
C++
C++ 语言异常处理实战:在编程潮流中坚守稳定,开启代码可靠之旅
【8月更文挑战第22天】C++的异常处理机制是确保程序稳定的关键特性。它允许程序在遇到错误时优雅地响应而非直接崩溃。通过`throw`抛出异常,并用`catch`捕获处理,可使程序控制流跳转至错误处理代码。例如,在进行除法运算或文件读取时,若发生除数为零或文件无法打开等错误,则可通过抛出异常并在调用处捕获来妥善处理这些情况。恰当使用异常处理能显著提升程序的健壮性和维护性。
74 2
|
3月前
|
算法 C语言 C++
C++语言学习指南:从新手到高手,一文带你领略系统编程的巅峰技艺!
【8月更文挑战第22天】C++由Bjarne Stroustrup于1985年创立,凭借卓越性能与灵活性,在系统编程、游戏开发等领域占据重要地位。它继承了C语言的高效性,并引入面向对象编程,使代码更模块化易管理。C++支持基本语法如变量声明与控制结构;通过`iostream`库实现输入输出;利用类与对象实现面向对象编程;提供模板增强代码复用性;具备异常处理机制确保程序健壮性;C++11引入现代化特性简化编程;标准模板库(STL)支持高效编程;多线程支持利用多核优势。虽然学习曲线陡峭,但掌握后可开启高性能编程大门。随着新标准如C++20的发展,C++持续演进,提供更多开发可能性。
80 0
|
13天前
|
测试技术 Go
go语言中测试工具
【10月更文挑战第22天】
27 4
|
7天前
|
开发框架 安全 .NET
.NET使用Moq开源模拟库简化单元测试
.NET使用Moq开源模拟库简化单元测试~
|
1月前
|
算法 C++
2022年第十三届蓝桥杯大赛C/C++语言B组省赛题解
2022年第十三届蓝桥杯大赛C/C++语言B组省赛题解
35 5
|
20天前
|
资源调度 前端开发 JavaScript
React 测试库 React Testing Library
【10月更文挑战第22天】本文介绍了 React Testing Library 的基本概念和使用方法,包括安装、基本用法、常见问题及解决方法。通过代码案例详细解释了如何测试 React 组件,帮助开发者提高应用质量和稳定性。
32 0
|
1月前
|
存储 编译器 C语言
深入计算机语言之C++:类与对象(上)
深入计算机语言之C++:类与对象(上)
|
1月前
|
存储 分布式计算 编译器
深入计算机语言之C++:C到C++的过度-2
深入计算机语言之C++:C到C++的过度-2
|
1月前
|
编译器 Linux C语言
深入计算机语言之C++:C到C++的过度-1
深入计算机语言之C++:C到C++的过度-1
|
3月前
|
编解码 编译器 C++
VS Code C/C++ MSVC编译器
VS Code C/C++ MSVC编译器
70 2