优化X_转置*X CUDA内核的技巧

优化X_转置*X CUDA内核的技巧,cuda,Cuda,我正在编写我的第一个CUDA应用程序,并且正在自己编写所有内核以供练习 在一部分中,我只是简单地计算X_转置*X 我一直在使用cudaMallocPitch和cudaMemcpy2D,我首先在设备上为X和X_transpose*X分配足够的空间。我将X复制到设备上,我的内核接受两个输入,X矩阵,然后是写入X_transpose*X结果的空间 使用分析器,内核最初需要104秒才能在大小为5000x6000的矩阵上执行。我在主机上用零填充矩阵,使其为块大小的倍数,以避免检查内核中矩阵的边界。我使用3

我正在编写我的第一个CUDA应用程序,并且正在自己编写所有内核以供练习

在一部分中,我只是简单地计算X_转置*X

我一直在使用cudaMallocPitch和cudaMemcpy2D,我首先在设备上为X和X_transpose*X分配足够的空间。我将X复制到设备上,我的内核接受两个输入,X矩阵,然后是写入X_transpose*X结果的空间

使用分析器,内核最初需要104秒才能在大小为5000x6000的矩阵上执行。我在主机上用零填充矩阵,使其为块大小的倍数,以避免检查内核中矩阵的边界。我使用32乘32的块大小

我做了一些改变,试图最大化对全局内存的联合读/写,这似乎有很大帮助。使用VisualProfiler评测代码的发布版本,内核现在需要4.27秒来执行

我还没有对我的matlab执行进行精确的计时(只是操作X'*X;),但似乎大约是3秒。我希望使用CUDA可以获得比matlab更好的加速比

nvidia VisualProfiler无法发现我的内核有任何问题,我希望这里的社区能给我一些建议,告诉我如何让它运行得更快

内核代码:

__global__ void XTXKernel(Matrix X, Matrix XTX) {

//find location in output matrix
int blockRow = blockIdx.y;
int blockCol = blockIdx.x;

int row = threadIdx.y;
int col = threadIdx.x;

Matrix XTXsub = GetSubMatrix(XTX, blockRow, blockCol);
float Cvalue = 0;

for(int m = 0; m < (X.paddedHeight / BLOCK_SIZE); ++m) {

    //Get sub-matrix
    Matrix Xsub = GetSubMatrix(X, m, blockCol);
    Matrix XTsub = GetSubMatrix(X, m, blockRow);

    __shared__ float Xs[BLOCK_SIZE][BLOCK_SIZE];
    __shared__ float XTs[BLOCK_SIZE][BLOCK_SIZE];

    //Xs[row][col] = GetElement(Xsub, row, col);
    //XTs[row][col] = GetElement(XTsub, col, row);
    Xs[row][col] = *(float*)((char*)Xsub.data + row*Xsub.pitch) + col;
    XTs[col][row] = *(float*)((char*)XTsub.data + row*XTsub.pitch) + col;

    __syncthreads();

    for(int e = 0; e < BLOCK_SIZE; ++e)
        Cvalue += Xs[e][row] * XTs[col][e];

    __syncthreads();
}

//write the result to the XTX matrix
//SetElement(XTXsub, row, col, Cvalue);
((float *)((char*)XTXsub.data + row*XTX.pitch) + col)[0] = Cvalue;
}
提前感谢您的建议

编辑:我忘了提到,我正在开普勒卡GTX6704GB上运行

  • 较小的块大小(如16x16或8x8)可能更快。此外,对于特定的矩阵大小,演示更大的块/共享内存的非方形大小可能更快
  • 对于共享内存分配,使用
    [BLOCK\u SIZE][BLOCK\u SIZE+1]
    在前导维度上添加一个dumy元素,以避免银行冲突
  • 使用
    #pragma unroll
  • 另一方面,对于足够大的A'*A,您可能不会比matlab GPU代码快很多。因为matlab的性能瓶颈是调用开销,而不是内核性能

    cuBLAS例程culas_gemm()可能具有最高的矩阵乘法性能。你可以把你的和它相比

    例程
    magma\u gemm()
    在某些情况下比cuBLAS具有更高的性能。这是一个开源项目。你也可以从他们的代码中得到一些想法

    struct Matrix {
    matrixLocation location;
    unsigned int width;             //width of matrix(# cols)
    unsigned int height;            //height of matrix(# rows)
    unsigned int paddedWidth;       //zero padded width
    unsigned int paddedHeight;      //zero padded height
    float* data;                    //pointer to linear array of data elements
    size_t pitch;               //pitch in bytes, the paddedHeight*sizeof(float) for host, device determines own pitch
    size_t size;                //total number of elements in the matrix
    size_t paddedSize;          //total number of elements counting zero padding
    };