CUDA 矩阵加法段错误

Posted

技术标签:

【中文标题】CUDA 矩阵加法段错误【英文标题】:CUDA Matrix Addition Seg faults 【发布时间】:2012-01-15 08:09:26 【问题描述】:

我只是对我编写的 cuda 程序有疑问。它允许我输入矩阵、列和行的大小。假设我输入 ~1124 并且计算良好。但是说我在设备中计算后输入 1149 它 Seg 故障(我认为它在复制回期间出现了 seg 故障)。但是假设我输入 2000 它在设备中计算之前出现了段错误(我认为它在复制过程中出现了段错误)。我认为我的问题都与内存管理有关。如果你们能指出我正确的方向,我将不胜感激。

我更新了代码的调用方式。在新的编辑中(在底部),它包含: sumMatrix(空白矩阵,大小为 eleCount1,即整个矩阵的大小),matrixOne(第一个矩阵),matrixTwo(第二个矩阵,分配方式与 matrix1 相同) ,eleCount1(矩阵的整个大小)。 matrixOne 和 two 都是从文件中读入的。

不确定是否有人需要查看有关我的 GPU 的这些内容:

常量内存总量:65536字节 每个块的共享内存总量:49152 字节 每个块可用的寄存器总数:32768 经纱尺寸:32 每个块的最大线程数:1024 块的每个维度的最大尺寸:1024 x 1024 x 64 网格每个维度的最大尺寸:65535 x 65535 x 65535

代码是:

void addKernel(float *c, float *a, float *b)

    int i = threadIdx.x;
    int idx = blockDim.x * blockIdx.x + threadIdx.x;
    c[idx] = a[idx] + b[idx];

cudaError_t addWithCuda(float *c, float *a, float *b, size_t size)

  float *dev_a = 0;
  float *dev_b = 0;
  float *dev_c = 0;
  cudaError_t cudaStatus;
  blocksNeeded=(size/MAXTHREADS)+1;
  int threadsPerBlock = MAXTHREADS/blocksNeeded+1;
  cudaStatus = cudaMalloc((void**)&dev_c, size * sizeof(float));
  if (cudaStatus != cudaSuccess) 
      fprintf(stderr, "cudaMalloc failed!");
      goto Error;
  

  cudaStatus = cudaMalloc((void**)&dev_a, size * sizeof(float));
  if (cudaStatus != cudaSuccess) 
      fprintf(stderr, "cudaMalloc failed!");
      goto Error;
  

  cudaStatus = cudaMalloc((void**)&dev_b, size * sizeof(float));
  if (cudaStatus != cudaSuccess) 
      fprintf(stderr, "cudaMalloc failed!");
      goto Error;
  

  cudaStatus = cudaMemcpy(dev_a, a, size * sizeof(float), cudaMemcpyHostToDevice);
  if (cudaStatus != cudaSuccess) 
      fprintf(stderr, "cudaMemcpy failed!");
      goto Error;
  

  cudaStatus = cudaMemcpy(dev_b, b, size * sizeof(float), cudaMemcpyHostToDevice);
  if (cudaStatus != cudaSuccess) 
      fprintf(stderr, "cudaMemcpy failed!");
      goto Error;
  

  addKernel<<<blocksNeeded, size>>>(dev_c, dev_a, dev_b);
  cudaStatus = cudaDeviceSynchronize();

  if (cudaStatus != cudaSuccess) 
      fprintf(stderr, "cudaDeviceSynchronize returned error code %d after launching addKernel!\n", cudaStatus);
      goto Error;
  
  cudaStatus = cudaMemcpy(c, dev_c, size * sizeof(float), cudaMemcpyDeviceToHost);
  if (cudaStatus != cudaSuccess) 
      fprintf(stderr, "cudaMemcpy failed!");
      goto Error;
  

Error:
  cudaFree(dev_c);
  cudaFree(dev_a);
  cudaFree(dev_b);

  return cudaStatus;

//edit: added how the matrix are allocated
    float* matrixOne = (float*)malloc(sizeof(float)*file1size);
int matrixIndex = 0;
readFromFile(fd,byte, matrixOneWidth, matrixOneHeight,  matrixOne);

//matrixOneHeight--;
eleCount1 = matrixOneHeight*matrixOneWidth;
matrixOne= (float*)realloc(matrixOne,eleCount1*sizeof(float));
//Edit: Added how the addWithCuda is called.
cudaStatus = addWithCuda(sumMatrix, matrixOne,matrixTwo,eleCount1);
//sumMatrix is created after we know how large the matrices are. 
float sumMatrix[eleCount1];

【问题讨论】:

很可能是 a、b 或 c 的错误,但我们看不到它们的分配位置或您如何调用 addWithCuda。 我更新了它的调用方式。让我知道我是否应该提供更多内容供您查看。谢谢! file1size 是从哪里来的?我敢打赌,堆损坏与 readFromeFile(...) 函数有关。 你能把它编辑成一个可编译、可运行的复制案例吗?您所做的编辑是按照无意义的顺序进行的,并且仍然有很多未定义的东西,没有它们就不可能说出 在您的主机代码中出了什么问题,因为这是 99.9999% 确定的与CUDA无关的问题。 CUDA 编译器不允许您调用未声明为__global__ 的内核。你至少应该解决这个问题...... 【参考方案1】:

您没有在内核中测试您的计算范围。如果工作总量没有平均分配到块的大小,一些线程将尝试写入输出数组之外的索引。我建议你也将大小作为参数传递给内核并引入检查:

__global__ void addKernel(float *c, float *a, float *b, int size)

    int i = threadIdx.x;
    int idx = blockDim.x * blockIdx.x + threadIdx.x;
    if(idx < size) c[idx] = a[idx] + b[idx];

【讨论】:

这不会导致主机段错误,这是报告的内容。 他说段错误发生在随机的地方。无论如何,值得尝试一下,因为它通常是导致 cuda 程序中的段错误的原因。 抱歉,没有。 GPU 中的内存违规会生成 CUDA 运行时错误 - 通常是未指定的启动错误 - 但不会生成主机内存保护错误。如果他遇到段错误,则意味着在主机内存中做了非法的事情。 talonmies 是正确的。 CUDA 有一个轻松的内存组织,你几乎可以在 GPU 内存上做你想做的事。可能发生的最糟糕的情况是,正如前面提到的未指明的启动错误。运行 cuda-memcheck 可以检测到 Witch。随机位置上的段错误很可能是损坏的堆。 所以我的理解是这是主机问题而不是 CUDA 内存问题?我还将代码更新到我调用 >> 我需要块和需要线程的位置。我更新了代码以反映我这样做了,但这仍然重要吗?截至目前,我每个块有 1024 个线程。假设我运行一个大小为 1025 的矩阵,它将在第一个块上计算 1024 个线程,在第二个块上计算 1 个线程。我不应该这样做吗?【参考方案2】:

我看到您正在对内核中的数组 a、b 和 c 进行索引,但您没有检查以确保索引在数组范围内。因此,您正在写入不属于您的内存,从而导致随机位置出现段错误。

【讨论】:

这会导致内核启动时出现 GPU 未指定的启动失败错误,而不是主机段错误。

以上是关于CUDA 矩阵加法段错误的主要内容,如果未能解决你的问题,请参考以下文章

CUDA可分离编译+共享库->无效的设备功能/段错误

[CUDA]CUDA编程实战三——矩阵加法的实现

段错误

分析一个CUDA矩阵加法代码,使用nvprof:代码API配置文件,内核没有

分析一个CUDA矩阵加法代码,使用nvprof:代码API配置文件,内核没有

为啥我在尝试将元素添加到 vector<vector<int>>(矩阵实现)时出现段错误?