Performance CUDA理论带宽与有效带宽

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][

我有一个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)

#定义块大小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);
        }