有没有人利用 gcc 可以做的自动矢量化?在现实世界中(与示例代码相反)?是否需要重组现有代码才能利用?在任何生产代码中是否有大量可以通过这种方式矢量化的案例?
5 回答
我还没有看到 GCC 或 Intel C++ 自动矢量化除了非常简单的循环之外的任何东西,即使给定可以(并且在我使用 SSE 内在函数手动重写它们之后)可以矢量化的算法代码。
这部分是保守的——尤其是在面对可能的指针别名时,C/C++ 编译器很难向自己“证明”向量化是安全的,即使作为程序员的你知道它是安全的。大多数编译器(明智地)宁愿不优化代码,也不愿冒错误编译的风险。至少在理论上,这是高级语言比 C 具有真正优势的一个领域(我说理论上是因为我实际上并不知道任何自动矢量化 ML 或 Haskell 编译器)。
另一部分只是分析限制——据我所知,向量化的大多数研究都与优化经典数值问题(比如流体动力学)有关,这是几年前大多数向量机的基础(当时,在 CUDA /OpenCL、Altivec/SSE 和 STI Cell,各种形式的矢量编程在商业系统中变得广泛可用)。
考虑到为标量处理器编写的代码对于编译器来说很容易向量化是不太可能的。令人高兴的是,您可以做很多事情来使编译器更容易理解如何对其进行矢量化,例如循环平铺和部分循环展开,即使编译器不知道如何处理,也(倾向于)提高现代处理器的性能向量化它。
它很难在任何业务逻辑中使用,但是当您以相同的方式处理大量数据时会加快速度。
很好的例子是声音/视频处理,您对每个样本/像素应用相同的操作。我为此使用了 VisualDSP,您必须在编译后检查结果——如果它真的用在了它应该使用的地方。
矢量化将主要用于数值程序。矢量化程序可以在矢量处理器上运行得更快,例如 PS3 游戏机中使用的 STI 单元处理器。在那里,用于渲染游戏图形的数值计算可以通过矢量化大大加快。这种处理器称为 SIMD(单指令多数据)处理器。
在其他处理器上不会使用矢量化。矢量化程序在不适用于非 SIMD 处理器的矢量化指令集上运行。
英特尔的 Nehalem 系列处理器(2008 年底发布)实现 SSE 4.2 指令,即 SIMD 指令。来源:维基百科。
矢量化指令不仅限于 Cell 处理器——大多数现代工作站之类的 CPU 都有它们(PPC、x86 自 pentium 3、Sparc 等)。当用于浮点运算时,它可以为计算密集型任务(过滤器等)提供很大帮助。根据我的经验,自动矢量化效果并不好。
您可能已经注意到,实际上几乎没有人知道如何充分利用 GCC 的自动矢量化。如果你在网上搜索人们的评论,总是会想到 GCC 允许你启用自动矢量化,但它很少实际使用它,所以如果你想使用 SIMD 加速(例如:MMX, SSE、AVX、NEON、AltiVec),那么您基本上必须弄清楚如何使用编译器内在函数或汇编语言代码来编写它。
但是内在函数的问题在于,您实际上需要了解它的汇编语言方面,然后还要学习描述您想要的内容的内在方法,这可能会导致代码效率低于您使用汇编代码编写的代码(例如 10 倍),因为编译器仍然难以充分利用您的内在指令!
例如,您可能正在使用 SIMD Intrinsics,以便可以同时并行执行许多操作,但是您的编译器可能会生成汇编代码,在 SIMD 寄存器和普通 CPU 寄存器之间来回传输数据,从而有效地使您的SIMD 代码的运行速度与普通代码相似(甚至更慢)!
所以基本上:
- 如果您想要高达 100% 的加速(2 倍速度),那么要么购买官方的 Intel/ARM 编译器,要么将您的一些代码转换为使用 SIMD C/C++ Intrinsics。
- 如果您想要 1000% 的加速(10 倍速度),请使用 SIMD 指令手动将其编写为汇编代码。或者,如果在您的硬件上可用,请改用 GPU 加速,例如 OpenCL 或 Nvidia 的 CUDA SDK,因为它们可以在 GPU 中提供与 SIMD 在 CPU 中类似的加速。