SSE指令在哪些方面超越普通指令?

7

x86-64架构的SSE指令(向量指令)在哪些情况下优于普通指令。因为我所看到的是,执行SSE指令所需的频繁加载和存储正在抵消由于向量计算而获得的任何收益。那么,有人能给我一个SSE代码示例,展示它比普通代码更好吗?

也许是因为我按照此方式单独传递每个参数...

__m128i a = _mm_set_epi32(pa[0], pa[1], pa[2], pa[3]);
__m128i b = _mm_set_epi32(pb[0], pb[1], pb[2], pb[3]);
__m128i res = _mm_add_epi32(a, b);

for( i = 0; i < 4; i++ )
 po[i] = res.m128i_i32[i];

有没有一种方式可以一次性传递所有4个整数,我的意思是一次性传递整个128字节的pa?并且一次性将res.m128i_i32赋值给po


1
基本上,每当您具有极高的计算/加载存储比率时。 - Mysticial
2
是的,你肯定不想那样使用 _mm_set_epi32()。使用 _mm_load_si128()。如果无法对齐数据,则可以使用 _mm_loadu_si128(),但会影响性能。 - Mysticial
1
对齐数据?你指的是什么? - pythonic
2
我有许多SSE和AVX的示例可以显示出比普通代码更快的速度,但它们都太大了无法在这里发布。一个好的经验法则是每个内存访问至少有3-4个操作。在您的示例中,即使您正确使用_mm_load_si128()_mm_store_si128(),对于3个内存访问只有1个操作。这就是为什么您没有得到任何加速的原因。 - Mysticial
是的,现在它可以工作了,但仍然比原来慢,虽然现在接近了,之前它要慢得多。但既然你说需要至少3-4个操作才能使它更快,你能给出一些例子吗?不需要代码,只需要操作的示例即可。 - pythonic
显示剩余4条评论
1个回答

10

将评论总结成答案:

你基本上陷入了大多数新手都会遇到的陷阱。 在你的示例中有两个问题:

  1. 你误用了_mm_set_epi32()
  2. 你的计算负载比非常低。(在你的示例中是1到3)

_mm_set_epi32() 是一个非常昂贵的内置函数。虽然它很方便使用,但它不会编译为单个指令。一些编译器(例如VS2010)在使用_mm_set_epi32()时可能生成性能非常差的代码。

相反,由于你正在加载连续的内存块,你应该使用_mm_load_si128()。 这要求指针对齐到16字节。如果无法保证此对齐,则可以使用 _mm_loadu_si128() - 但会有性能损失。理想情况下,你应该正确对齐你的数据,以便不需要使用_mm_loadu_si128()


为了真正高效地使用SSE,你还需要最大化计算/负载存储比率。我追求的目标是每个内存访问3-4个算术指令。这是一个相当高的比率。通常你需要重构代码或重新设计算法来增加它。结合对数据的多次遍历是一种常用方法。

当你有具有长依赖链的大型循环体时,展开循环通常是最大化性能所必需的。


一些成功使用SSE以实现加速的SO问题示例。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接