首页> 后端开发> C++> 正文

追求性能第三部分:C Force

王林
发布: 2024-08-06 01:10:02
原创
894 人浏览过

The Quest for Performance Part III : C Force

在本系列的前两期中,我们考虑了 Perl 中浮动操作的性能,
Python 和 R 在一个玩具示例中计算函数cos(sin(sqrt(x))),其中 x 是一个非常大50M 双精度浮点数数组。
将算术密集型部分委托给 C 的混合实现是性能最高的实现之一。在本期中,我们将稍微偏离主题,看看玩具示例的纯 C 代码实现的性能。
C 代码将提供有关内存局部性对于性能重要性的进一步见解(默认情况下,C 数组中的元素存储在内存中的顺序地址中,以及数字 API,例如 PDL 或 numpy 与此类容器的接口)相对于容器,
例如Perl 数组不将其值存储在内存中的连续地址中。最后但同样重要的是,C 代码实现将允许我们评估与低级编译器(在本例中为 gcc)的浮点运算相关的标志是否会影响性能。
这一点值得强调:普通人在“管道”安装或构建内联文件时完全依赖于编译器标志的选择。如果一个人不触及这些标志,那么人们就会幸福地不知道他们可能会错过什么,或者他们可能会避免的陷阱。
简陋的 C 文件 makefile 允许人们明确地进行此类性能评估。

下面完整列出了我们玩具示例的 C 代码。该代码相当不言自明,因此除了指出它包含四个函数之外,不会花时间解释

  • 昂贵函数的非顺序计算:所有三个浮点操作都使用一个线程在单个循环内进行
  • 昂贵函数的顺序计算:3 个浮点函数计算中的每一个都使用一个线程在一个单独的循环中进行
  • 非顺序 OpenMP 代码:非顺序代码的线程版本
  • 顺序 OpenMP 代码:顺序代码的线程化

在这种情况下,人们可能希望编译器足够聪明,能够识别平方根映射到汇编中的打包(向量化)浮点操作,以便可以使用适当的 SIMD 指令对一个函数进行向量化(请注意,我们没有使用OpenMP 代码的 simd 程序)。
也许矢量化的加速可以抵消重复访问相同内存位置(或不访问)所造成的性能损失。

雷雷

一个关键问题是,使用快速浮动编译器标志(一种以速度换取代码准确性的技巧)是否会影响性能。
这是没有这个编译器标志的 makefile

雷雷

这是带有此标志的:

雷雷

这是运行这两个程序的结果

  • 没有-ffast-math
雷雷
  • 与-ffast-math
雷雷

请注意,可以在 Numba 代码中使用 fastmath,如下所示(默认为 fastmath=False):

雷雷

值得注意的几点:

  • -ffast-math 显着提高了性能(单线程和多线程代码大约提高了 300%),但它可能会生成错误的结果
  • Fastmath 也适用于 Numba,但应避免使用,其原因与在任何追求准确性的应用程序中应避免的原因相同
  • 顺序 C 单线程代码提供类似于单线程 PDL 和 Numpy 的性能
  • 令人惊讶的是,当使用正确(非快速)数学时,顺序代码比非顺序代码快约 20%。
  • 毫不奇怪,多线程代码比单线程代码更快:)
  • 我仍然无法解释 numbas 如何为这个相当简单的函数提供比 C 代码高 50% 的性能。

标题:“性能追求第三部分:C Force”

日期:2024-07-07

在本系列的前两期中,我们考虑了 Perl 中浮动操作的性能,
Python 和 R 在一个玩具示例中计算函数cos(sin(sqrt(x))),其中 x 是一个非常大50M 双精度浮点数数组。
将算术密集型部分委托给 C 的混合实现是性能最高的实现之一。在本期中,我们将稍微偏离主题,看看玩具示例的纯 C 代码实现的性能。
C 代码将提供有关内存局部性对于性能重要性的进一步见解(默认情况下,C 数组中的元素存储在内存中的顺序地址中,以及数字 API,例如 PDL 或 numpy 与此类容器的接口)相对于容器,
例如Perl 数组不将其值存储在内存中的连续地址中。最后但同样重要的是,C 代码实现将允许我们评估与低级编译器(在本例中为 gcc)的浮点运算相关的标志是否会影响性能。
这一点值得强调:普通人在“管道”“安装”或构建内联文件时完全依赖于编译器标志的选择。如果一个人不触及这些标志,那么人们就会幸福地不知道他们可能会错过什么,或者他们可能会避免的陷阱。
简陋的 C 文件 makefile 允许人们明确地进行此类性能评估。

下面完整列出了我们玩具示例的 C 代码。该代码相当不言自明,因此除了指出它包含四个函数之外,不会花时间解释

  • 昂贵函数的非顺序计算:所有三个浮点操作都使用一个线程在单个循环内进行
  • 昂贵函数的顺序计算:3 个浮点函数计算中的每一个都使用一个线程在一个单独的循环中进行
  • 非顺序 OpenMP 代码:非顺序代码的线程版本
  • 顺序 OpenMP 代码:顺序代码的线程化

在这种情况下,人们可能希望编译器足够聪明,能够识别平方根映射到汇编中的打包(向量化)浮点操作,以便可以使用适当的 SIMD 指令对一个函数进行向量化(请注意,我们没有使用OpenMP 代码的 simd 程序)。
也许矢量化的加速可以抵消重复访问相同内存位置(或不访问)所造成的性能损失。

雷雷

一个关键问题是使用快速浮动编译器标志(一种以速度换取代码准确性的技巧)是否会影响性能。
这是没有这个编译器标志的 makefile

雷雷

这是带有此标志的:

雷雷

这是运行这两个程序的结果

  • 没有-ffast-math
雷雷
  • 与-ffast-math
雷雷

请注意,可以在 Numba 代码中使用 fastmath,如下所示(默认为 fastmath=False):

雷雷

值得注意的几点:

  • -ffast-math 显着提高了性能(单线程和多线程代码大约提高了 300%),但它可能会生成错误的结果
  • Fastmath 也适用于 Numba,但应避免使用,其原因与在任何追求准确性的应用程序中应避免的原因相同
  • 顺序 C 单线程代码提供类似于单线程 PDL 和 Numpy 的性能
  • 令人惊讶的是,当使用正确(非快速)数学时,顺序代码比非顺序代码快约 20%。
  • 毫不奇怪,多线程代码比单线程代码更快:)
  • 我仍然无法解释 numbas 如何为这个相当简单的函数提供比 C 代码高 50% 的性能。

以上是追求性能第三部分:C Force的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责声明 Sitemap
PHP中文网:公益在线PHP培训,帮助PHP学习者快速成长!