基本概念
記憶體延遲掩藏
這裡我們假設乙個warp中線程數為2(實際不一定,如tesla為32個),有兩種規約的方式,左邊這種是採取鄰接的配對方式,右邊這種採用的是交錯的配對方式。
從圖中我們可以看出,如果採用右邊這種配對方式,那麼在第一次配對完成之後我們就可以釋放出一半的warp,效能相比第一種方式有所提公升。
下面是**實現:
由於每個warp中的執行緒都是天然同步的,所以我們在設計演算法的時候最好不要讓他們產生分支(執行緒束分化)
同樣以上面的圖為例子來講述,左邊我們可以看到在第一輪配對之後就發生了執行緒束分化,也就是說對於同乙個warp中的執行緒,有的需要進行下一步的配對而有的則不需要,這樣就會產生效能的浪費。
而在右邊的圖里我們可以看到,在前面幾輪中,不會發生這樣子的執行緒束分化,同時後面的warp就可以被釋放出來進而進行其他的工作。
由於平行計算很多情況下我們是在gpu上進行的,但是這樣我們就有大量的資料傳輸要在cpu和gpu之間進行。
這時候通常情況下我們有三種方式進行優化:
組團傳輸
記憶體傳輸與計算時間重疊
global memory的延時 : 400-800 cycles
如果快取:warp的讀寫請求落到一級快取,只需一次傳輸transaction = # l1 line accessed
如果沒有快取:那麼就有一些合併的原則,比如下面這種
但是有兩種訪存模式不推薦
每個執行緒訪問很長的連續的一段空間
如果要跳著訪問,也就是訪問的步長很大,那麼就需要用到shared memory來進行優化了
shared memory 被劃分為很多個 banks
下面這個情況就沒有發生bank衝突:
而下面這個情況則發生了bank衝突:(一般情況下,有幾路的bank衝突就會讓效能下降幾倍)
實際上就是解決這個bank衝突的過程
由於矩陣轉置的過程中,讀入是按行訪問的,但是寫出卻要按列訪問,如果保持不變的話在寫入時就會發生bank衝突,這時候我們可以通過改變一下位置(+1即可)來避免這種衝突。
總結一下對資料平行計算的優化方式以g80為例,他有768個執行緒,8k個暫存器,16k個shared memory,8個block。使用shared memory時減少bank衝突
所以我們能把這麼多個執行緒分為8個執行緒塊,每塊放96個執行緒。但如果我們把這麼多個執行緒分為4個執行緒塊,每塊就要放192個執行緒。
假設每個block有256個執行緒,那麼 768 threads( 3 blocks),每個執行緒用 10 registers。而 512 threads( 2 blocks),每個執行緒用 11 registers。也就是說,如果每個執行緒要用11個暫存器,那麼剩下的執行緒就得等到下一批了,而剩下的暫存器保持空閒直到下一次被使用,這樣會造成效能的下降。我們將這種因為資源用量的增加而造成的並行性的急劇下降稱為performance cliff。
kernel啟動引數配置:
方法1:
方法2:
occupancy 佔用率這裡預設一條算術指令需要2個時鐘週期這裡第二個語句就是被插入進去的,因為第乙個語句和第三個語句的延遲比較大。對於部分指令我們可以進行替換
避免double到float的型別自動轉換,因為這個轉換時多餘的操作
將慢但是精度高的函式
func()
轉換為快但是精度低的函式__func()
對於這個for迴圈,其實有很多多餘的東西,如每次都要 ++k 和 判斷k是否小於block_size 以及 訪存時位址的運算 等等。for
(int k=
0; k
++k)
這樣就有很多多餘的操作,所以我們可以通過迴圈展開來優化它。
這樣我們就少了迴圈計數器更新、分支指令和位址運算指令。//這裡假設block_size = 16,則可以展開為
pvalue +
= ms[ty][0
]* ns[0]
[tx]
+ ms[ty][1
]* ns[1]
[tx]+.
..ms[ty][15
]* ns[15]
[tx]
;
當然,迴圈展開也可以自動實現,**如下:
但是,迴圈展開也有一些缺點,如可擴充套件性不強。#pragma unroll block_size
for(
int k=
0; k
++k)
CUDA 學習優化思路
參考 cpu中memory l3 cache傳輸頻寬為20gb s,除以64bytes line得到傳輸記錄速度約300m line s,約為300m 8 2.4g double s.一般地,浮點數操作需要兩個輸入 1個輸出,那麼loading 3個數 3 lines 的代價為 100mflops。...
CUDA分支優化
標籤 cuda 分支優化 warpsm 2015 07 16 10 24 293人閱讀收藏 舉報 cuda 26 在cuda中,分支會極大的減弱效能,因為 沒有分支 因此只能讓束內線程在每個分支上都執行一遍,當然如果某個分支沒有執行緒執行,就可以忽略,因此要減少分支的數目。可以簡單的說 1.同乙個w...
cuda程式設計學習3 VectorSum
這個程式是把兩個向量相加 add dev a,dev b,dev c 第乙個引數n代表block的數量,第二個引數1代表每個block中thread的數量 tid blockidx.x blockidx是乙個內建變數,blockidx.x代表這是乙個2維索引 下面對這個程式做幾個變化,並指出相應的程...