linux编程的108种奇淫巧计之18(SIMD)
2011-03-28 09:23
330 查看
在优化的层次中,从上到下依次是,业务级,算法级,编码级,指令级,平台级,和硬件级。
业务级表示很多优化可以在业务讨论中被剪枝或者改进,例如业务真的需要用3个月的数据来做分析吗?还是2个月就够了?这需要产品经理,技术经理的经验,不在话下。
算法级主要集中在复杂度上,一个好的复杂度算法,哪怕实现的在拙劣可能都要远远好于一个优化到极致的差方法。往往大公司考试喜欢涉及这些方面。
编码级主要集中在语言上,语言使用的技巧,这方面的技巧非常多,也有很多书,C++编程思想等等。
指令级主要涉及到汇编和特定的处理器,这也有很多技巧,但需要一些低层的经验,本系列主要覆盖这个层次,也是比较冷门的层次。
平台级主要特指linux kernel的一些优化,将kernel优化到一些特定的应用上。
硬件级主要涉及具体的硬件,以及硬件的组合。
优秀的优化工程师需要兼顾从业务级到硬件级的各种知识,这样的人才非常宝贵。
上面是一些引子,本文继续讨论优化技巧,SIMD,单指令多数据,其简单含义就是将多个数据进行打包,用一条指令来完成多个数据的计算,和往常一样,还是举一个具体的例子。这是我最近优化的例子,可以说是第一个从现实而来的例子,此前的都是和我工作无关的。
简单解释一下这个函数的作用,code表示压缩后的编码,data中每个数都是0或者1,例如data【0】=0,data【1】=1,这是函数调用的先验假定,n是需要pack的数量,这里默认为128,其功能是将data[i](i=0-127)打包成一个4个整形(128bit)。
例如int data[128]={0,1,0.......0,1,1},
调用完PACK1(code,data,128)后
code[0]=3
code[1]=0
code[2]=0
code[3]=1073741824
将code按比特从高到低展开为
[01000000 00000000 00000000 00000000]
[00000000 00000000 00000000 00000000]
[00000000 00000000 00000000 00000000]
[00000000 00000000 00000000 00000011]
原来data为128*4=512字节。打包后只有4*4=16字节。
好,这个功能,应该讲清楚了,下面就是实现的代码,希望感兴趣的朋友动手实践,详细的代码分析,下回再说。还会介绍另外一种实现方法,以及指令集兼容的问题,希望读者持续关注。
本系列其他文章:http://blog.csdn.net/pennyliang/category/746545.aspx
业务级表示很多优化可以在业务讨论中被剪枝或者改进,例如业务真的需要用3个月的数据来做分析吗?还是2个月就够了?这需要产品经理,技术经理的经验,不在话下。
算法级主要集中在复杂度上,一个好的复杂度算法,哪怕实现的在拙劣可能都要远远好于一个优化到极致的差方法。往往大公司考试喜欢涉及这些方面。
编码级主要集中在语言上,语言使用的技巧,这方面的技巧非常多,也有很多书,C++编程思想等等。
指令级主要涉及到汇编和特定的处理器,这也有很多技巧,但需要一些低层的经验,本系列主要覆盖这个层次,也是比较冷门的层次。
平台级主要特指linux kernel的一些优化,将kernel优化到一些特定的应用上。
硬件级主要涉及具体的硬件,以及硬件的组合。
优秀的优化工程师需要兼顾从业务级到硬件级的各种知识,这样的人才非常宝贵。
上面是一些引子,本文继续讨论优化技巧,SIMD,单指令多数据,其简单含义就是将多个数据进行打包,用一条指令来完成多个数据的计算,和往常一样,还是举一个具体的例子。这是我最近优化的例子,可以说是第一个从现实而来的例子,此前的都是和我工作无关的。
简单解释一下这个函数的作用,code表示压缩后的编码,data中每个数都是0或者1,例如data【0】=0,data【1】=1,这是函数调用的先验假定,n是需要pack的数量,这里默认为128,其功能是将data[i](i=0-127)打包成一个4个整形(128bit)。
例如int data[128]={0,1,0.......0,1,1},
调用完PACK1(code,data,128)后
code[0]=3
code[1]=0
code[2]=0
code[3]=1073741824
将code按比特从高到低展开为
[01000000 00000000 00000000 00000000]
[00000000 00000000 00000000 00000000]
[00000000 00000000 00000000 00000000]
[00000000 00000000 00000000 00000011]
原来data为128*4=512字节。打包后只有4*4=16字节。
好,这个功能,应该讲清楚了,下面就是实现的代码,希望感兴趣的朋友动手实践,详细的代码分析,下回再说。还会介绍另外一种实现方法,以及指令集兼容的问题,希望读者持续关注。
#define dolaf3(x,y,z,o,p) "pxor %%xmm1,%%xmm1/npxor %%xmm2,%%xmm2/npxor %%xmm3,%%xmm3/npxor %%xmm4,%%xmm4/nmovhpd "#x"(%1),%%xmm1/npsllq $32,%%xmm1/nmovhpd "#y"(%1) ,%%xmm2/npsllq $32,%%xmm2/npsrlq $32,%%xmm2/nORPD %%xmm1,%%xmm2/nmovss "#z"(%1),%%xmm3/npsllq $32,%%xmm3/nmovss "#o"(%1),%%xmm4/nORPD %%xmm3,%%xmm4/npslld $"#p" ,%%xmm15/nORPD %%xmm2,%%xmm15/nORPD %%xmm4,%%xmm15/n" #define laf3(x) dolaf3(x*4,128+x*4,256+x*4,384+x*4,1) void PACK1(uint32_t* code,uint32_t* data,size_t n) { unsigned char* des = (unsigned char*)code; unsigned char* src = (unsigned char*)data; for(int i =0,j=0;j<n;src+=4*4,des+=128*4,j+=128) { __asm__ __volatile__( "pxor %%xmm15,%%xmm15/n" laf3(0) laf3(1) laf3(2) laf3(3) laf3(4) laf3(5) laf3(6) laf3(7) laf3(8) laf3(9) laf3(10) laf3(11) laf3(12) laf3(13) laf3(14) laf3(15) laf3(16) laf3(17) laf3(18) laf3(19) laf3(20) laf3(21) laf3(22) laf3(23) laf3(24) laf3(25) laf3(26) laf3(27) laf3(28) laf3(29) laf3(30) laf3(31) "movdqu %%xmm15 ,(%0)/n" ::"r"(des),"r"(src):"memory"); } __asm__ __volatile__ ( " sfence /n " :: ); };
本系列其他文章:http://blog.csdn.net/pennyliang/category/746545.aspx
相关文章推荐
- linux编程的108种奇淫巧计-11(乱序)【续】
- linux编程的108种奇淫巧计-2(RDTSC)【续】
- linux编程的108种奇淫巧计-4(编译展开)
- linux编程的108种奇淫巧计-1(FALSE SHARING)
- linux编程的108种奇淫巧计-7(Lock-free实验)
- linux编程的108种奇淫巧计-15(减少复制)
- linux编程的108种奇淫巧计-1(FALSE SHARING)【续】
- linux编程的108种奇淫巧计-7(Lock-free实验)
- linux编程的108种奇淫巧计-4(编译展开)
- linux编程的108种奇淫巧计-1(FALSE SHARING)【续】
- linux编程的108种奇淫巧计-2(RDTSC)
- linux编程的108种奇淫巧计-3(magic 2)
- linux编程的108种奇淫巧计-4(编译展开)
- linux编程的108种奇淫巧计-12(存储计算)
- linux编程的108种奇淫巧计-4(编译展开)
- linux编程的108种奇淫巧计-7(再答gangban_lau)
- linux编程的108种奇淫巧计-11(乱序)
- linux编程的108种奇淫巧计-1(FALSE SHARING)
- linux编程的108种奇淫巧计-4(编译展开)(续)
- linux编程的108种奇淫巧计-16(如何达到内存最大带宽,复杂指令)【续】