简单cuda内核添加:2432内核调用后内存非法

Posted

技术标签:

【中文标题】简单cuda内核添加:2432内核调用后内存非法【英文标题】:Simple cuda kernel add: Illegal memory after 2432 kernel calls 【发布时间】:2020-11-25 14:41:26 【问题描述】:

我构建了一个简单的 cuda 内核,对元素进行求和。每个线程将输入值添加到输出缓冲区。每个线程计算一个值。正在使用 2432 个线程(19 个块 * 128 个线程)。

输出缓冲区保持不变,输入缓冲区指针在每次内核执行后移动线程数。所以总的来说,我们有一个循环调用添加内核,直到我们计算出所有输入数据。

示例: 我所有的输入值都设置为 1。输出缓冲区大小为 2432。输入缓冲区大小为 2432 *2000。 调用 add 内核 2000 次,为每个输出字段加 1。每个字段的输出最终结果是 2000。我调用包含 for 循环的函数聚合,根据需要经常调用内核以传递完整的输入数据。 到目前为止,除非我过于频繁地调用内核,否则这是可行的。

但是,如果我调用内核 2500 次,我会收到非法内存访问 cuda 错误。

如您所见,最后一个成功内核的运行时间增加了 3 个数量级。之后我的指针失效,以下调用导致 CudaErrorIllegalAdress。

我清理了代码以获得一个最小的工作示例:

 #include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <vector>
#include <stdio.h>
#include <iostream>

using namespace std;

template <class T> __global__ void addKernel_2432(int *in, int * out)

    int i = blockIdx.x * blockDim.x  + threadIdx.x;
    out[i] = out[i] + in[i];



static int aggregate(int* array, size_t size, int* out) 

    

    size_t const vectorCount = size / 2432;
    cout << "ITERATIONS: " << vectorCount << endl;
    
    
    for (size_t i = 0; i < vectorCount-1; i++)
    

         addKernel_2432<int><<<19,128>>>(array, out);
        
        array += vectorCount;
       
    
    addKernel_2432<int> << <19, 128 >> > (array, out);
    return 1;
    

    int main()
    
  
    int* dev_in1 = 0;
    size_t vectorCount = 2432;
    int * dev_out = 0;
    size_t datacount = 2432*2500;
   
    std::vector<int> hostvec(datacount);
   
    //create input buffer, filled with 1
    std::fill(hostvec.begin(), hostvec.end(), 1);
    
    //allocate input buffer and output buffer
    cudaMalloc(&dev_in1, datacount*sizeof(int));
    cudaMalloc(&dev_out, vectorCount * sizeof(int));

    //set output buffer to 0
    cudaMemset(dev_out, 0, vectorCount * sizeof(int));

    //copy input buffer to GPU
    cudaMemcpy(dev_in1, hostvec.data(), datacount * sizeof(int), cudaMemcpyHostToDevice);
    
    //call kernel datacount / vectorcount times
    aggregate(dev_in1, datacount, dev_out);
    
    //return data to check for corectness
    cudaMemcpy(hostvec.data(), dev_out, vectorCount*sizeof(int), cudaMemcpyDeviceToHost);
   
    if (cudaSuccess != cudaMemcpy(hostvec.data(), dev_out, vectorCount * sizeof(int), cudaMemcpyDeviceToHost))
    
        cudaError err = cudaGetLastError();
        cout << " CUDA ERROR: " << cudaGetErrorString(err) << endl;
    
    else
    
        cout << "NO CUDA ERROR" << endl;
        cout << "RETURNED SUM DATA" << endl;
        for (int i = 0; i < 2432; i++)
        
            cout << hostvec[i] << " ";
        

    
   
    cudaDeviceReset();
    return 0;

如果你编译并运行它,你会得到一个错误。 变化:

size_t 数据计数 = 2432 * 2500;

size_t 数据计数 = 2432 * 2400;

它给出了正确的结果。

我正在寻找任何想法,为什么它在 2432 次内核调用后中断。

到目前为止,我在谷歌上发现了什么: 错误的目标架构集。我用的是1070ti。我的目标设置为:compute_61,sm_61 在 Visual Studio 项目属性中。这不会改变任何事情。

我错过了什么吗?在 cuda 使指针无效之前,可以调用内核的次数是否有限制?谢谢您的帮助。我使用了 windows、Visual Studio 2019 和 CUDA 运行时 11。

这是两种情况下的输出。成功与失败:

[

错误: [

【问题讨论】:

【参考方案1】:
static int aggregate(int* array, size_t size, int* out) 
    size_t const vectorCount = size / 2432;
    for (size_t i = 0; i < vectorCount-1; i++)
    
        array += vectorCount;
    

这不是vectorCount,而是您意外增加的迭代次数。 vectorCount &lt;= 2432 工作正常(但产生错误的结果),并导致上面的缓冲区溢出。

array += 2432 是你要写的。

【讨论】:

我的疏忽太糟糕了。谢谢你:)

以上是关于简单cuda内核添加:2432内核调用后内存非法的主要内容,如果未能解决你的问题,请参考以下文章

CUDA 中大小为 4 的非法写入

cuda 编 程简单CUDA程序的基本框架

具有动态共享内存的模板化 CUDA 内核

cuda 异常后的内存数据状态

使用统一内存时 CUDA 中出现意外的读取访问冲突错误

CUDA 内核的参数