18(SIMD)
在優化的層次中,從上到下依次是,業務級,算法級,編碼級,指令級,平臺級,和硬件級。
業務級表示很多優化可以在業務討論中被剪枝或者改進,例如業務真的需要用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為1284=512字節。打包後只有44=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 "
::
);
};