C++ 優(yōu)化方法
1.單個線程中,將加鎖變量取出來,傳遞給局部變量,然后釋放加鎖變量,可有效減少加鎖時間。
?
void?QCJSynchronizer::core()?{
????while?(run_flag_)?{
????????std::deque?data;
????????{
????????????std::unique_lock?lock(mutex_);
????????????if?(msg_deque_.empty())?{
????????????????condition_.wait(lock);
????????????????if?(!run_flag_)?{
????????????????????continue;
????????????????}
????????????}
????????????data?=?msg_deque_;???//?msg指針傳遞給局部變量data指針
????????????msg_deque_.clear();??//?msg指針清空,不再指向內(nèi)存空間
????????}
??//?后續(xù)就是線程內(nèi)部對局部變量的處理,不需要加速
????????while?(!data.empty())?{
???//?work
????????????//?1.?正常情況,所有的消息序列都在均勻地接收消息數(shù)據(jù)
????????????if?(deque.size()?==?(size_t)?1)?{
????//?work
????????????}?else?{
????????????}
????????????//?2.?不正常情況,某一個已經(jīng)超過了queue_size
???//?work
????????}
????}
}
?
2.4個變量的向量需要計算,可使用vmulq_f32并行處理加速
?
//?××××××××××××××??x86平臺???××××××××××××××
void?so3(const?float?*src,?float?*tgt)?const?{
????__m128?p0?=?_mm_mul_ps(_mm_load_ps1(&src[0]),?c[0]);???//?并行處理
????__m128?p1?=?_mm_mul_ps(_mm_load_ps1(&src[1]),?c[1]);
????__m128?p2?=?_mm_mul_ps(_mm_load_ps1(&src[2]),?c[2]);
????_mm_store_ps(tgt,?_mm_add_ps(p0,?_mm_add_ps(p1,?p2)));
}
?
_mm_mul_ps:
Multiplies the four single-precision, floating-point values of a and b.
3.Strength reduction
3.1 由于不同指令本身的速度就是不一樣的,比較、整型的加減、位操作速度都是最快的,而除法/取余卻很慢。
?
#include?#include? //?獲取一個整數(shù)對應(yīng)10進制的位數(shù) uint32_t?digits10_v1(uint64_t?v)?{ ????uint32_t?result?=?0; ????do?{ ????????++result; ????????v?/=?10; ????}?while?(v); ????return?result; } uint32_t?digits10_v2(uint64_t?v)?{ ??uint32_t?result?=?1; ??for?(;;)?{ ????if?(v?10)?return?result; ????if?(v?100)?return?result?+?1; ????if?(v?1000)?return?result?+?2; ????if?(v?10000)?return?result?+?3; ????//?Skip?ahead?by?4?orders?of?magnitude ????v?/=?10000U; ????result?+=?4; ??} } uint32_t?digits10_v3(uint64_t?v)?{ ????if?(v?10)?return?1; ????if?(v?100)?return?2; ????if?(v?1000)?return?3; ????if?(v?1000000000000)?{????//?10^12 ????????if?(v?100000000)?{????//?10^7 ????????????if?(v?1000000)?{??//?10^6 ????????????????if?(v?10000)?return?4; ????????????????return?5?+?(v?>=?100000);?//?10^5 ????????????} ????????????return?7?+?(v?>=?10000000);?//?10^7 ????????} ????????if?(v?10000000000)?{??//?10^10 ????????????return?9?+?(v?>=?1000000000);?//?10^9 ????????} ????????return?11?+?(v?>=?100000000000);?//?10^11 ????} ????return?12?+?digits10_v3(v?/?1000000000000);?//?10^12 } #define?ITEM_COUNT?100 #define?RUN_TIMES?99 int?main(int?argc,?char?**argv) { ????srand(100); ????uint64_t?digit10_array[ITEM_COUNT]; ????for(?int?i?=?0;?i? ?
編譯一下:
?
qiancj@qianchengjun:~/ShareFolder/5Codes/test/build$?g++?-g?-O2?../optimizatize.cpp??&&?./a.out?
結(jié)果:
?
sum1:935?????????sum2:935????????sum3:935 cost1:6us????????cost2:3us???????cost3:1us???????cost2/cost1:0.5?????????cost3/cost1:0.166667?
核心原因是 digits10_v2 用比較和加法來減少除法 (/=) 操作,digits10_v3 通過搜索的方式進一步減少了除法操作。
3.2 整形:
1.類型轉(zhuǎn)換:
int--> short/char (0~1 clock cycle)
int --> float/double (4~16個clock cycle), signed int 快于 unsigned int,唯一一個場景 signed 比 unsigned 快的
short/char?的計算通常使用?32bit?存儲,只是返回的時候做了截取,故只在要考慮內(nèi)存大小的時候才使用?short/char,如?array
注:隱式類型轉(zhuǎn)換可能會溢出,有符號的溢出變成負(fù)數(shù),無符號的溢出變成小的整數(shù)
2.運算:
除法、取余運算unsigned int?快于signed int
除以常量比除以變量效率高,因為可以在編譯期做優(yōu)化,尤其是常量可以表示成2^n時
++i和i++本身性能一樣,但不同的語境效果不一樣,如array[i++]比arry[++i]性能好;當(dāng)依賴自增結(jié)果時,++i性能更好,如a=++b,a和b可復(fù)用同一個寄存器
代碼示例
?
//?div和mod效率 Timer?timer; int?a,?b,?c; timer.tic(); a?=?b?/?c;?//?This?is?slow double?time4?=?timer.toc(true); std::cout?<"a?=?b?/?c?"?<?
結(jié)果:
公式 耗時(us) a = b / c 0.054 a = b / 10 0.039 a = (unsigned int)b / 10 0.038 a = b / 16 0.036 a = (unsigned int)b / 16 0.037 3.3 浮點型:
單精度、雙精度的計算性能是一樣的
常量的默認(rèn)精度是雙精度
不要混淆單精度、雙精度,混合精度計算會帶來額外的精度轉(zhuǎn)換開銷
?
//?混用 float?a,?b; a?=?b?*?1.2;?//?bad.?先將b轉(zhuǎn)換成double,返回結(jié)果轉(zhuǎn)回成float float?a,?b; a?=?b?*?1.2f;?//?ok.?everything?is?float double?a,?b; a?=?b?*?1.2;?//?ok.?everything?is?double?
浮點除法比乘法慢很多,故可以利用乘法來加快速度
?
double?y,?a1,?a2,?b1,?b2; y?=?a1/b1?+?a2/b2;??????????????//?slow double?y,?a1,?a2,?b1,?b2; y?=?(a1*b2?+?a2*b1)?/?(b1*b2);?//?faster?
實際結(jié)果差不多,在除法較多的情況下,第二種方式肯定要快一點.
?
y?=?a1/b1?+?a2/b2??????????????0.026?us y?=?(a1*b2?+?a2*b1)?/?(b1*b2);?0.026?us?
時間比較:
?
comparisons?????????????????????????(1?clock?cycle) (u)int?add,?subtract,?bitops,?shift?(1?clock?cycle) floating?point?add,?sub?????????????(3~6?clock?cycle)? indexed?array?access????????????????(cache?effects) (u)int32?mul????????????????????????(3~4?clock?cycle) Floating?point?mul??????????????????(4~8?clock?cycle) Float?Point?division,?remainder?????(14~45?clock?cycle) (u)int?division,?remainder??????????(40~80?clock?cycle)?
3.4?減少內(nèi)存寫操作?一個很自然的優(yōu)化想法,應(yīng)該盡量避免內(nèi)存寫操作;對于內(nèi)存讀取,盡可能順序訪問內(nèi)存
?
struct?Bitfield?{ int?a:4; int?b:2; int?c:2; }; Bitfield?x; int?A,?B,?C; x.a?=?A; x.b?=?B; x.c?=?C;?
假定 A、B、C 都很小,且不會溢出,可以寫成
?
union?Bitfield?{ struct?{ int?a:4; int?b:2; int?c:2; }; char?abc; }; Bitfield?x; int?A,?B,?C; x.abc?=?A?|?(B?<4)?|?(C?<6);?
如果需要考慮溢出,也可以改為
?
x.abc?=?(A?&?0x0F)?|?((B?&?3)?<4)?|?((C?&?3)?<<6?);?
3.5?避免不必要的函數(shù),特別在最底層的循環(huán),應(yīng)該盡量讓代碼在一個函數(shù)內(nèi)??雌饋砼c良好的編碼習(xí)慣沖突(一個函數(shù)最好不要超過80行),其實不然,跟這個系列其他優(yōu)化一樣,我們應(yīng)該知道何時去使用這些優(yōu)化,而不是一上來就讓代碼不可讀。
3.6 嘗試使用inline函數(shù),讓函數(shù)調(diào)用的地方直接用函數(shù)體替換。inline對編譯器來說是個建議,而且不是inline了性能就好,一般當(dāng)函數(shù)比較小或者只有一個地方調(diào)用的時候,inline效果會比較好
3.7 在函數(shù)內(nèi)部使用循環(huán)
(e.g., change?for(i=0;i<100;i++) DoSomething(); into?DoSomething() { for(i=0;i<100;i++) { ... } }?)
3.8 減少函數(shù)的間接調(diào)用,如偏向靜態(tài)鏈接而不是動態(tài)鏈接,盡量少用或者不用多繼承、虛擬繼承
3.9 優(yōu)先使用迭代而不是遞歸
3.10?使用函數(shù)來替換define,從而避免多次求值。宏的其他缺點:不能overload和限制作用域(undef除外)
?
//?Use?macro?as?inline?function #define?MAX(a,b)?((a)?>?(b)???(a)?:?(b)) y?=?MAX(f(x),?g(x)); //?Replace?macro?by?template template?static?inline?T?max(T?const?&?a,?T?const?&?b)?{ return?a?>?b???a?:?b; } ?
3.11 ** 盡可能的減少跳轉(zhuǎn)和分支**,對于長的if...else,使用switch case,以減少后面條件的判斷,把最容易出現(xiàn)的條件放在最前面
3.12 在跳轉(zhuǎn)之間的代碼盡量減少數(shù)據(jù)依賴
3.13 多使用引用傳遞參數(shù),減少值傳遞
4 常見的優(yōu)化手段
1. 消除條件分支
代碼實例
?
if?(a??
優(yōu)化版本1
?
int?mask?=?(a-b)?>>?31; r?=?(mask?&?c)?|?(~mask?&?d);?
優(yōu)化版本2
?
int?mask?=?(a-b)?>>?31; r?=?d?+?mask?&?(c-d);?
優(yōu)化版本3
?
//?cmovg版本 r =?(a < b)??c : d;?
bool 類型變換
實例代碼
?
bool?a,?b,?c,?d; c?=?a?&&?b; d?=?a?||?b;?
編譯器的行為是
?
bool?a,?b,?c,?d; if?(a?!=?0)?{ ????if?(b?!=?0)?{ ????????c?=?1; ????} ????else?{ ????????goto?CFALSE; ????} } else?{ CFALSE: ????c?=?0; } if?(a?==?0)?{ ????if?(b?==?0)?{ ????????d?=?0; ????} ????else?{ ????????goto?DTRUE; ????} } else?{ DTRUE: ????d?=?1; }?
優(yōu)化版本
?
char?a?=?0,?b?=?0,?c,?d; c?=?a?&?b; d?=?a?|?b;?
實例代碼2
?
bool?a,?b; b?=?!a; //?優(yōu)化成 char?a?=?0,?b; b?=?a?^?1;?
反例
a && b?何時不能轉(zhuǎn)換成?a & b,當(dāng) a 不可能為?false?的情況下
a | | b?何時不能轉(zhuǎn)換成?a | b,當(dāng) a 不可能為?true?的情況下
2. 循環(huán)展開
實例代碼
?
int?i; for?(i?=?0;?i?20;?i++)?{ ????if?(i?%?2?==?0)?{ ????????FuncA(i); ????} ????else?{ ????????FuncB(i); ????} ????FuncC(i); }?
優(yōu)化版本
?
int?i; for?(i?=?0;?i?20;?i?+=?2)?{ ????FuncA(i); ????FuncC(i); ????FuncB(i+1); ????FuncC(i+1); }?
優(yōu)化說明
優(yōu)點:減少比較次數(shù)、某些CPU上重復(fù)次數(shù)越少預(yù)測越準(zhǔn)、去掉了if判斷
缺點:需要更多的code cache or micro-op cache、有些處理器(core 2)對于小循環(huán)性能很好(小于65bytes code)、循環(huán)的次數(shù)和展開的個數(shù)不匹配
一般編譯器會自動展開循環(huán),程序員不需要主動去做,除非有一些明顯優(yōu)點,比如減少上面的if判斷
3. 邊界檢查
實例代碼1
?
const?int?size?=?16;?int?i; float?list[size]; ... if?(i?0?||?i?>=?size)?{ ????cout?<"Error:?Index?out?of?range"; } else?{ ????list[i]?+=?1.0f; } //?優(yōu)化版本 if?((unsigned?int)i?>=?(unsigned?int)size)?{ ????cout?<"Error:?Index?out?of?range"; }else?{ ????list[i]?+=?1.0f; }?
實例代碼2
?
const?int?min?=?100,?max?=?110;?int?i; ... if?(i?>=?min?&&?i?<=?max)?{?... //優(yōu)化版本 if?((unsigned?int)(i?-?min)?<=?(unsigned?int)(max?-?min))?{?...?
4. 使用數(shù)組
實例代碼1
?
float?a;?int?b; a?=?(b?==?0)???1.0f?:?2.5f; //?使用靜態(tài)數(shù)組 float?a;?int?b; static?const?float?OneOrTwo5[2]?=?{1.0f,?2.5f}; a?=?OneOrTwo5[b?&?1];?
實例代碼2
?
//?數(shù)組的長度是2的冪 float?list[16];?int?i; ... list[i?&?15]?+=?1.0f;?
5. 整形的 bit array 語義,適用于 enum、const、define
?
enum?Weekdays?{ ????Sunday,?Monday,?Tuesday,?Wednesday,?Thursday,?Friday,?Saturday }; Weekdays?Day; if?(Day?==?Tuesday?||?Day?==?Wednesday?||?Day?==?Friday)?{ ????DoThisThreeTimesAWeek(); } //?優(yōu)化版本?using?& enum?Weekdays?{ ????Sunday?=?1,?Monday?=?2,?Tuesday?=?4,?Wednesday?=?8, ????Thursday?=?0x10,?Friday?=?0x20,?Saturday?=?0x40 }; Weekdays?Day; if?(Day?&?(Tuesday?|?Wednesday?|?Friday))?{ ????DoThisThreeTimesAWeek(); }?
?
審核編輯:湯梓紅
電子發(fā)燒友App





















評論