-
應用級別
1.編譯器選項
許多編譯器具有自己的優(yōu)化方案莉炉,也是最容易最穩(wěn)定的實現方法
2.調用高性能庫
如:BLAS FFTW
3.去掉全局變量
4.受限指針
多個指針指向同一個內存地址或指向的內存地址有重疊黑滴,它會阻礙編譯器對程序進行指令重排、表達式移除等優(yōu)化挟憔。restrict標識符砰奕,指定受限指針
5.條件編譯
-
算法級別
1.索引順序
訪問多維數據時的局部性直接與各維數據在內存中存放的先后順序有關。如C語言中數據是以行為主序存放的,在計算時盡量按行訪問數據售睹。
for( int i = 0; i<M; i++){
float ret=0.0f;
for(int j =0 ;j<N;j++){
ret+=a[i][j];
}
r[i]=ret;
}
2.緩存分塊
3.軟件預取
數據被使用前,投機的加載到緩存中
4.查表法
會較少精度可训,實際項目中將查表法和線性插值結合減少精度的降低
-
函數級別
1.函數調用參數
如果函數的參數是大結構體或類昌妹,應當通過傳指針或引用減少調用時復制和返回時的銷毀開銷
2.內聯小函數
能夠消除函數調用的開銷,并提供更多的指令級并行握截,表達式移除等優(yōu)化機會飞崖。建議少于10行的函數inline
-
循環(huán)級別
1.循環(huán)展開
展開循環(huán)不但減少了每次的判斷數量和循環(huán)變量改變的次數,更能增加流水線執(zhí)行的性能
float sum=0.0f;
for(int i=0;i<num;i++){
sum+= a[i];
}
優(yōu)化后:
float sum=0.0f,sum1=0.0f,sum2=0.0f,sum3=0.0f;
for(int i = 0;i< num;i+=4){
sum1 +=a[i];
sum2 +=a[i+1];
sum3 +=a[i+2];
sum +=a[i+3];
}
sum +=sum1+sum2+sum3;
對于二層循環(huán)來說谨胞,建議優(yōu)先展開外層循環(huán)固歪,但不是一個普適的準則。
需要注意?枧@紊选!留意處理末尾的數據
2.循環(huán)累積
循環(huán)累積主要和循環(huán)展開同時使用叶沛,減少寄存器的使用量的同時保證平行度蒲讯。
float sum=0.0f,sum1=0.0f,sum2=0.0f;
for(int i = 0;i< num;i+=6){
sum1 +=a[i]+a[i+1];
sum +=a[i+2]+a[i+3];
sum2 +=a[i+4]+a[i+5];
}
sum +=sum1+sum2;
直接展開6次需要6個臨時變量,現在只需要3個灰署。
3.循環(huán)合并
for(int i=0; i<len; i++){{
x1 +=a[i];
}
for(int i=0; i<len; i++){{
x2 *=b[i];
}
合并后:
for(int i=0; i<len; i++){{
x1 +=a[i];
x2 *=b[i];
}
適合于小循環(huán)
4.循環(huán)拆分
相對于循環(huán)合并判帮,就是循環(huán)拆分局嘁。
-
語句級別
1.減少內存讀寫
2.選用盡量小的數據類型
3.結構體對齊
不同硬件平臺和編譯器對結構體對齊的要求不相同,
- 結構體占用總字節(jié)數盡量是2的冪
- 每個域的開始地址是他大小的整數倍脊另,比如在32位cpu下导狡,假設一個整型變量的地址為0x00000004,那它就是自然對齊的
- 編譯器提供了字節(jié)對齊的編譯語句
GCC下則在每個結構加attribute((aligned(4))): - 對于標準數據類型偎痛,它的地址只要是它的長度的整數倍就行了,而非標準數據類型按下面的原則對齊
1.數組 :按照基本數據類型對齊独郎,第一個對齊了后面的自然也就對齊了踩麦。
2.聯合 :按其包含的長度最大的數據類型對齊。
3.結構體: 結構體中每個數據類型都要對齊氓癌。
struct stu{
char sex;
int length;
char name[10];
};
struct stu my_stu;
由于在x86下谓谦,GCC默認按4字節(jié)對齊,它會在sex后面跟name后面分別填充三個和兩個字節(jié)使length和整個結構體對齊贪婉。于是我們sizeof(my_stu)會得到長度為20反粥,而不是15.
struct stu{
char sex;
int length;
char name[10];
}__attribute__ ((aligned (4)));
- 表達式移除
去掉重復的、共同的計算或訪問 - 分支優(yōu)化
1.盡量避免把判斷放到循環(huán)里
2.拆分循環(huán)疲迂,減少分支
3.合并多個條件
4.查表法移除分支
5.分支順序才顿。如:if( a&&b)若啊計算量大應該放后面
6.優(yōu)化交換性能
uchar tmp=a[ji];
a[ji]=a[[jj];
a[jj]=tmp;
可優(yōu)化為:
uchar aji=a[ji];
uchar ajj=a[[jj];
a[ji]=ajj;
a[jj]=aji;
后一段代碼雖然多一個臨時變量,但是讀寫間沒有關系尤蒿,并行讀高郑气!
-
指令級別
1.減少數據依賴
2.注意處理器多發(fā)射能力
3.優(yōu)化乘除法和模余
整數運算最多一個周期,而乘法要三個周期腰池,除法十幾個尾组,模余需要幾十或上百,移位運算只要一個周期示弓。
將除法轉換成乘法
4.選擇更具體的庫函數或算法
5.其他:如聲明float時加f后綴讳侨,使用const,static