首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用混合(浮点,双)输入向量执行AVX内部产品操作的最快方法

使用混合(浮点,双)输入向量执行AVX内部产品操作的最快方法
EN

Stack Overflow用户
提问于 2018-03-21 18:40:31
回答 1查看 612关注 0票数 8

我需要为混合的单/双精度浮点矢量建立一个单精度浮点内积例程,利用AVX指令集实现256位的SIMD寄存器。

问题:一个输入向量是float (x),另一个是double (yD)。

因此,在计算真正的内部积操作之前,我需要将输入的yD向量数据从double转换为float。

使用SSE2指令集,我能够实现一个非常快的代码来完成我需要的事情,并且速度性能非常接近于向量x和y都浮动时的情况:

代码语言:javascript
复制
  void vector_operation(const size_t i) 
  {
    __m128 X = _mm_load_ps(x + i);
    __m128 Y = _mm_movelh_ps(_mm_cvtpd_ps(_mm_load_pd(yD + i + 0)), _mm_cvtpd_ps(_mm_load_pd(yD + i + 2)));
    //inner-products accumulation
    res = _mm_add_ps(res, _mm_mul_ps(X, Y));
  }   

现在,为了进一步加快速度,我用AVX指令集实现了一个相应的版本:

代码语言:javascript
复制
  inline void vector_operation(const size_t i) 
  {
    __m256 X = _mm256_load_ps(x + i);
    __m128 yD1 = _mm_cvtpd_ps(_mm_load_pd(yD + i + 0));
    __m128 yD2 = _mm_cvtpd_ps(_mm_load_pd(yD + i + 2));
    __m128 yD3 = _mm_cvtpd_ps(_mm_load_pd(yD + i + 4));
    __m128 yD4 = _mm_cvtpd_ps(_mm_load_pd(yD + i + 6));

    __m128 Ylow = _mm_movelh_ps(yD1, yD2);
    __m128 Yhigh = _mm_movelh_ps(yD3, yD4);

    //Pack __m128 data inside __m256 
    __m256 Y = _mm256_permute2f128_ps(_mm256_castps128_ps256(Ylow), _mm256_castps128_ps256(Yhigh), 0x20);

    //inner-products accumulation 
    res = _mm256_add_ps(res, _mm256_mul_ps(X, Y));
  }

我还测试了其他AVX实现,例如,使用浇铸和插入操作,而不是执行数据。与x和y向量都浮动的情况相比,性能较差。

AVX代码的问题是,无论我如何实现它,它的性能都远远不如仅使用浮点x和y向量(即不需要双浮点数转换)所实现的性能。

对于yD向量,从double到float的转换看起来相当快,而在将数据插入_m256 Y寄存器的行中则浪费了大量时间。

你知道这是不是AVX的一个众所周知的问题吗?

你有什么办法能保持好的表现吗?

提前感谢!

EN

回答 1

Stack Overflow用户

发布于 2018-03-21 23:37:45

我重写了你的功能,更好地利用了AVX提供的功能。我还在末尾使用了融合乘法加法;如果你不能使用FMA,只需用加法和乘法替换这一行。我现在只看到,我编写了一个使用未对齐负载的实现,而您的实现使用对齐加载,但我不会因此而失去任何睡眠。:)

代码语言:javascript
复制
__m256 foo(float*x, double* yD, const size_t i, __m256 res_prev)
{
  __m256 X = _mm256_loadu_ps(x + i);

  __m128 yD21 = _mm256_cvtpd_ps(_mm256_loadu_pd(yD + i + 0));
  __m128 yD43 = _mm256_cvtpd_ps(_mm256_loadu_pd(yD + i + 4));

  __m256 Y = _mm256_set_m128(yD43, yD21);

  return _mm256_fmadd_ps(X, Y, res_prev);
}

我做了一个快速的便签,并比较了您和我的实现的运行时间。我尝试了两种不同的基准测试方法,每次我的代码大约快15%。我使用MSVC14.1编译器,用/O2和/arch:AVX2标志编译程序。

编辑:这是函数的反汇编:

代码语言:javascript
复制
vcvtpd2ps   xmm3,ymmword ptr [rdx+r8*8+20h]  
vcvtpd2ps   xmm2,ymmword ptr [rdx+r8*8]  
vmovups     ymm0,ymmword ptr [rcx+r8*4]  

vinsertf128 ymm3,ymm2,xmm3,1  

vfmadd213ps ymm0,ymm3,ymmword ptr [r9] 

编辑2:这是相同算法的AVX实现的反汇编:

代码语言:javascript
复制
vcvtpd2ps   xmm0,xmmword ptr [rdx+r8*8+30h]  
vcvtpd2ps   xmm1,xmmword ptr [rdx+r8*8+20h]  

vmovlhps    xmm3,xmm1,xmm0  
vcvtpd2ps   xmm0,xmmword ptr [rdx+r8*8+10h]  
vcvtpd2ps   xmm1,xmmword ptr [rdx+r8*8]  
vmovlhps    xmm2,xmm1,xmm0  

vperm2f128  ymm3,ymm2,ymm3,20h  

vmulps      ymm0,ymm3,ymmword ptr [rcx+r8*4]  
vaddps      ymm0,ymm0,ymmword ptr [r9]
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49414268

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档