gpt4 book ai didi

c++ - 使用混合(浮点、 double )输入 vector 执行 AVX 内积运算的最快方法

转载 作者:可可西里 更新时间:2023-11-01 18:38:14 26 4
gpt4 key购买 nike

我需要为混合单精度/ double 浮点 vector 构建一个单精度浮点内积例程,利用 SIMD 的 AVX 指令集寄存器为 256 位。

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

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

使用 SSE2 指令集,我能够实现一个非常快速的代码来满足我的需要,并且速度性能非常接近 vector x 和 y 都是 float 的情况:

  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指令集实现了一个对应的版本:

  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 vector 均为 float 的情况相比,性能相对较差。

AVX 代码的问题在于,无论我如何实现它,它的性能远不如仅使用 float x 和 y vector (即不需要双 float 转换)所实现的性能。

yD vector 从 double 到 float 的转换看起来相当快,但在将数据插入 _m256 Y 寄存器的行中浪费了很多时间。

您知道这是否是 AVX 的一个众所周知的问题吗?

您有可以保持良好性能的解决方案吗?

提前致谢!

最佳答案

我重写了您的函数并更好地利用了 AVX 所提供的功能。最后我还使用了融合乘加;如果您不能使用 FMA,只需将该行替换为加法和乘法即可。我现在才看到我写了一个使用未对齐负载的实现,而你的使用对齐负载,但我不会为此失眠。 :)

__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% 左右。我使用 MSVC 14.1 编译器并使用/O2 和/arch:AVX2 标志编译程序。

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

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 实现的反汇编:

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]

关于c++ - 使用混合(浮点、 double )输入 vector 执行 AVX 内积运算的最快方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49414268/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com