用SSE指令打点产品性能:DPPS值得使用吗?

问题描述 投票:0回答:1

通过 SSE4.1 计算两个短(4 元素)向量的点积更快

dpps
还是使用一系列
mulps
/
shufps
/
addps
上交所1的指示?

(对于大向量,当然最好将

mulps
/
addps
放入向量累加器并在最后进行一个水平求和,有足够的求和向量来隐藏 FP 延迟

assembly x86 simd sse dot-product
1个回答
6
投票

答案可能与上下文密切相关,并且完全取决于它在更大的代码流中的使用位置和方式,以及您所使用的硬件。

从历史上看,当英特尔推出新指令时,他们并没有专门为其投入太多硬件区域。如果它得到足够的采用和使用,他们会在后代中投入更多的硬件。因此,就原始 ALU 性能而言,与 SSE2 方式相比,Penryn 上的

_mm_dp_ps
并不是特别令人印象深刻。另一方面,它确实需要更少的指令缓存中的指令,因此当更紧凑的编码性能更好时,它可能会有所帮助。

_mm_dp_ps
的真正问题是作为 SSE 4.1 的一部分,你不能指望它在每台现代 PC 上都得到支持(Valve 的 Steam 硬件调查显示,对于游戏玩家来说,它的支持率约为 85%)。因此,您最终必须编写受保护的代码路径而不是直线代码,这通常比使用指令所获得的好处要高。

2024 年 2 月更新:SSE2/SSE3 在 Steam 上的利用率为 100%。 SSSE3、SSE4.1、SSE 4.2 为 99%。甚至 AVX 和 AVX2 也处于 90 年代上层。如今,使用

/arch:AVX
构建游戏是合理的,检查启动时是否支持 SSE/SSE2/SSE3/SSSE3/SSE4.1/SSE4.2/AVX,并且不支持缺乏任何支持的机器其中。

如果您正在为保证支持它的 CPU 制作二进制文件,那么它很有用。例如,如果您使用

/arch:AVX
(甚至是
/arch:AVX2
)进行构建,无论是因为您的目标是 Xbox One 等固定平台,还是正在构建 EXE/DLL 的多个版本,您可以假设 SSE 4.1 将受到支持好吧。

这实际上就是 DirectXMath 的作用:

inline XMVECTOR XMVector4Dot( FXMVECTOR V1, FXMVECTOR V2 )
{
#if defined(_XM_NO_INTRINSICS_)

    XMVECTOR Result;
    Result.vector4_f32[0] =
    Result.vector4_f32[1] =
    Result.vector4_f32[2] =
    Result.vector4_f32[3] = V1.vector4_f32[0] * V2.vector4_f32[0] + V1.vector4_f32[1] * V2.vector4_f32[1] + V1.vector4_f32[2] * V2.vector4_f32[2] + V1.vector4_f32[3] * V2.vector4_f32[3];
    return Result;

#elif defined(_M_ARM) || defined(_M_ARM64)

    float32x4_t vTemp = vmulq_f32( V1, V2 );
    float32x2_t v1 = vget_low_f32( vTemp );
    float32x2_t v2 = vget_high_f32( vTemp );
    v1 = vpadd_f32( v1, v1 );
    v2 = vpadd_f32( v2, v2 );
    v1 = vadd_f32( v1, v2 );
    return vcombine_f32( v1, v1 );

#elif defined(__AVX__) || defined(__AVX2__)

    return _mm_dp_ps( V1, V2, 0xff );

#elif defined(_M_IX86) || defined(_M_X64)

    XMVECTOR vTemp2 = V2;
    XMVECTOR vTemp = _mm_mul_ps(V1,vTemp2);
    vTemp2 = _mm_shuffle_ps(vTemp2,vTemp,_MM_SHUFFLE(1,0,0,0));
    vTemp2 = _mm_add_ps(vTemp2,vTemp);
    vTemp = _mm_shuffle_ps(vTemp,vTemp2,_MM_SHUFFLE(0,3,0,0));
    vTemp = _mm_add_ps(vTemp,vTemp2);
    return _mm_shuffle_ps(vTemp,vTemp,_MM_SHUFFLE(2,2,2,2));

#else
    #error Unsupported platform
#endif
}

这当然假设您将在其他向量运算中使用点积的“标量”结果。按照惯例,DirectXMath 返回这样的标量“分布”在返回向量上。

参见 DirectXMath:SSE4.1 和 SSE4.2

更新: 虽然不像 SSE/SSE2 支持那么普遍,但对于不使用

/arch:AVX
/arch:AVX2
构建的情况,您可能需要 SSE3 支持,并尝试:

inline XMVECTOR XMVector4Dot(FXMVECTOR V1, FXMVECTOR V2)
{
    XMVECTOR vTemp = _mm_mul_ps(V1,V2);
    vTemp = _mm_hadd_ps( vTemp, vTemp );
    return _mm_hadd_ps( vTemp, vTemp );
}

也就是说,目前尚不清楚

hadd
在大多数情况下至少在点积方面优于 SSE/SSE2 添加和洗牌解决方案。

© www.soinside.com 2019 - 2024. All rights reserved.