Depoly your flask app into Heroku Fix shit IE code manually ISBN to Book Category by Scraping DangDang A Generic Makefile for C/C++ Program Configure Raspberry pi Remove watermark with PyPDF2 tips for docker Anaconda+TensorFlow+CUDA Snippets Configure Remote Mathematica Kernel Build your own ngrok server Access Array SSL VPN 使用Rstudio制作html5幻灯片 tips for Mac OS X system Tips for ipython notebook 配置Ubuntu server + Openbox (Obuntu) tips for Vimperator tips for Vim 安装CUDA My First Jekyll Blog rsync常见选项 在Linux中读取Ipod touch的文件 tip for texmacs 在VPS上建站的一些tip Gnuplot绘图札记 Samba系统和autofs自动挂载 Linux中alsamixer声卡无法录音 搭建自己的RSS订阅器——Tiny Tiny RSS Grub2引导安装Ubuntu awk tips 将Ubuntu系统装入U盘 The Great Rtorrent 编译GCC 再这样剁手!!!该死的libgd 使用ulimit进行资源限制 使用SSH代理上IPV6 使用RCurl抓取网页数据 修复Ubuntu Grub记 openbox中的文件关联 在Ubuntu 12.04下编译qtiplot 处理BCM4312网卡驱动纪实 配置我的Ubuntu Server记 Cygwin杂记 Linux 使普通用户具有以超级权限执行脚本 让firefox自定义地处理文件类型 WordPress优秀主题及插件 在phpcloud上搭建wordpress UBUNTU下用pptpd做VPN server ubuntu升级内核过后的一些问题 安装telnet服务 kubuntu札记 64位kubuntu札记 统计软件R virtualbox stardict星际译王 Ubuntu重装windows系统后的grub引导修复 SSH服务及花生壳域名解析 采用cbp2make工具由code::blocks工程创建makefile文件 UBUNTU 札记

SSE指令集加速运算

2012年07月24日

先上代码:

/*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;
}