Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/135.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/url/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 从SSE转换为AVX的处罚?_C++_Sse_Avx_Sse2 - Fatal编程技术网

C++ 从SSE转换为AVX的处罚?

C++ 从SSE转换为AVX的处罚?,c++,sse,avx,sse2,C++,Sse,Avx,Sse2,我知道从AVX指令切换到SSE指令而不首先将所有ymm寄存器的上半部分归零的现有惩罚,但在我的机器上(i7-39K 3.2GHz),如果换成另一种方式(SSE到AVX),似乎会受到很大的惩罚,即使我在AVX代码段之前和之后显式使用了_mm256_zeropper 我编写了一些函数,用于在32位浮点和32位定点整数之间进行转换,它们位于两个32768个元素宽的缓冲区上。我将一个SSE2内部版本直接移植到AVX,在SSE2的4个元素上同时执行8个元素,期望看到显著的性能提升,但不幸的是,情况恰恰相反

我知道从AVX指令切换到SSE指令而不首先将所有ymm寄存器的上半部分归零的现有惩罚,但在我的机器上(i7-39K 3.2GHz),如果换成另一种方式(SSE到AVX),似乎会受到很大的惩罚,即使我在AVX代码段之前和之后显式使用了_mm256_zeropper

我编写了一些函数,用于在32位浮点和32位定点整数之间进行转换,它们位于两个32768个元素宽的缓冲区上。我将一个SSE2内部版本直接移植到AVX,在SSE2的4个元素上同时执行8个元素,期望看到显著的性能提升,但不幸的是,情况恰恰相反

因此,我有两个功能:

void ConvertPcm32FloatToPcm32Fixed(int32* outBuffer, const float* inBuffer, uint sampleCount, bool bUseAvx)
{
    const float fScale = (float)(1U<<31);

    if (bUseAvx)
    {
        _mm256_zeroupper();
        const __m256 vScale = _mm256_set1_ps(fScale);
        const __m256 vVolMax = _mm256_set1_ps(fScale-1);
        const __m256 vVolMin = _mm256_set1_ps(-fScale);

        for (uint i = 0; i < sampleCount; i+=8)
        {
            const __m256 vIn0 = _mm256_load_ps(inBuffer+i); // Aligned load
            const __m256 vVal0 = _mm256_mul_ps(vIn0, vScale);
            const __m256 vClamped0 = _mm256_min_ps( _mm256_max_ps(vVal0, vVolMin), vVolMax );
            const __m256i vFinal0 = _mm256_cvtps_epi32(vClamped0);
            _mm256_store_si256((__m256i*)(outBuffer+i), vFinal0); // Aligned store
        }
        _mm256_zeroupper();
    }
    else
    {
        const __m128 vScale = _mm_set1_ps(fScale);
        const __m128 vVolMax = _mm_set1_ps(fScale-1);
        const __m128 vVolMin = _mm_set1_ps(-fScale);

        for (uint i = 0; i < sampleCount; i+=4)
        {
            const __m128 vIn0 = _mm_load_ps(inBuffer+i); // Aligned load
            const __m128 vVal0 = _mm_mul_ps(vIn0, vScale);
            const __m128 vClamped0 = _mm_min_ps( _mm_max_ps(vVal0, vVolMin), vVolMax );
            const __m128i vFinal0 = _mm_cvtps_epi32(vClamped0);
            _mm_store_si128((__m128i*)(outBuffer+i), vFinal0); // Aligned store
        }
    }
}

void ConvertPcm32FixedToPcm32Float(float* outBuffer, const int32* inBuffer, uint sampleCount, bool bUseAvx)
{
    const float fScale = (float)(1U<<31);

    if (bUseAvx)
    {
        _mm256_zeroupper();
        const __m256 vScale = _mm256_set1_ps(1/fScale);

        for (uint i = 0; i < sampleCount; i+=8)
        {
            __m256i vIn0 = _mm256_load_si256(reinterpret_cast<const __m256i*>(inBuffer+i)); // Aligned load
            __m256 vVal0 = _mm256_cvtepi32_ps(vIn0);
            vVal0 = _mm256_mul_ps(vVal0, vScale);
            _mm256_store_ps(outBuffer+i, vVal0); // Aligned store
        }
        _mm256_zeroupper();
    }
    else
    {
        const __m128 vScale = _mm_set1_ps(1/fScale);

        for (uint i = 0; i < sampleCount; i+=4)
        {
            __m128i vIn0 = _mm_load_si128(reinterpret_cast<const __m128i*>(inBuffer+i)); // Aligned load
            __m128 vVal0 = _mm_cvtepi32_ps(vIn0);
            vVal0 = _mm_mul_ps(vVal0, vScale);
            _mm_store_ps(outBuffer+i, vVal0); // Aligned store
        }
    }
}
void ConvertPcm32FloatToPcm32Fixed(int32*exputffer、const float*inBuffer、uint sampleCount、bool bUseAvx)
{

const float fScale=(float)(1U我没有测试您的代码,但是由于您的测试看起来很短,可能您看到了Agner Fog在其第101页(这适用于Sandy Bridge体系结构)中讨论的浮点预热效果。我引用:

处理器未出现任何浮动时处于冷态 指向指令一段时间。256位向量的延迟 加法和乘法最初比 理想的数字,然后再长一个时钟,然后再长几百个 浮点指令处理器进入热状态,其中 延迟分别为3和5个时钟。吞吐量为 冷态下256位矢量运算的理想值。128位 矢量运算受这种预热效应的影响较小 128位向量加法和乘法的延迟为 大多数情况下,一个时钟周期比理想值长,且吞吐量低 在冷态下不会还原


我的印象是,除非编译器使用VEX指令格式对SSE指令进行编码,就像Paul R所说的-vmulps而不是mulps,否则影响是巨大的

当优化小段时,我倾向于使用Intel提供的这个不错的工具和一些好的ol基准测试

IACA生成的报告包括以下符号:


“@-SSE指令跟随AVX256指令,预计会有几十个周期的惩罚”

您能提供一个吗?对于SSE代码,您使用的是旧SSE(破坏性)还是新SSE(非破坏性)指令?我的理解是AVX-SSE切换惩罚只适用于前一个旧SSE的破坏性。但是从阅读文档来看,它无论如何都不重要,因为我在去AVX而不是来自AVX的时候受到了伤害。已经添加了C++代码。通过在计时器之前运行SSE2版本来缓存缓冲区,然后在计时器之后运行AVX版本来实现,但性能损失仍然存在。如果使用-mavx编译SSE代码,则应该使用新的(非破坏性的)SSE说明,例如
VMULPS
而不是
MULPS
——上面的代码是您在测试中实际使用的代码,还是真正的代码有单独的模块,使用/不使用
-mavx
编译?谢谢,Robert。这似乎很适合症状,但我想知道“一段时间”需要多长时间真的是这样。在我的例子中,转换代码每21毫秒执行一次,每次都有相同的效果。值得一提的是,我也可以在完全不同的(特殊的)系统上运行相同的测试CPU架构和编译器也有AVX,我一点也不知道AVX会受到什么样的惩罚,但我不确定我是否有权说这个系统到底是什么。