contributed by <ktvexe
>
yanglin5689446
static inline
改成 static inline __attribute__((always_inline))
的部分,感覺可以用巨集取代,這樣就不用將檔案的全部內容修改。資料:http://os.51cto.com/art/200703/41426.htm
翻譯-
使用Gnu gprof進行Linux平台下的程式分析
Gprof 簡介:
Gprof 的功能:列印出程式執行中各個函數消耗的時間,可以幫助programmer找出眾多函數中耗時最多的函数。產生程式執行時候的function call關係,包括call function得次數,可以幫助programmer分析程式的執行過程。
有了function call 的關係,會讓開發者大大提高工作效率,不用費心地去一點點找出程式的執行過程,這對小程式来说可能效果不是很行顯,但對於有幾萬,幾十萬程式碼的工程來說,效率是毋庸置疑的!而且這個功能對於維護舊程式碼或者是分析Open Source来说那是相當誘人的。
結論-
使用gprof可以了解各個function間互call的次數、時間等關係,可以由此找出需進行優化的片段。
晚點來研究使用gprof與perf top的使用時機與差異。
步驟-
gprof -b raytracing gmon.out | less
或gprof raytracing gmon.out | less
,差別在於是否有每個欄位的說明原始結果:
可以找出花費時間前幾名的function。
為什麼%time的比例與cumulative sec的結果不同呢?等下來研究。
答 : 沒有不同,cumulative sec是累加self sec而來,%time是self sec的比例
Original
執行時間-
gprof-
當然,如果不開gprof,執行時間會變快,因為少了 mcount 函數。
此函數在執行期間會記錄呼叫次數等相關資訊。而這些資訊會儲存至 gmon.out 中 - by 勃興筆記。
找到gprof2dot 的document: https://github.com/jrfonseca/gprof2dot
這是可以將各式profiler的output會製程dot圖的工具,像是perf或是gprof都可以,需先安裝python與graphviz。
$ ./raytracing
$ gprof raytracing| gprof2dot | dot -Tpng -o dot.png
$ perf record -g -- ./raytracing
$ perf script | c++filt | gprof2dot. -f perf | dot -Tpng -o output.png
可善用 POSIX Thread, OpenMP, software pipelining, 以及 loop unrolling。
所以直接看程式碼,由前面效能分析工具分析的結果可以知道,math-toolkit.h中的運算function是這次改善效能的重點,而
math-toolkit.h中的function都有static inline這行,先查一下資料。
inline function是一個keyword,提醒compiler可以將function本體直接填入呼叫該function的位置。
優點:
減少呼叫function的overhead,如參數傳遞、回傳值處理等。
切換到function會jump,也就是會有branch的行為。因為CPU的pipeline和cache的特性,會影響效能。
經由代換程式碼,也許可以增加最佳化的可能性。
static function-意思是說靜態函式只能被該檔案所看見,其它檔案無法得知該檔案是否有其靜態函式。
範例:
f1( )只在這個 Compilation Unit 中生效。而 f2( )可以被其他 Compilation Unit 訪問。
來畫個圖說明Compilation Unit 吧,使用graphviz吧。
每個經過preprocessor處理後的.c 檔,和它的目的檔是一一對應的,而Compilation Unit就是這些被處理後的.cpp 檔。
Compilation Unit就是經過preprocessor處理後的.c 檔,因為f2沒有static所以與其他Compilation Unit link時會找到多份的f2,產生錯誤,即使加inline也是。
HackMD可以直接產生graphviz不用自己產生圖片後貼上,開心
複習一下:
static function-意思是說靜態函式只能被該檔案所看見,其它檔案無法得知該檔案是否有其靜態函式。
範例
static void f1(){
cout << “f1()" << endl;
}
void f2(){
cout << “f2()" << endl;
}
f1( )只在這個 Compilation Unit 中生效。而 f2( )可以被其他 Compilation Unit 訪問。
來畫個圖說明Compilation Unit 吧,使用graphviz吧。
每個經過preprocessor處理後的.c 檔,和它的目的檔是一一對應的,而Compilation Unit就是這些被處理後的.cpp 檔。
Compilation Unit就是經過preprocessor處理後的.c 檔,因為f2沒有static所以與其他Compilation Unit link時會找到多份的f2,產生錯誤,即使加inline也是。
extern-extern可以聲明變數會在其它的位置被定義,這個位置可能是在同一份文件之中,或是在其它文件之中。
範例:
extern代表var並非在main.c中定義,compiler會找其它位置或文件中var的定義,而且extern時不可同時assign其值,會變成在該位置定義變數,結果就產生重複定義。
範例:
From: Linus Torvalds
No, we had this fight with the gcc people a few years back, and they have a very valid argument for the current semantics
I think the current gcc semantics are (a) more powerful than the old one and (b) have been in effect long enough that it's not painful for Linux to just switch over to them. In short, we might actually want to start taking advantage of them, and even if we don't we should just convert
all current users of "extern inline" to "static inline".
Linus
過去在撰寫C程式碼時並沒有特別注意過loop unrolling的問題,因為compiler optimization時自然會被處理掉,而且展開後在維護上其實並不方便,只有在寫assembly時才會刻意將loop展開。
執行時間-節省0.9秒
既然loop unrolling這類優化compiler optimilation時都會做,那不如先開optimilation來比較一下結果,要比也要知道對手是誰的概念。
-O0:
-O1:
-O2:
-O3:
然後就實作multithread,因為以前OS也練習過thread的使用,所以實作上很快,我是將圖的height分成四份,讓不同的thread去執行。
將原先的inline改成__attribute__ ((always_inline))
,才會被強制inline,執行時間變成1.04秒。