先上代码:
/*g++ -msse2 main.cpp -lrt*/
#include <iostream>
#include <xmmintrin.h>//SSE指令集需包含词头文件
#include <time.h>
using namespace std;
#define N 120
int main() {
struct timespec tpstart,tpend;
clock_gettime(CLOCK_MONOTONIC, &tpstart);
/////////////////do something
{
__m128 *p1,*p2,*p3;//__m128是一个长128位的数据类型,存放在寄存器中
__attribute(aligned(128)) float f1[N],f2[N],f3[N];//新建一些浮点型数组
/*__attribute(aligned(128))强制使编译器在给f1等分配
内存空间时对齐在128位(8字节)上*/
//cout<<f1<<"t"<<(int)f1%128<<endl;
/*运行此条语句可以看出地址f1总是128的倍数,在内存上即
是总存在一行上,使得总线取值时能够一次取完*/
for(int i=0; i<N; i++) {
f1[i]=i+0.12;
f2[i]=i+0.16;
}
for(int time=0; time<10000; time++) {
p1=(__m128*)f1;
p2=(__m128*)f2;
p3=(__m128*)f3;
for(int i=0; i<N; i+=4) {
*p3=_mm_mul_ps(*p1,*p2);//此函数封装了一些汇编原语,使得可以同时计算4个值的乘法
p3++;
p2++;
p1++;
}
/*注意N的取值,N取为4的整数倍,使得最后一次调
用SSE指令时刚好能全部处理完。否则容易引发段错误。
所以,即使不能使用完,也一定要申请4的整数倍空间*/
}
}
/////////////////done
clock_gettime(CLOCK_MONOTONIC, &tpend);
long timedif = (tpend.tv_sec-tpstart.tv_sec)*1000*1000+(tpend.tv_nsec-tpstart.tv_nsec)/1000;
cout<<"SSE:t"<<timedif<<endl;
/////////////////////////不采用SSE指令/////////////////////////////////////
clock_gettime(CLOCK_MONOTONIC, &tpstart);
/////////////////do something
{
float f1[N],f2[N],f3[N];
for(int i=0; i<N; i++) {
f1[i]=i+0.12;
f2[i]=i+0.16;
}
for(int time=0; time<10000; time++) {
for(int i=0; i<N; i++) {
f3[i]=f1[i]*f2[i];
}
}
}
/////////////////done
clock_gettime(CLOCK_MONOTONIC, &tpend);
timedif = (tpend.tv_sec-tpstart.tv_sec)*1000*1000+(tpend.tv_nsec-tpstart.tv_nsec)/1000;
cout<<"noSSE:t"<<timedif<<endl;
return 0;
}
注意计时函数需要包含的头文件和编译选项,clock_gettime函数能精确到纳秒。
运行结果为:
SSE: 4929
noSSE: 9980
以微秒为单位,平均提高约两倍。
下面是另一份代码,演示如何动态申请空间,注意内存对齐:
#include <xmmintrin.h>
#include <iostream>
using namespace std;
const int N=120;
int main()
{
__m128 *p1,*p2,*p3;
__attribute(aligned(128)) float *pf1,*pf2,*pf3;
pf1=(float *)_mm_malloc(sizeof(float)*N,128);
pf2=(float *)_mm_malloc(sizeof(float)*N,128);
pf3=(float *)_mm_malloc(sizeof(float)*N,128);
cout<<(int)pf1%128<<endl;
cout<<(int)pf2%128<<endl;
cout<<(int)pf3%128<<endl;
for(int i=0;i<N;i++){
pf1[i]=i+0.12;
pf2[i]=i+0.16;
};
p1=(__m128*)pf1;
p2=(__m128*)pf2;
p3=(__m128*)pf3;
for(int i=0;i<N;i+=4){
*p3=_mm_add_ps(*p1,*p2);
p3++;
p2++;
p1++;
}
_mm_free(pf1);
_mm_free(pf2);
_mm_free(pf3);
return 0;
}