下載請點擊:矩陣按行(列)求和CUDA並行算法
通過矩陣按行求和與按列求和兩個示例介紹CUDA並行算法設計的思路,希望對大家有所幫助。很多公司CUDA工程師面試也會考察這個題目。
1. 矩陣按行求和
矩陣A[M][N],B[M];
B[i] =A[0]+A[1]+...+A[N-1];
串行代碼:
#define A(i)(j) A[(i)*N+(j)]
void sum_row(T *A,T*B,int M,int N)
{
int i,j;
T tmp;
for(i=0; i<M; i++)
{
tmp=0;
for(j=0; j<N; j++)
tmp += A(i)(j);
B[i] = tmp;
}
}
CUDA程序設計:
每個block處理一行數據的求和,M設置爲block數目,即
dim3 dimBlock(BLOCKSIZE, 1, 1);
dim3 dimGrid(M, 1, 1);
__global__ void sum_row_kernel(T*A,T *B,int M,int N)
{
int i,j;
T tmp;
unsigned inttid =threadIdx.x;
i = blockIdx.x;
tmp=0;
T sh_B[BLOCKSIZE];
sh_B[tid] = 0;
__syncthreads();
for(j=tid; j<N; j+= BLOCKSIZE)
tmp += A(i)(j);
sh_B[tid] = tmp;
__syncthreads();
if (blockSize >= 512) {if (tid < 256) {sh_B[tid] =tmp = tmp +sh_B[tid + 256]; }__syncthreads();}
if (blockSize >= 256) {if (tid < 128) {sh_B[tid] =tmp = tmp +sh_B[tid + 128]; }__syncthreads(); }
if (blockSize >= 128) {if (tid < 64) {sh_B[tid] =tmp = tmp +sh_B[tid + 64]; }__syncthreads(); }
if (tid < 32)
{
volatile float *smem = sh_B;
if (BLOCKSIZE >= 64) { smem[tid] = tmp = tmp + smem[tid + 32]; }
if (BLOCKSIZE >= 32) { smem[tid] = tmp = tmp + smem[tid + 16]; }
if (BLOCKSIZE >= 16) { smem[tid] = tmp = tmp + smem[tid + 8]; }
if (BLOCKSIZE >= 8) { smem[tid] = tmp = tmp + smem[tid + 4]; }
if (BLOCKSIZE >= 4) { smem[tid] = tmp = tmp + smem[tid + 2]; }
if (BLOCKSIZE >= 2) { smem[tid] = tmp = tmp + smem[tid + 1]; }
}
if(tid==0)
B =sh_B[0];
}
備註:
1) 當M比較大,N比較小時,可以採用一個warp處理一行的方式;
2) 當M比較小,N比較大時,可以讓多個block處理一行的求和
以上的設計可以保證足夠多的線程數和block數,充分利用GPU資源。
2. 矩陣按列求和
矩陣A[M][N],B[N];
B[j] = A[0][j]+A[1][j]+...+A[M-1][j];
串行代碼:
#define A(i)(j) A[(i)*N+(j)]
void sum_col(T *A,T*B,int M,int N)
{
int i,j;
T tmp;
for(j=0; j<N; j++)
{
tmp=0;
for(i=0; i<M; i++)
tmp += A(i)(j);
B[j] = tmp;
}
}
CUDA程序設計:
每個線程處理一列數據的求和,N/threads設置爲block數目,即
dim3 dimBlock(BLOCKSIZE, 1, 1);
dim3 dimGrid((M+ BLOCKSIZE-1)/ BLOCKSIZE, 1, 1);
__global__ void sum_col_kernel(T*A,T *B,int M,int N)
{
int i,j;
T tmp;
j = blockIdx.x*blockDim.x+ threadIdx.x;
tmp=0;
for(i=0; i<M; i++)
tmp += A(i)(j); //可以滿足合併訪問
B[j] = tmp;
}
備註:
當M比較大,N比較小時,可以採用一個block處理一列的方式,然後對block內的值再求和