我正在使用AVX内在函数在VC ++中编写一个前馈网络。我在C#中通过PInvoke调用此代码。调用计算包含函数exp()的大循环的函数时,我的性能对于160M的循环大小是~1000ms。一旦我调用使用AVX内在函数的任何函数,然后使用exp(),我的性能就会下降到大约8000ms的相同操作。请注意,计算exp()的函数是标准C,并且使用AVX内在函数的调用在处理的数据方面可能完全不相关。某种旗帜在运行时会在某处绊倒。
换句话说,
A(); // 1000ms calculates 160M exp()
B(); // completely unrelated but contains AVX
A(); // 8000ms
或者,奇怪的是,
C(); // contains 128 bit SSE SIMD expressions
A(); // 1000ms
我很遗憾这里有什么可能的机制,或者如何追求一个解决方案。我在英特尔2500K cpu \ Win 7. Express版本的VS.
感谢。
答案 0 :(得分:10)
如果使用任何AVX256指令,则“AVX上部状态”变为“脏”,如果随后使用SSE指令(包括在xmm寄存器中执行的标量浮点),则会导致大的停顿。这在英特尔优化手册中有记录,您可以download for free(如果您正在进行此类工作,则必须阅读):
AVX指令总是修改YMM寄存器的高位,而SSE指令不修改高位。从硬件角度来看,YMM寄存器集合的高位可以被认为是三种状态之一:
•清洁:YMM的所有高位都为零。这是处理器从RESET启动时的状态。
•已修改并保存到XSAVE区域YMM寄存器的高位内容与XSAVE区域中的已保存数据匹配。这在XSAVE / XRSTOR执行后发生。
•已修改和未保存:执行一条AVX指令(256位或128位)会修改目标YMM的高位。
只要处理器状态为“已修改且未保存”,AVX / SSE转换惩罚就适用。使用VZEROUPPER将处理器状态移至“清理”并避免转换惩罚。
您的例程B( )
会弄脏YMM状态,因此A( )
中的SSE代码会停止。在VZEROUPPER
和B
之间插入A
指令以避免此问题。