手动SIMD代码可负担性

Manual SIMD code affordability

本文关键字:负担 代码 SIMD 手动      更新时间:2023-10-16

我们正在运行一个高度计算密集型的项目,现在我们让编译器进行SSE优化。但是,我们不确定我们是否获得了代码的最佳性能。

我的问题是,我明白,但是我没有发现很多建议:编写手册Simd代码负担得起的,还是其他术语值得付出的努力?

可负担性在这里意味着对成本收益的粗略估计,例如speedup / development_time或在项目开发中合理的任何其他措施。

减少范围:

  • 我们介绍了代码,我们知道计算是最繁重的部分
  • 我们有一个C 代码,可以轻松地使用Boost.SIMD和类似的库
  • 可负担性不应照顾代码可读性,我们假设我们对SSE/AVX
  • 当前代码是多线程(OpenMP(
  • 我们的编译器是英特尔的icc

完全同意保罗·R(Paul R(,并且只是想补充说,在大多数情况下,IMO Intinsics/ASM优化不值得。在大多数情况下,这些优化是由营销驱动的,即,我们在特定平台上的性能是为了获得(在大多数情况下(更好的数字。

如今,只要在ASM中重写您的C/C 代码,就几乎不可能获得绩效的数量级。在大多数情况下,这是记忆/缓存访问和方法/算法(即并行化(的问题。

您应该尝试的第一件事是用硬件性能计数器(使用免费的" Perf"工具或Intel VTune(分析代码,并了解真正的瓶颈。例如,计算过程中的内存访问实际上是最常见的瓶颈,而不是计算本身。因此,此类代码的手动矢量化无济于事,因为无论如何CPU摊位在内存上。

这样的分析总是值得付出的,因为您更好地了解代码和CPU架构。

您应该尝试的下一件事是优化代码。有多种方法:优化数据结构,缓存友好的内存访问模式,更好的算法等。例如,在某些情况下,您在结构中声明字段的顺序可能会产生重大的性能影响,因为您的结构可能会有孔,并且占据两行缓存而不是一行。另一个示例是错误共享,当您在CPU和简单的缓存对齐之间订阅相同的高速缓存线时,可能会给您提供更好的数量级性能。

这些优化总是值得付出的,因为它们也会影响您的低级代码。

然后,您应该尝试帮助您的编译器。例如,默认情况下,编译器向量化/展开内部循环,但最好是向量化/展开外循环。您可以用#pragma提示来做到这一点,有时值得付出努力。

您应该尝试的最后一件事是使用内在/ASM重写已经高度优化的C/C 代码。可能有一些原因,例如更好的说明交织(因此您的CPU管道总是很忙(或使用特殊的CPU指令(即加密(。合理内在/ASM的实际数量可忽略不计,它们始终依赖于平台。

因此,如果没有有关您的代码/算法的更多详细信息,那么很难猜测这是否有意义,但我敢打赌。更好地将精力用于分析和独立于平台的优化。如果您确实需要该计算能力,最好查看OpenCL或类似框架。最后,投资更好的CPU:这种投资的效果是可以预见的,即时的。

您需要进行成本效益分析,例如如果您可以投资说X个月的努力,费用为$ Y,使您的代码更快地运行n次,这转化为硬件成本的降低(例如,在HPC上下文中的CPU较少(,或者减少运行时的运行时间从某种意义上说,在某种程度上等同于成本收益,然后这是一个简单的算术练习。(但是,请注意,有一些无形的长期成本,例如,SIMD优化的代码往往更复杂,更容易出错,便携式且难以维护。(

如果代码的关键性能部分(HOT 10%(是可矢量化的,那么您也许可以获得数量级的速度(更少用于双精度浮点,更多的是较窄的数据类型,例如16位。固定点(。

请注意,这种优化并不总是将标量代码转换为SIMD代码的简单问题 - 您可能必须考虑数据结构和缓存/内存访问模式。