我有一个用C++编写的循环,它是为一个大整数数组的每个元素执行的.在循环内部,我屏蔽了整数的一些位,然后找到最小值和最大值.我听说如果我使用SSE指令进行这些操作,它将比使用按位AND和if-else条件写入的普通循环运行得快得多.我的问题是我应该参加这些SSE指令吗?此外,如果我的代码在不同的处理器上运行会发生什么?它仍然可以工作或这些指令是特定于处理器的吗?
SSE指令是特定于处理器的.您可以在维基百科上查找哪个处理器支持哪个SSE版本.
如果SSE代码更快或更快取决于许多因素:第一个当然是问题是内存限制还是CPU限制.如果内存总线是瓶颈,SSE将无济于事.尝试简化整数计算,如果这使得代码更快,它可能受CPU限制,并且您很有可能加快它的速度.
请注意,编写SIMD代码比编写C++代码困难得多,并且生成的代码更难以更改.始终保持C++代码是最新的,您需要将其作为注释并检查汇编代码的正确性.
考虑使用像IPP这样的库,它实现了针对各种处理器优化的常见低级SIMD操作.
以SSE为例的SIMD允许您对多个数据块执行相同的操作.因此,使用SSE作为整数运算的直接替换将不会有任何好处,只有您可以同时对多个数据项执行操作时才会获得优势.这涉及加载一些在内存中连续的数据值,执行所需的处理,然后单步执行数组中的下一组值.
问题:
1如果代码路径依赖于正在处理的数据,则SIMD变得更难实现.例如:
a = array [index]; a &= mask; a >>= shift; if (a < somevalue) { a += 2; array [index] = a; } ++index;
像SIMD一样不容易做到:
a1 = array [index] a2 = array [index+1] a3 = array [index+2] a4 = array [index+3] a1 &= mask a2 &= mask a3 &= mask a4 &= mask a1 >>= shift a2 >>= shift a3 >>= shift a4 >>= shift if (a12如果数据不重要,则将数据加载到SIMD指令中是很麻烦的
3代码是特定于处理器的.SSE仅适用于IA32(Intel/AMD),并非所有IA32 cpus都支持SSE.
您需要分析算法和数据以查看它是否可以进行SSE并且需要了解SSE的工作原理.英特尔网站上有大量文档.
问题1通常使用SIMD掩码指令来解决.像__m128 mask = _mm_cmplt_ps(a,somevalue); a = _mm_add_ps(a,_mm_and_ps(mask,_ mm_set_ps1(2));对于if(a
3> 小智..:这种问题是良好的低级分析器必不可少的完美例子.(像VTune这样的东西)它可以让你更加了解你的热点所在的位置.
我的猜测,从你描述的是你的热点可能是使用if/else计算最小/最大值导致的分支预测失败.因此,使用SIMD内在函数应该允许您使用最小/最大指令,但是,尝试使用无分支最小/最大计算可能是值得的.这可以通过减少痛苦来实现大部分收益.
像这样的东西:
inline int minimum(int a, int b) { int mask = (a - b) >> 31; return ((a & mask) | (b & ~mask)); }
4> jalf..:如果您使用SSE指令,则显然仅限于支持这些指令的处理器.这意味着x86,可以追溯到Pentium 2左右(不记得确切的时候它们被引入,但是很久以前)
SSE2,据我所知,是提供整数运算的,有点近一些(Pentium 3?虽然第一款AMD Athlon处理器不支持它们)
在任何情况下,您都有两种使用这些说明的选项.要么在汇编中编写整个代码块(可能是一个坏主意.这使得编译器几乎不可能优化代码,并且人类很难编写高效的汇编程序).
或者,使用编译器可用的内在函数(如果内存服务,它们通常在xmmintrin.h中定义)
但同样,性能可能无法提高.SSE代码对其处理的数据提出了额外的要求.主要是要记住的是数据必须在128位边界上对齐.加载到同一寄存器中的值之间也应该存在很少或没有依赖关系(128位SSE寄存器可以容纳4个整数.将第一个和第二个加在一起并不是最佳的.但是将所有四个整数添加到相应的4个整数中另一个注册会很快)
使用包含所有低级SSE摆弄的库可能很诱人,但这也可能会破坏任何潜在的性能优势.
我不知道SSE的整数运算支持有多好,所以这也可能是一个可以限制性能的因素.SSE主要针对加速浮点运算.