c++ - SSE FP 单元是否检测到 0.0 个操作数?

标签 c++ performance sse computer-architecture

根据我之前的question我的想法是通过删除系数 m_a、m_b 为 1.0 或 0.0 时的计算来优化算法。现在我尝试优化算法并得到了一些我无法解释的奇怪结果。

第一个分析器运行 100k 个样本。从文件中读取参数值(!):

b0=1.0 b1=-1.480838022915731 b2=1.0

a0=1.0 a1=-1.784147570544337 a2=0.854309980957510

Slow

第二个分析器运行相同的 100k 个样本。从文件中读取参数值(!):

b0=1.0 b1=-1.480838022915731 b2=1.0

a0=1.0 a1=-1.784147570544337 a2=0.0 <--- 只有 a2 不同!

Fast

图中左侧的数字(灰色背景)代表所需的 CPU 周期。清晰可见,参数 a2=0.0 的第二次运行要快得多。

我检查了调试和发布代码之间的区别。发布代码更快(如预期)。当修改参数 a2 时,调试和发布代码具有相同的奇怪行为。

然后我检查了ASM代码。我注意到使用了 SSE 指令。这是有效的,因为我使用/arch:SSE2 编译。因此我禁用了 SSE。生成的代码不再使用 SSE,并且性能不再依赖于参数值 a2(正如预期的那样)

因此我得出结论,当使用 SSE 并且 SSE 引擎检测到 a2 为 0.0 时,它们是某种性能优势,因此省略了过时的乘法和减法。我从来没有听说过这个,并试图找到信息但没有成功。

那么有人可以解释我的表现结果吗?

为了完整起见,这是发布版本的相关 ASM 代码:

00F43EC0  mov         edx,dword ptr [ebx]  
00F43EC2  movss       xmm0,dword ptr [eax+edi*4]  
00F43EC7  cmp         edx,dword ptr [ebx+4]  
00F43ECA  je          $LN419+193h (0F43F9Dh)  
00F43ED0  mov         esi,dword ptr [ebx+4]  
00F43ED3  lea         eax,[edx+68h]  
00F43ED6  lea         ecx,[eax-68h]  
00F43ED9  cvtps2pd    xmm0,xmm0  
00F43EDC  cmp         ecx,esi  
00F43EDE  je          $LN419+180h (0F43F8Ah)  
00F43EE4  movss       xmm1,dword ptr [eax+4]  
00F43EE9  mov         ecx,dword ptr [eax]  
00F43EEB  mov         edx,dword ptr [eax-24h]  
00F43EEE  movss       xmm3,dword ptr [edx+4]  
00F43EF3  cvtps2pd    xmm1,xmm1  
00F43EF6  mulsd       xmm1,xmm0  
00F43EFA  movss       xmm0,dword ptr [ecx]  
00F43EFE  cvtps2pd    xmm4,xmm0  
00F43F01  cvtps2pd    xmm3,xmm3  
00F43F04  mulsd       xmm3,xmm4  
00F43F08  xorps       xmm2,xmm2  
00F43F0B  cvtpd2ps    xmm2,xmm1  
00F43F0F  movss       xmm1,dword ptr [ecx+4]  
00F43F14  cvtps2pd    xmm4,xmm1  
00F43F17  cvtps2pd    xmm2,xmm2  
00F43F1A  subsd       xmm2,xmm3  
00F43F1E  movss       xmm3,dword ptr [edx+8]  
00F43F23  mov         edx,dword ptr [eax-48h]  
00F43F26  cvtps2pd    xmm3,xmm3  
00F43F29  mulsd       xmm3,xmm4  
00F43F2D  subsd       xmm2,xmm3  
00F43F31  movss       xmm3,dword ptr [edx+4]  
00F43F36  cvtps2pd    xmm4,xmm0  
00F43F39  cvtps2pd    xmm3,xmm3  
00F43F3C  mulsd       xmm3,xmm4  
00F43F40  movss       xmm4,dword ptr [edx]  
00F43F44  cvtps2pd    xmm4,xmm4  
00F43F47  cvtpd2ps    xmm2,xmm2  
00F43F4B  xorps       xmm5,xmm5  
00F43F4E  cvtss2sd    xmm5,xmm2  
00F43F52  mulsd       xmm4,xmm5  
00F43F56  addsd       xmm3,xmm4  
00F43F5A  movss       xmm4,dword ptr [edx+8]  
00F43F5F  cvtps2pd    xmm1,xmm1  
00F43F62  movss       dword ptr [ecx+4],xmm0  
00F43F67  mov         edx,dword ptr [eax]  
00F43F69  cvtps2pd    xmm4,xmm4  
00F43F6C  mulsd       xmm4,xmm1  
00F43F70  addsd       xmm3,xmm4  
00F43F74  xorps       xmm1,xmm1  
00F43F77  cvtpd2ps    xmm1,xmm3  
00F43F7B  movss       dword ptr [edx],xmm2  
00F43F7F  movaps      xmm0,xmm1  
00F43F82  add         eax,70h  
00F43F85  jmp         $LN419+0CCh (0F43ED6h)  
00F43F8A  movss       xmm1,dword ptr [ebx+10h]  
00F43F8F  cvtps2pd    xmm1,xmm1  
00F43F92  mulsd       xmm1,xmm0  
00F43F96  xorps       xmm0,xmm0  
00F43F99  cvtpd2ps    xmm0,xmm1  
00F43F9D  mov         eax,dword ptr [ebp-4Ch]  
00F43FA0  movss       dword ptr [eax+edi*4],xmm0  
00F43FA5  mov         ecx,dword ptr [ebp-38h]  
00F43FA8  mov         eax,dword ptr [ebp-3Ch]  
00F43FAB  sub         ecx,eax  
00F43FAD  inc         edi  
00F43FAE  sar         ecx,2  
00F43FB1  cmp         edi,ecx  
00F43FB3  jb          $LN419+0B6h (0F43EC0h)  

编辑:用发布代码替换调试 ASM 代码。

最佳答案

SSE 上的 FP 乘法没有早期出局。这是一个具有短延迟的完全流水线操作,因此添加早期输出会使指令退出复杂化,同时提供零性能优势。在现代处理器上通常具有数据相关执行特征的唯一指令是除法和平方根(忽略次正规,它会影响更广泛的指令)。英特尔和 AMD 以及 Agner Fog 都对此进行了广泛记录。

那么为什么您会看到性能发生变化?最可能的解释是,由于输入或结果不正常,您遇到了停顿;这在 DSP 滤波器和延迟中很常见,就像您拥有的那样。在没有看到您的代码和输入数据的情况下,无法确定这就是正在发生的事情,但这是迄今为止最有可能的解释。如果是这样,您可以通过在 MXCSR 中设置 DAZ 和 FTZ 位来解决问题。

英特尔文档: http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-optimization-manual.pdf (请参阅附录中的延迟表,注意 mulssmulsd 有一个固定值。)

AMD 16 小时指令延迟(excel 电子表格): http://amd-dev.wpengine.netdna-cdn.com/wordpress/media/2012/10/AMD64_16h_InstrLatency_1.1.xlsx

Agner Fog 的英特尔和 AMD 指令延迟表: http://www.agner.org/optimize/instruction_tables.pdf

关于c++ - SSE FP 单元是否检测到 0.0 个操作数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26816523/

相关文章:

c++ - 如何组织或排序 std::vector <cv::Point2f>

c - 使用多线程时低于预期的加速

c - x86-64 整数向量化优化

c - SSE operator+= 用于 vector

c++ - 无法更改光标(从 OnSetCursor 内部)

c++ - 将 LARGE_INTEGER.QuadPart 作为 size_t 的输出参数传递是否安全?

c++ - _beginthreadx 和套接字

performance - Nim 检查 :off vs -d:release

php - 使用 OOP 在 PHP 中组合大量函数(某种 namespace )?

c++ - 性能与 SSE 相同