gpu的架構分爲streaming multiprocessors算法
每一個streaming multiprocessors(SM)又能分步驟執行不少threads,單個SM內部能同時執行的threads叫作warp。一個warp能同時操做16個單精度浮點數/8個雙精度(tesla),或者32個單精度浮點數/16個雙精度浮點數(feimi)。架構
單個SM內部有local memory和16kb大小的share memory,後者是在作計算的時候要儘可能利用好的東西。線程
根據gpu的架構,作cuda計算的時候基本上是這麼一個流程調試
先把目標矩陣分塊,8*8或者16*16等,具體多大要看所用gpu的配置ip
分塊完之後,gpu會把每一個塊調度到每一個SM上去執行。SM執行的時候按照warp大小起線程,直到運算完成。內存
資源限制:資源
每一個GPU必須有16個以上的block(對應16個SM)。而每一個SM最多隻能有8個block(對應8個flag位)。rem
算法舉例thread
拿矩陣乘法C=A*B舉例,stream
在不使用share memory的時候,每計算C中的一個值就須要2*N*N的數值。因此不使用BLOCK算法的時候,一個N*N的矩陣算一次就須要讀2*N^4的數據,起了N^2的threads。每次要讀2*N的數,這個操做數就是2N。帶寬顯然不夠。這是很是慢的。在使用share memory的時候,每計算BLOCK_SIZE*BLOCK_SIZE中的值就須要讀2*BLOCK_SIZE*BLOCK_SIZE的數據,當BLOCK_SIZE是16的時候,那就是2k,16kb的share memory能容許8個block。
當BLOCK_SIZE是32的時候,大小是8k,就是2個block。
那回顧一下剛纔的數據,咱們能知道,大小是32*32的block在16kbshare memory的時候對SM的利用率不高,(只能放2個block),而大小是16*16的block在16kb sharememory的時候對SM的利用率高(到了8個block,到頂了)。
爲何不用2個block而是8個block呢?
由於在從local memory讀到share memory的是要時間的,gpu能夠在這一個warp讀取share memory的時候切換到別的warp 讓他們也讀share memory。還記得嗎?一個warp是16個線程,SM能同時保存8個BLOCK的狀態。對於32*32這個大小的block,對於SM的調度沒有利用好,全部線程全都卡在讀取內存上了。
對於16*16的block,每次要讀2*256=512個數,這256個數的操做是256*16*2=8192個浮點操做。這時帶寬就足夠了。
對於feimi架構來講,share memory翻了3倍成了48kb
BLOCK_SIZE等於16的時候,就是24個block,BLOCK_SIZE=32的時候就是6個block。gpu讀取share memory大概要20個cycle。一個32*32的block有1024個線程,一個warp 32個線程。這樣就至少32個cycle過去了,足夠前面的線程讀完。
而對於BLOCK_SIZE等於16的時候,24個block對於一個SM來講太多了(同時只能調度8個).
ps:
在調試矩陣乘法的時候掉進坑裏了……給每一個矩陣賦值10.0*i+j,兩個矩陣互相乘。當矩陣比較小的時候100*100及如下,一點問題都沒有。大到1000*1000的開始出現計算錯誤。找了大半天都沒找出個因此然來。忽然發現結果比較長,一數位數,都快7-8位了,原來是過了單精度浮點數的有效位數了。