optimization - SSE 是多余的还是不鼓励的?

标签 optimization sse simd auto-vectorization

环顾这里和互联网,我可以找到很多关于现代编译器在许多实际情况下击败 SSE 的帖子,我刚刚遇到了一些我继承的代码,当我禁用 2006 年编写的一些基于整数的图像处理的 SSE 代码时并强制代码进入标准 C 分支,它运行得更快。

在具有多核和高级流水线等的现代处理器上,较旧的 SSE 代码是否表现不佳 gcc -O2 ?

最佳答案

您必须小心使用微基准。衡量你认为的东西之外的东西真的很容易。就 L1 I-cache/uop-cache 和分支预测器条目的压力而言,微基准测试通常也根本不考虑代码大小。

在大多数情况下,微基准测试通常会尽可能好地预测所有分支,而经常调用但不在紧密循环中的例程在实践中可能效果不佳。

多年来,SSE 增加了许多内容。新代码的合理基准是 SSSE3(在 Intel Core2 及更高版本以及 AMD Bulldozer 及更高版本中找到),只要有标量回退。添加快速字节洗牌 (pshufb) 可以改变某些事情的游戏规则。 SSE4.1 也为整数代码添加了很多好东西。如果旧代码不使用它,编译器输出或新的手写代码可以做得更好。

目前我们达到了 AVX2,它在 256b 寄存器中一次处理两个 128b channel 。有一些 256b shuffle 指令。 AVX/AVX2 提供了所有先前 SSE 指令的 3 操作数(非破坏性 dest、src1、src2)版本,这有助于提高代码密度,即使在使用 256b 操作的双 channel 方面是不利的情况下(或者当针对 AVX1 没有AVX2 用于整数代码)。

在一两年内,第一款 AVX512 桌面硬件可能会问世。这增加了大量强大的功能(屏蔽寄存器,并在高度非正交的 SSE/AVX 指令集中填补更多空白),以及更宽的寄存器和执行单元。

如果旧的 SSE 代码在编写时仅比标量代码提供了边际加速,或者没有人对其进行基准测试,那可能就是问题所在。编译器的进步可能会导致生成的标量 C 代码击败需要大量改组的旧 SSE。有时,将数据洗牌到向量寄存器的成本会耗尽所有的加速速度。

或者根据您的编译器选项,编译器甚至可能是自动矢量化的。 IIRC,gcc -O2不启用 -ftree-vectorize , 所以你需要 -O3用于自动 vec。

可能阻碍旧 SSE 代码的另一件事是它可能假设未对齐的加载/存储很慢,并且使用了 palignr或类似的技术在寄存器中未对齐的数据和对齐的加载/存储之间进行。因此,旧代码可能会针对旧微架构进行调整,而这种方式实际上在最近的微架构上更慢。

因此,即使不使用以前不可用的任何指令,调整不同的微架构也很重要。

编译器输出很少是最佳的,尤其是。如果你还没有告诉它指针不是别名( restrict ),或者是对齐的。但它通常设法运行得非常快。您通常可以对其进行一些改进(尤其是通过减少 uops/insns 来完成相同的工作,从而对超线程更加友好),但您必须 know the microarchitecture you're targeting .例如。英特尔 Sandybridge 及更高版本只能使用单寄存器寻址模式对内存操作数进行微熔丝。 上的其他链接维基。

因此,回答标题,SSE 指令集绝不是多余或不鼓励的。不鼓励随意使用它直接与 asm 一起使用(改用内部函数)。不鼓励使用内在函数,除非您实际上可以加速编译器输出。如果它们现在绑定(bind)在一起,那么 future 的编译器使用标量代码做得比使用向量内在函数做得更好会更容易。

关于optimization - SSE 是多余的还是不鼓励的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33948751/

相关文章:

c - 如何使用 Neon SIMD 将无符号字符转换为有符号整数

performance - 在 C# 中进行模拟退火时,OOP 比结构化编程慢得多。为什么以及如何修复它?

assembly - 如何使用 SSE 计算模数/余数?

c++ - SSE/AVX 寄存器的非零字节索引

自动矢量化最小 float 的 C 代码

c - openmp simd 失败

algorithm - SIMD 利用两个元素在场上实现 Peterson 和 Monico 的 Lanczos 算法

mysql - Sql 查询优化以获取更快的结果

iphone - 测量 iPhone 应用程序加载时间

mysql - 如何在派生表的 where 条件中使用先前联接中的字段?