CUDA程式優化心得之序列優化
相信大家看到這個題目會有所疑問,畢竟要說的CUDA程式優化,而這裡說的是序列程式的優化,我要說的是序列程式優化的能力對於並行程式優化同等的重要,因為大多數時候我們是從序列程式到並行程式,而且並行執行緒的內部依舊是序列的。
一般而言,演算法級別的優化是最有效的,但是本文的優化並不涉及,本文假設你已經有了一個可以執行並能夠得到正確結果的程式,在此基礎上進行優化。
3.1 編譯器選項
這是最簡單的一種優化方法,一般而言使用高階的優化選項總比使用低優化選項的速度要快一些,如gcc就有o0,o1,o2,o3三個優化選項,一般使用o2就已經足夠,注意有時03優化選項會更慢甚至產生錯誤的結果。
3.2 快取優化
程式訪問的資料在空間和時間上都有其區域性性,也就是說一個資料被訪問了,它附近的資料也很有可能被訪問,因此,如果我們在訪問下一個資料的時候,其已經在快取中也就是說快取命中,此時就用不著從記憶體中取資料,可加速訪問。
比如有一個二維陣列a[M][N],大家覺得下面的程式碼,那個快呢?
for(int j = 0; j < N; j++)
a[i][j] *= 3;
程式碼二、
for(int I = 0; I < M; i++)
for(int j = 0; j < M; j++)
a[j][i] *= 3;當然還有其它一些優化快取的方法,比如分塊等。快取的優化,往往對程式的效能有決定性的改變。
3.2 選用盡量小的資料型別
一般而言,小資料型別的計算速度比大資料型別要快
3.4 結構體宣告
宣告結構體時,儘量大資料型別在前,小資料型別在後。這樣會節省一些空間,你可以自己驗證一下,只要sizeof運算子就可以了。在作用CUDA時可以使用__align__(xx)來確定對齊的位元組數。
3.5 使用位運算
因為位運算要比算術運算快,因此使用位運算取代算術運算是有利的。但是要注意的是由於GPU沒有ECC,使用位運算的時候出錯的概率有點大。
如乘以一個數可以轉變成左移操作,如果乘數是常量,編譯器會自動轉換;除以2的冪可換成右移;模2的冪可換成位與。
3.6 使用複合運算子
在C中使用+=,-=,++,――等複合運算子會比較快。
3.7 展開小迴圈
展開小迴圈不但省略了每次的判斷,更使用編譯器使用向量化和並行指令成為可能。如下面的程式碼,程式碼二效率就比程式碼一高
float sum = 0.0f;
for(int I = 0; I <100000; I++){
Sum += a[I];
程式碼二
float sum = 0.0f, sum1 = 0.0f, sum2 = 0.0f, sum3 = 0.0f;
for(int I = 0; I < 25000; I +=4){
Sum1 += a[I];
Sum2 += a[I+1;
Sum3 += a[I+2];
Sum += a[I+3];
}
Sum += sum1+sum2+sum3;3.8 表示式移除
假設有一向量v長為N;下面的程式碼一就比程式碼二快
Vector vi;
Int len = vi.size();
For(int I = 0; I < len; i++)
…
程式碼二
vector vi;
…
for(int i = 0; I < vi.size(); i++)
…. 3.9 判斷式
在C中判斷式是短路的,也就是說如果現在的資訊已經能夠決定整體的結果,後面的就不用算了。如if(a && b),如果a為假,那麼if里語句就一定不能執行,故b不用再求值,這樣如果a,b中有一個是計算量相當大的,就應當將它放在後面,如果計算量差不多,就把a,b中為假概率大的放在前面。對於||可以類推。
3.10 查表
查表在圖形學非常常用。比如有一批資料,我們要知道每個資料出現的次數,我們就沒有必要每次都去統計,只要統計一次,然後記錄結果,在每次查的時候,只要查記錄的結果就行了。
其它
如宣告float時加f字尾,使用const,static,少用虛擬函式等。
最後要說的是,很多時候編譯器能夠幫助我們優化,因此,這裡說的優化方法在某些編譯器下,或者某些編譯器開啟了某些選項的情況下,並不有效。
一般而言,演算法級別的優化是最有效的,但是本文的優化並不涉及,本文假設你已經有了一個可以執行並能夠得到正確結果的程式,在此基礎上進行優化。
3.1 編譯器選項
這是最簡單的一種優化方法,一般而言使用高階的優化選項總比使用低優化選項的速度要快一些,如gcc就有o0,o1,o2,o3三個優化選項,一般使用o2就已經足夠,注意有時03優化選項會更慢甚至產生錯誤的結果。
3.2 快取優化
程式訪問的資料在空間和時間上都有其區域性性,也就是說一個資料被訪問了,它附近的資料也很有可能被訪問,因此,如果我們在訪問下一個資料的時候,其已經在快取中也就是說快取命中,此時就用不著從記憶體中取資料,可加速訪問。
比如有一個二維陣列a[M][N],大家覺得下面的程式碼,那個快呢?
CODE:
for(int I = 0; I < M; i++)for(int j = 0; j < N; j++)
a[i][j] *= 3;
程式碼二、
for(int I = 0; I < M; i++)
for(int j = 0; j < M; j++)
a[j][i] *= 3;當然還有其它一些優化快取的方法,比如分塊等。快取的優化,往往對程式的效能有決定性的改變。
3.2 選用盡量小的資料型別
一般而言,小資料型別的計算速度比大資料型別要快
3.4 結構體宣告
宣告結構體時,儘量大資料型別在前,小資料型別在後。這樣會節省一些空間,你可以自己驗證一下,只要sizeof運算子就可以了。在作用CUDA時可以使用__align__(xx)來確定對齊的位元組數。
3.5 使用位運算
因為位運算要比算術運算快,因此使用位運算取代算術運算是有利的。但是要注意的是由於GPU沒有ECC,使用位運算的時候出錯的概率有點大。
如乘以一個數可以轉變成左移操作,如果乘數是常量,編譯器會自動轉換;除以2的冪可換成右移;模2的冪可換成位與。
3.6 使用複合運算子
在C中使用+=,-=,++,――等複合運算子會比較快。
3.7 展開小迴圈
展開小迴圈不但省略了每次的判斷,更使用編譯器使用向量化和並行指令成為可能。如下面的程式碼,程式碼二效率就比程式碼一高
CODE:
程式碼一float sum = 0.0f;
for(int I = 0; I <100000; I++){
Sum += a[I];
程式碼二
float sum = 0.0f, sum1 = 0.0f, sum2 = 0.0f, sum3 = 0.0f;
for(int I = 0; I < 25000; I +=4){
Sum1 += a[I];
Sum2 += a[I+1;
Sum3 += a[I+2];
Sum += a[I+3];
}
Sum += sum1+sum2+sum3;3.8 表示式移除
假設有一向量v長為N;下面的程式碼一就比程式碼二快
CODE:
程式碼一Vector
Int len = vi.size();
For(int I = 0; I < len; i++)
…
程式碼二
vector
…
for(int i = 0; I < vi.size(); i++)
…. 3.9 判斷式
在C中判斷式是短路的,也就是說如果現在的資訊已經能夠決定整體的結果,後面的就不用算了。如if(a && b),如果a為假,那麼if里語句就一定不能執行,故b不用再求值,這樣如果a,b中有一個是計算量相當大的,就應當將它放在後面,如果計算量差不多,就把a,b中為假概率大的放在前面。對於||可以類推。
3.10 查表
查表在圖形學非常常用。比如有一批資料,我們要知道每個資料出現的次數,我們就沒有必要每次都去統計,只要統計一次,然後記錄結果,在每次查的時候,只要查記錄的結果就行了。
其它
如宣告float時加f字尾,使用const,static,少用虛擬函式等。
最後要說的是,很多時候編譯器能夠幫助我們優化,因此,這裡說的優化方法在某些編譯器下,或者某些編譯器開啟了某些選項的情況下,並不有效。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/23057064/viewspace-663263/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- CUDA程式優化心得之錯誤處理優化
- CUDA優化之指令優化優化
- CUDA優化優化
- CUDA優化之執行配置和暫存器優化優化
- 漫談CUDA優化優化
- CUDA總體優化策略優化
- 破解心得之Windows優化大師篇Windows優化
- MSSQL優化之索引優化SQL優化索引
- sql優化之邏輯優化SQL優化
- MySQL 效能優化之索引優化MySql優化索引
- MySQL 效能優化之SQL優化MySql優化
- 前端優化常用技術心得前端優化
- CUDA優化心得之測時函式設計優化函式
- CUDA 矩陣乘法終極優化指南矩陣優化
- Android優化之佈局優化Android優化
- web前端優化之圖片優化Web前端優化
- TableView 優化之資料模型優化View優化模型
- Web效能優化之圖片優化Web優化
- 最優化之無約束優化優化
- Webpack之模組化優化Web優化
- Android效能優化之佈局優化Android優化
- MySQL優化之系統變數優化MySql優化變數
- SQL Server優化之SQL語句優化SQLServer優化
- oracle優化一例之sql優化Oracle優化SQL
- 如何優化多個關鍵詞?分享多關鍵詞優化心得優化
- cuda優化之常量儲存器和紋理儲存器優化
- Android開發優化之——從程式碼角度進行優化Android優化
- MySQL調優之索引優化MySql索引優化
- 程式分析與優化 - 6 迴圈優化優化
- Android效能優化——程式碼優化(一)Android優化
- Java學習之程式碼優化Java優化
- 案例分析之JavaScript程式碼優化JavaScript優化
- 資料庫優化之臨時表優化資料庫優化
- Android效能優化篇之服務優化Android優化
- 九、Android效能優化之網路優化Android優化
- Android 效能優化之記憶體優化Android優化記憶體
- Android 效能優化(八)之網路優化Android優化
- MySQL 效能優化之快取引數優化MySql優化快取