У меня есть ядро CUDA, которое умножает две матрицы, в которых ширина и высота являются кратными размера используемого мной блока.
Используемая мной видеокарта Nvidia Quadro Fx 3800 имеет теоретическую пропускную способность 50 Гбит / с, и яя получаю некоторые странные результаты (эффективная пропускная способность больше, чем теоретическая пропускная способность)
Я опубликую здесь некоторые результаты:
с размером блока 2
[10] [10] * [10] [10] -> BW = 0,02 Гб / с [1000] [1000] * [1000] [1000] -> BW = 69,4 Гб / с
с размером блока 64
[1000] [1000] * [1000] [1000] -> BW = 486,4 Гбит / с [10000] [10000] * [10000][10000] -> BW = 45072,12 Гбит / с
Я взял формулу эффективной полосы пропускания из Руководства по оптимальным методам Nvidia (я упростил ее, но ее эквивалент (если только нет глупой ошибки)).Я думаю, что ядро прекрасно, так как оно очень похоже (если не равно) на некоторые лекции по Nvidia, которые я читаю, а также потому, что оно работает правильно (afaik).
#define blocksize 64
#define HM (10000)
#define WM (10000)
#define WN (10000)
#define HN WM
#define WP WN
#define HP HM
#define PTH WM
#define PTW HM
__global__ void nonsquare(float*M, float*N, float*P, int uWM,int uWN)
{
__shared__ float MS[blocksize][blocksize];
__shared__ float NS[blocksize][blocksize];
int tx=threadIdx.x, ty=threadIdx.y, bx=blockIdx.x, by=blockIdx.y;
int rowM=ty+by*blocksize;
int colN=tx+bx*blocksize;
int Pvalue=0;
for(int m=0; m< uWM/blocksize;m++){
MS[ty][tx]=M[rowM*uWM+(m*blocksize+tx)];
NS[ty][tx]=M[colN + uWN*(m*blocksize+ty)];
__syncthreads();
for(int k=0;k<blocksize;k++)
Pvalue+=MS[ty][k]*NS[k][tx];
P[rowM*WP+colN]=Pvalue;
}
}
int main(){
cudaEvent_t evstart, evstop;
cudaEventCreate(&evstart);
cudaEventCreate(&evstop);
float*M=(float*)malloc(sizeof(float)*HM*WM);
float*N=(float*)malloc(sizeof(float)*HN*WN);
for(int i=0;i<WM*HM;i++)
M[i]=(float)i;
for(int i=0;i<WN*HN;i++)
N[i]=(float)i;
float*P=(float*)malloc(sizeof(float)*HP*WP);
float *Md,*Nd,*Pd;
cudaMalloc((void**)&Md,HM*WM*sizeof(float));
cudaMalloc((void**)&Nd,HN*WN*sizeof(float));
cudaMalloc((void**)&Pd,HP*WP*sizeof(float));
cudaMemcpy(Md,M,HM*WM*sizeof(float),cudaMemcpyHostToDevice);
cudaMemcpy(Nd,N,HN*WN*sizeof(float),cudaMemcpyHostToDevice);
dim3 dimBlock(blocksize,blocksize);//(tile_width , tile_width);
dim3 dimGrid(WN/dimBlock.x,HM/dimBlock.y);//(width/tile_width , width/tile_witdh);
cudaEventRecord(evstart,0);
nonsquare<<<dimGrid,dimBlock>>>(Md,Nd,Pd,WM,WN);
cudaEventRecord(evstop,0);
cudaEventSynchronize(evstop);
float time;
cudaEventElapsedTime(&time,evstart,evstop);
cudaMemcpy(P,Pd,WP*HP*sizeof(float),cudaMemcpyDeviceToHost);
cudaFree(Md);
cudaFree(Nd);
cudaFree(Pd);
printf("\ntime spent:%f",time);
float Bandwidth=(HM*WM*4+WN*HN*4+HP*WP*4)/(time*1000000); /
printf("\nEffective Bandwidth:%f Gb/s\n",Bandwidth);
}
Заранее спасибо