Performance CUDA理论带宽与有效带宽
我有一个CUDA内核,它将两个矩阵相乘,宽度和高度是我使用的块大小的倍数 我使用的Nvidia Quadro Fx 3800的理论带宽为50 Gb/s,我得到了一些奇怪的结果(有效带宽大于理论带宽) 我将在这里发布一些结果: 具有块大小2 [10] [10]*[10][10] ->BW=0,02 Gb/s[1000][1000]*[1000][1000]->BW=69,4 Gb/s 块大小为64 [1000][1000]* [1000][1000]->BW=486,4 Gb/s [10000][10000]*[10000][10000]->BW= 45072,12 Gb/s 我从英伟达最佳实践指南中获得了有效带宽公式(我简化了它,但它相当于(除非有一个愚蠢的错误))。 我认为内核很好,因为它与我读过的一些Nvidia讲座非常相似(如果不相等的话),而且还因为它工作正常(afaik)Performance CUDA理论带宽与有效带宽,performance,cuda,bandwidth,matrix-multiplication,Performance,Cuda,Bandwidth,Matrix Multiplication,我有一个CUDA内核,它将两个矩阵相乘,宽度和高度是我使用的块大小的倍数 我使用的Nvidia Quadro Fx 3800的理论带宽为50 Gb/s,我得到了一些奇怪的结果(有效带宽大于理论带宽) 我将在这里发布一些结果: 具有块大小2 [10] [10]*[10][10] ->BW=0,02 Gb/s[1000][1000]*[1000][1000]->BW=69,4 Gb/s 块大小为64 [1000][1000]* [1000][1000]->BW=486,4 Gb/s [10000][
#定义块大小64
#定义HM(10000)
#定义WM(10000)
#定义WN(10000)
#定义HN-WM
#定义WP-WN
#定义HP HM
#定义PTH-WM
#定义PTW HM
__全局无效非方形(float*M,float*N,float*P,int-uWM,int-uWN)
{
__共享浮点数MS[blocksize][blocksize];
__共享浮点数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*块大小;
int Pvalue=0;
对于(int m=0;m 对于(int k=0;k,我可以想出一些解释:
对基线代码的更改会对测量产生不利影响
无效的性能假设
未确定的微观优化
不切实际的基准
你说你的代码简化了。我会尝试使用原始基准代码,看看会发生什么。如果数字更真实,你可以将原始基准代码与简化代码进行比较,以确定差异。注意,通过使用共享内存、纹理内存等,有时可能会超过理论值带宽。这通常意味着您可能无意中使用了一些专用硬件支持的功能(如内置双线性纹理插值等)
除了Robert Harvey提到的原因外,还有供应商可能在工厂对卡进行超频(尽管GeForce比Quadros更常见)
总的来说,如果接近或超过理论带宽(内存或计算带宽),我会说你做得很好。我认为内核只是默默地失败了
在测试之后,您是否检查了任何错误
内核调用
代码有效吗
你在这方面有什么结果
时间
有效带宽是如何超过理论带宽的?我认为理论带宽是图形卡可以达到的最大带宽,还是我错了?当我说简化时,这只是一个基本数学问题(我只是加入了10^9和10^3(转换为秒)因子,没有其他).至于你指出的解释,我会再次检查代码,看看是否遗漏了一些东西。我对图形卡很在行,因为3个月前它们只用于游戏。然而,我现在的结果是200 Gb/s(比理论值高4倍),我读了很多关于矩阵乘法的讲座(我从中获取代码)他们没有得到这些带宽值。所以我可能计算错了这些值,但我真的找不到错误。我发现了问题。我没有注意每个块的最大线程数。因为我使用64 blocksize,所以我不在乎,问题是它是一个2D块,所以每个块64*64=4096个线程。这就是我想象的错误内核确实失败了:)再次感谢您在我的一个问题中的回答;)
#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);
}