谁能告诉我为什么我的代码将Z数组返回为0? CUDA C

问题描述

我编写了一个CUDA C程序,通过让每个线程计算结果矩阵的一行来并行化矩阵乘法。我已将矩阵存储为行主要形式的一维数组。我似乎找不到任何地方为什么我的程序不起作用,无论是指针还是内核代码问题。帮助将不胜感激,谢谢!

代码

#include <cuda.h>
#include <time.h>
#include <stdlib.h>

__global__ void multiplyMatricesKernel(float* d_x,float* d_y,float* d_z,int m,int n,int p)
{
    int i = blockDim.x * blockIdx.x + threadIdx.x;
    if(i < m)
    {
        for(int j = 0; j < p; ++j)
        {
            d_z[i * p + j] = 0;
            for(int k = 0; k < m; ++k)
            {
                d_z[i * p + j] += d_x[i * n + k] * d_y[k * p + j];
            }
        }
    }
}

void multiplyMatrices(float* x,float* y,float* z,int p)
{

    int elements_x = m * n * sizeof(float);
    int elements_y = n * p * sizeof(float);
    int elements_z = m * p * sizeof(float);

    float* d_x;
    float* d_y;
    float* d_z;

    cudamalloc((void**) &d_x,elements_x);
    cudamalloc((void**) &d_y,elements_y);
    cudamalloc((void**) &d_z,elements_z);

    cudamemcpy(d_x,x,elements_x,cudamemcpyHostToDevice); 
    cudamemcpy(d_y,y,elements_y,cudamemcpyHostToDevice);

    multiplyMatricesKernel<<<ceil(m / 64.0),64>>>(d_x,d_y,d_z,m,n,p);

    cudamemcpy(z,elements_z,cudamemcpyDevicetoHost);

    cudaFree(d_x);
    cudaFree(d_y);
    cudaFree(d_z);
}

int main()
{
    srand(time(NULL));
    int m = rand() % 8 + 1;
    int n = rand() % 8 + 1;
    int p = rand() % 8 + 1;

    float x[m * n] = {0};
    float y[n * p] = {0};
    float z[m * p] = {0};

    printf("X =\n[");
    for(int i = 0; i < sizeof(x) / sizeof(float); ++i)
    {
        x[i] = rand() % 129 - 64;
        printf("%.1f ",x[i]);
        if((i + 1) % n == 0 && i != (sizeof(x) / sizeof(float) - 1))
        {
            printf("]\n[");
        }
        if(i == (sizeof(x) / sizeof(float) - 1))
        {
            printf("]\n\n");
        }
    }
    
    printf("Y = \n[");
    for(int i = 0; i < sizeof(y) / sizeof(float); ++i)
    {
        y[i] = rand() % 129 - 64;
        printf("%.1f ",y[i]);
        if((i + 1) % p == 0 && i != (sizeof(y) / sizeof(float) - 1))
        {
            printf("]\n[");
        }
        if(i == (sizeof(y) / sizeof(float) - 1))
        {
            printf("]\n\n");
        }
    }

    multiplyMatrices(x,z,p);

    printf("Z = \n[");
    for(int i = 0; i < sizeof(z) / sizeof(float); ++i)
    {   
        printf("%.1f ",z[i]);
        if((i + 1) % p == 0 && i != (sizeof(z) / sizeof(float) - 1))
        {
            printf("]\n[");
        }
        if(i == (sizeof(z) / sizeof(float) - 1))
        {
            printf("]\n\n");
        }
    }
    return 0;
}

解决方法

关于您的内核,将y和z二维化是一个错误

    int elements_x = m * n * sizeof(float);
    int elements_y = n * p * sizeof(float);
    int elements_z = m * p * sizeof(float);
  1. x是m x n
  2. y是m x p,不是n x p
  3. z是n x p,不是m x p 这种错误很难发现...
,

问题出在内核中的这一行。

for(int k = 0; k < m; ++k)

应该为n而不是m,因为每个元素都是n乘法的总和,如下所示:

for(int k = 0; k < n; ++k)

我还要补充一点,您可以使大小为1024的块不只是64。

multiplyMatricesKernel<<<ceil(m / 1024.0),1024>>>(d_x,d_y,d_z,m,n,p);

最后,您可以通过并行计算所有元素(不仅是行)来提高速度。

,

我设法解决了我的问题。事实证明,由于内核软件包更新后我没有重新启动Arch Linux系统,因此未加载执行GPU内存分配和GPU到CPU内存传输所需的必要nvidia模块(nvidia_uvm是模块名称)。重新启动系统可以解决问题。感谢您的所有帮助,尤其是Robert Crovella和AbdelAziz AbdelLatef指出了内核中的迭代错误。谢谢!