我知道从AVX指令切换到SSE指令的现有惩罚,而没有先将所有ymm寄存器的上半部分归零,但在我的机器上的特殊情况下(i7-3939K 3.2GHz),似乎有一个非常反之亦然(SSE到AVX),即使我在AVX代码部分之前和之后明确使用_mm256_zeroupper.
我编写了用于在32位浮点数和32位定点整数之间进行转换的函数,在2个32768元素宽的缓冲区上.我将一个SSE2内在版本直接移植到AVX,在SSE的4上同时执行8个元素,期望看到显着的性能提升,但不幸的是,相反的情况发生了.
所以,我有2个功能:
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
        }
    }
}
所以我运行启动计时器,运行ConvertPcm32FloatToPcm32Fixed然后ConvertPcm32FixedToPcm32Float直接转换回来,结束计时器.SSE2版本的函数执行总共15-16微秒,但XVX版本需要22-23微秒.有点困惑,我挖了一下,我发现如何加速AVX版本,使它们比SSE2版本更快,但它是作弊.我只是在启动计时器之前运行ConvertPcm32FloatToPcm32Fixed,然后启动计时器,再次运行ConvertPcm32FloatToPcm32Fixed,然后转换ConvertPcm32FixedToPcm32Float,停止计时器.好像SSE对AVX有一个巨大的惩罚,如果我先用试运行"启动"AVX版本,AVX执行时间会下降到12微秒,而使用SSE等价物做同样的事情只会减少时间微秒到14,使AVX在这里成为边缘赢家,但前提是我作弊.我认为AVX可能不像SSE那样与缓存一样好,但是使用_mm_prefetch也无法帮助它.
我在这里错过了什么吗?
| 归档时间: | 
 | 
| 查看次数: | 1910 次 | 
| 最近记录: |