7

我正在使用 AVX 内在函数在 VC++ 中编写前馈网络。我通过 C# 中的 PInvoke 调用此代码。我在调用计算包含函数 exp() 的大循环的函数时的性能约为 1000 毫秒,循环大小为 160M。一旦我调用任何使用 AVX 内在函数的函数,然后使用 exp(),对于相同的操作,我的性能下降到大约 8000 毫秒。请注意,计算 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

我不知道这里发生了什么可能的机制,或者如何寻求解决方案。我在 Intel 2500K cpu\Win 7. Express 版本的 VS 上。

谢谢。

4

1 回答 1

10

如果您使用任何 AVX256 指令,“AVX 上层状态”将变为“脏”,如果您随后使用 SSE 指令(包括在 xmm 寄存器中执行的标量浮点),则会导致大停顿。这在英特尔优化手册中有记录,您可以免费下载(如果您正在从事此类工作,则必须阅读):

AVX 指令总是修改 YMM 寄存器的高位,而 SSE 指令不修改高位。从硬件的角度来看,YMM 寄存器集合的高位可以被认为处于以下三种状态之一:

• Clean:YMM 的所有高位均为零。这是处理器从 RESET 启动时的状态。

• 修改并保存到XSAVE 区域 YMM 寄存器的高位内容与XSAVE 区域中保存的数据相匹配。这发生在 XSAVE/XRSTOR 执行之后。

• 已修改和未保存:执行一条 AVX 指令(256 位或 128 位)会修改目标 YMM 的高位。

每当处理器状态为“已修改且未保存”时,都会应用 AVX/SSE 转换惩罚。使用 VZEROUPPER 将处理器状态移动到“清洁”并避免转换损失。

您的例程B( )弄脏了 YMM 状态,因此 SSE 代码A( )停滞不前。在和之间插入一条VZEROUPPER指令以避免该问题。BA

于 2011-05-04T23:07:06.280 回答