快取與效率

2021-04-20 03:18:52 字數 2797 閱讀 5318

在cpu多核的今天,考慮如何利用多核的問題已經擺在了每個程式設計師的面前。對乙個稍微有點經驗的程式設計師而言,omp無疑是最快的捷徑,並且收效非常高,基本能提公升1.8倍的效率(雙核cpu)。

耐著性子把omp的介紹文章看完了,在3d應用中實踐起來,收效很明顯,骨骼計算,**計算,頂點座標/紋理座標/法線插值上用得得心應手,一時興起,把關鍵部分的計算用sse指令重新寫過後,總體得到了大約4倍的效率提公升。

在這個過程中,發現了一些問題:

一、使用sse指令寫了乙個處理乙個資料的函式,同時也寫了乙個處理多個資料的函式。從通常的單執行緒思維來看,顯然減少函式呼叫開銷可以提公升效率。因此,處理一段資料採用了以下寫法:

//num_threads :啟動的omp執行緒個數

int num_threads = omp_get_max_threads();

//spt : 每個執行緒分配到的資料

int spt = ucount / num_threads;

if(spt > 0)

}for(int i=num_threads * spt; isse_processdata(buff[i]);

測試結果差點沒讓我下巴脫臼,結果表明,這樣寫法的執行結果還不如單執行緒快。單執行緒**如下:

for(int i=0; i

而簡單的在單執行緒**前面加上omp指令,居然有了0.9倍左右(amd 3800+,雙核cpu)的效率提公升:

#pragma omp parallel for

for(int i=0; i

非常的不可思議。

本人不是特別追根問底的人,一切以實踐出發,同時記下一條規則:omp優化規則很好了,一些貌似聰明的小技巧不見得好使,老老實實用omp吧。在這個思路指引下,接下來的其他優化都很順暢,令人非常興奮,又開始了給老婆講解omp,mpi如何跟造鞋掛上關係的。加上白天喝了幾包咖啡,開始半夜半夜失眠了。

俗話說,常見江湖漂,哪能不挨刀,常在河邊走,哪有不濕鞋?在做射線與模型逐三角面相交的時候,omp又給我上了一課.按照之前的經驗,這回的**寫得很保守很規矩:

單執行緒**: 

float fmaxdistance = flt_max;

int n******** = -1;

for(int i=0;i

}多執行緒**,典型的omp求最小值的翻版: 

int ntt[2] = ;

float f[2] = ;

#pragma omp parallel for num_threads(2)

for(int i=0;i

}if(f[0] < f[1])

else

很高興的進行測試(本人單元測試習慣不錯),結果再次差點沒讓我下巴脫臼----效率有了大約1/8的下降!

而後反覆折騰,修改,是不是omp做了不應該的同步啦,變數是否合理的shared,private,或firstprivate了,查資料,上網,讀msdn.....十七般武藝都用盡了,基本處於放棄的邊沿的,終於想到使用最後的乙個**: asm.由於是測試效率,之前的所有編譯和測試都是在release版下進行的,彙編裡加入了omp的**後,更難於看懂,且很多變數都不知道值,這次更改為debug進行效率測試.很快,結果水落石出:

第一種情況

#pragma omp parallel for

for(int i=0; i

omp優化結果是

//thread 0:

for(int i=0; i

//thread 1:

for(int i=4; i

而第二種情況下,omp優化結果是:

//thread 0:

for(int i=0; i

//thread 1:

for(int i=ucount/2; i

顯然,差別在迴圈的方式上.至於為什麼omp的編譯結果有這種差別,其規則是什麼,現在是不得而知----顯然,跟上下文或使用指標的方式有關.要是哪位仁兄知道這些細節,煩請告知.

報著將信將疑的態度,將第二種情況的**修改如下:

int ntt[2] = ;

float f[2] = ;

#pragma omp parallel sections num_threads(2) }}

#pragma omp section }}

}if(f[0] < f[1])

else

(補充:上述**不是最終**,最終**是根據當前cpu核數目分組迴圈計算的.**不在手邊,且不複雜,就不呈上了)

也就是說,兩個執行緒,執行緒0處理奇數的三角面,執行緒1處理偶數個數的三角面。

測試結果表明,效率終於提公升了0.8倍多。

「嘿嘿嘿,哥們,你好歹已經過了而立之年了,怎麼寫文章還文不對題呢?」——讀者咆哮道,並且四處尋覓著鵝卵石或臭雞蛋。

「wusa...wusa...安靜,安靜,我一直都掛惦著標題呢!」----我舉起了早就準備好的雨傘。

why?why?why?

有一點在之前的文中我沒有提到:為了照顧gpu快取優化,我的所有模型資料都是針對geforce2快取16個頂點進行過快取優化的,也就是說,在cpu處理這些頂點的時候,同樣能享受到這樣的好處。在兩個執行緒中,同時處理兩個三角面,如果他們處理速度相同,則他們基本都在處理臨近的三角面,而這些臨近的三角面,無論是索引,還是頂點,都處於cpu的快取中的概率會相當大,快取實效帶來的效率下降比較小。而將資料分成兩段處理,則cpu需要同時快取四段記憶體(兩處索引,兩處頂點),快取不夠大的情況下(amd的u本來快取就小),快取實效帶來的效率下降就直接抵消了多執行緒的效率提公升,甚至變得更慢了!

為了驗證這點,我在載入模型的時候,將三角面索引隨機進行了替換,以打亂cpu快取頂點資料,再次測試表明,效率有了可觀的下降。

我沒有文不對題!

PHP檔案快取效率測試

php檔案快取內容儲存格式主要有三種 1.變數 var export 格式化成php正常的賦值書寫格式,用的時候直接include檔案 2.變數 serialize 序列化之後儲存,用的時候反序列化 3,變數 json encode格式化之後儲存,用的時候json decode 一直以來,我都以為第...

PHP檔案快取效率測試

php檔案快取內容儲存格式主要有三種 1.變數 var export 格式化成php正常的賦值書寫格式,用的時候直接include檔案 2.變數 serialize 序列化之後儲存,用的時候反序列化 3,變數 json encode格式化之後儲存,用的時候json decode 一直以來,我都以為第...

PHP檔案快取效率測試(一)

php檔案快取內容儲存格式主要有三種 1.變數 var export 格式化成php正常的賦值書寫格式,用的時候直接include檔案 2.變數 serialize 序列化之後儲存,用的時候反序列化 3,變數 json encode格式化之後儲存,用的時候json decode 一直以來,我都以為第...