You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何x86平台MS C编译器下AVX2+FMA代码性能下降?

开普勒方程初始值计算函数的AVX2性能异常问题

以下是求解开普勒方程的三种经典初始值计算函数,其中S3是代码简洁但时序表现异常的典型案例。问题出现在Microsoft C编译器的x86编译模式下:理论上更简单的S3函数在AVX2最高优化下的执行时间远长于S9函数,而Intel编译器无此问题(因Mingw的x87正弦函数问题无法测试GCC)。所有初始值函数的输入范围为:偏心率0 ≤ e ≤ 1,平近点角-π ≤ M ≤ π,这些经典函数由Gooding & Odel(1986)提出:

double S1(double e, double M)
{ 
  if(M>0) return M + e; else return M - e;
  // 最简单的初始值,最终保证收敛
}
// 当e趋近于1时,S3和S9都无法保证收敛

double Gooding_S3(double e, double M)
{
  return M + e*sin(M)*(1+e*cos(M));  
// 速度慢且实用性低,S9的精度高得多!
}

double Gooding_S9(double e, double M)
{
 // 原论文中的写法为 sin(M)/sqrt(1-2*e*cos(M)+e*e)
 // 这是Halley方法的一种形式,由E-M的简单二次近似求根推导而来,在e<0.7时表现优秀且速度快!
  double y;
  y = 1-e;
  if (M == 0.0) return M; // 防止除零
  double s = sin(M/2);
  return M+e*sin(M)/sqrt(y*y+4*e*s*s);  // 更精确的形式(当e趋近于1时误差极大)
}

快速统计操作数及类型后,理论执行时间应依次递增,但实际并非如此!S9有时反而更快(操作数统计可能存在误差):

  1. S1:仅加法操作
  2. S3:两次加法、三次乘法,调用sincos
  3. S9:一次减法、两次加法、五次乘法、一次除法,两次调用sin、一次调用sqrt

使用标准_cdecl调用约定的x86代码生成及MSC 2022编译器,得到S3与S9的时序如下(S1因函数调用开销约为8周期,AVX2下的74并非笔误,切换为x64代码则无此问题):

Starterx87SSE2AVXAVX2*_64
S319923247423
S920650484730

已分离出x86代码生成中S3的AVX与AVX2差异片段,但无法理解为何AVX2性能更差,同时惊讶于S9的快速且稳定的时序表现,x64代码则性能稳定且更快,对此深感困惑。

以下是S3的快速AVX代码(无FMA):

call        ___libm_sse2_sincos_ (0BF7D50h)    
vshufpd     xmm1,xmm0,xmm0,1  
vmulsd      xmm1,xmm1,mmword ptr [e]  
vmulsd      xmm0,xmm0,mmword ptr [e]  
vaddsd      xmm1,xmm1,mmword ptr [__real@3ff0000000000000 (0BFBFB8h)]  
vmulsd      xmm0,xmm1,xmm0  
vaddsd      xmm0,xmm0,mmword ptr [M]  
vmovsd      qword ptr [esp],xmm0  
fld         qword ptr [esp]  

以下是S3的慢速AVX2代码(使用FMA,优化效果不佳):

call        ___libm_sse2_sincos_ (0672600h)  
 vmovsd      xmm2,qword ptr [e]  
 vpermilpd   xmm1,xmm0,1  
 vfmadd213sd xmm2,xmm1,mmword ptr [__real@3ff0000000000000 (0676F50h)]  
 vmulsd      xmm0,xmm0,mmword ptr [e]  
 vfmadd213sd xmm0,xmm2,mmword ptr [M]  
 vmovsd      qword ptr [esp],xmm0  
 fld         qword ptr [esp] 

现提出疑问:为何AVX2代码性能远低于AVX/SSE2,且仅在x86代码中出现此问题?同时寻求此类优化指令集反而导致性能下降的规避建议。该问题似乎与x86通过ST(0)返回浮点结果的旧链接约定有关,且可能与超越库函数调用相关。

内容的提问来源于stack exchange,提问作者Martin Brown

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 14:57:35