为啥 SSE 和 AVX 具有相同的效率?

Posted

技术标签:

【中文标题】为啥 SSE 和 AVX 具有相同的效率?【英文标题】:why do the SSE and AVX have same efficiency?为什么 SSE 和 AVX 具有相同的效率? 【发布时间】:2013-08-30 10:19:05 【问题描述】:

我用的是vs2012,想测试一下SSE和AVX的效率。 SSE 和 AVX 的代码几乎一样, 除了 SSE 使用 _m128 而 AVX 使用 _m256。 我希望 AVX 代码比 SSE 代码快两倍, 但是测试结果显示它们的速度几乎是一样的。

我尝试选择 /arch:AVX 或 /arch:SSE 或 /NOT SET 并注释 SSE 代码或注释 AVX 代码, 无论我测试什么, 用于 SSE 代码的时间约为 2138 毫秒,而 AVX 代码约为 2106 毫秒。 外层for循环只是用来增加循环时间,

#include "testfun.h"
#include <iostream>
#include <time.h> 
#include <malloc.h>
#include "immintrin.h"
using namespace std;
#define dataLen  800000

void testfun()

float *buf1 = reinterpret_cast<float*>(_aligned_malloc( sizeof(float)*dataLen, 32 ));
float *buf2 = reinterpret_cast<float*>(_aligned_malloc( sizeof(float)*dataLen, 32 ));
for(int i=0; i<dataLen; i++)

    buf1[i] = 1;
    buf2[i] = 1;

double timePassed;
int t = clock();
float sum = 0;
//=========================SSE CODE=====================================
__m128 *p1 = (__m128 *)buf1;
__m128 *p2 = (__m128 *)buf2;
__m128 _result = _mm_set_ps1(0.0f);

for(int j=0;j<10000; j++)
   
    p1 = (__m128 *)buf1;
    p2 = (__m128 *)buf2;        
    _result = _mm_sub_ps(_mm_set_ps(j,0,0,0) ,_result);

    for(int i=0; i<dataLen/4; i++)
    
        _result = _mm_add_ps(_mm_mul_ps(*p1, *p2), _result);
        p1++;
        p2++;
    


sum = _result.m128_f32[0]+_result.m128_f32[1]+_result.m128_f32[2]+_result.m128_f32[3];
timePassed = clock() - t;
std::cout<<std::fixed<<"SSE calculate result : "<<sum<<std::endl;
std::cout<<"SSE time used: "<<timePassed<<"ms"<<std::endl;

//=========================AVX CODE=====================================
t = clock();
__m256  *pp1 ; 
__m256  *pp2 ; 
__m256 _rresult = _mm256_setzero_ps();
sum = 0;

for(int j=0;j<10000; j++)
   
    pp1 = (__m256*) buf1;
    pp2 = (__m256*) buf2;
    _rresult = _mm256_sub_ps(_mm256_set_ps(j,0,0,0,0,0,0,0), _rresult);

    for(int i=0; i<dataLen/8; i++)
           
        _rresult = _mm256_add_ps(_mm256_mul_ps(*pp1, *pp2), _rresult);
        pp1++;
        pp2++;
    


sum = _rresult.m256_f32[0]+_rresult.m256_f32[1]+_rresult.m256_f32[2]+_rresult.m256_f32[3]+_rresult.m256_f32[4]+_rresult.m256_f32[5]+_rresult.m256_f32[6]+_rresult.m256_f32[7];
timePassed = clock() - t;
std::cout<<std::fixed<<"AVX calculate result : "<<sum<<std::endl;
std::cout<<"AVX time used: "<<timePassed<<"ms"<<std::endl;

_aligned_free(buf1);
_aligned_free(buf2);

【问题讨论】:

【参考方案1】:

您很可能只是带宽受限,因为您的循环中只有两条算术指令,而且您有两个负载。如果您减小数据集的大小以使其适合缓存,那么您应该会看到性能上的差异(因为您将拥有更大的加载带宽并减少来自缓存的加载延迟)。

(此外,您的时间数字似乎非常高 - 请确保您使用的是发布版本,即您已启用优化,否则您的结果将具有误导性。)

【讨论】:

+1 此外,像推土机这样的 cpus 有两个统一的 sse 到每个模块的一个 avx 中,因此如果没有内存操作也可能无关紧要。我没试过。 你是对的,如果我将 "dataLen" 设置为 4000 ,并删除内部 for 循环上方的 _mm_sub_ps 和 _mm_set_ps 操作,那么 AVX 比 SSE 快大约两倍。 (在release模式下,设置为“Advanced Vector Extensions (/arch:AVX) )。我还是不太明白,为什么datalen对结果影响这么大。实际情况下,需要计算数组总是大于 4000。你的意思是如果数据集适合缓存,那么它总共只会加载一次,如果数据集大于缓存,那么它会在每个 for 循环中加载两次? @myej:现在 CPU 比内存快得多,这就是我们拥有越来越大的缓存的原因。为了获得最佳性能,您需要最大限度地减少缓存未命中,这意味着在数据从缓存中清除之前尽可能多地处理数据。如果您只执行少量操作,那么缓存未命中和带宽相对较低的 DRAM 访问的成本将超过任何计算优化。 我的cpu level1 cash 32kB,只能装8000个float,符合测试。如果两个数组都大于4000,那么AVX时间会逐渐超过SSE时间 重要的是优化您的软件设计,以便您在数据处于缓存中时组合对数据的操作,即,而不是执行func1(data); func2(data); func3(data);,每个函数都完全通过data,您strip-mine 或 tile 数据,这样func1func2func3 在循环中被调用,它们每个处理一个缓存友好的子集每次迭代的数据。 (这当然假设您可以像这样对您的数据进行其他操作。)

以上是关于为啥 SSE 和 AVX 具有相同的效率?的主要内容,如果未能解决你的问题,请参考以下文章

为啥并行 SIMD/SSE/AVX 需要置换?

为啥 AVX2 和 SSE2 按位 OR 运算符并不比简单的快?操作员?

Ubuntu - 如何判断 CPU 应用程序当前正在使用 AVX 还是 SSE?

是否所有支持 AVX2 的 CPU 也支持 SSE4.2 和 AVX?

如何检查编译代码是否使用SSE和AVX指令?

AVX mat4 inv 实现比 SSE 慢