【问题标题】:CUDA kernel pointer arguments become NULLCUDA 内核指针参数变为 NULL
【发布时间】:2015-11-22 21:41:35
【问题描述】:

我的 CUDA 内核需要很多数组,这些数组需要作为指向内核的指针传递。问题是在内核启动之前,所有的指针都有有效的地址,而且cudaMalloccudaMemcpy调用总是返回cudaSuccess,但是一旦内核启动,所有这些参数都变为空!

我对正在发生的事情一无所知。这是我使用cuda-gdb 运行代码时得到的结果

CUDA Exception: Device Illegal Address
The exception was triggered in device 0.

Program received signal CUDA_EXCEPTION_10, Device Illegal Address.
[Switching focus to CUDA kernel 0, grid 1, block (0,0,0), thread (64,0,0), device 0, sm 1, warp 2, lane 0]
0x00000000062a3dd8 in compute_data_and_match_kernel<<<(2,1,1),(512,1,1)>>> (a11=0x0, a12=0x0, a22=0x0, b1=0x0, b2=0x0, mask=0x0, wx=0x0, wy=0x0, du=0x0, dv=0x0, uu=0x0, 
    vv=0x0, Ix_c1=0x0, Ix_c2=0x0, Ix_c3=0x0, Iy_c1=0x0, Iy_c2=0x0, Iy_c3=0x0, Iz_c1=0x0, Iz_c2=0x0, Iz_c3=0x0, Ixx_c1=0x0, Ixx_c2=0x0, Ixx_c3=0x0, Ixy_c1=0x0, Ixy_c2=0x0, 
    Ixy_c3=0x0, Iyy_c1=0x0, Iyy_c2=0x0, Iyy_c3=0x0, Ixz_c1=0x0, Ixz_c2=0x0, Ixz_c3=0x0, Iyz_c1=0x0, Iyz_c2=0x0, Iyz_c3=0x0, desc_weight=0x0, desc_flow_x=0x0, 
    desc_flow_y=0x0, half_delta_over3=0.0833333358, half_beta=0, half_gamma_over3=0.833333313, width=59, height=26, stride=60) at opticalflow_aux.cu:441
441         ix_c1_val = Ix_c1[index]; iy_c1_val = Iy_c1[index]; iz_c1_val = Iz_c1[index];
(cuda-gdb) 

有什么很明显的东西我错过了。 提前致谢。

编辑 1: 正如 Gilles 所建议的,我正在尝试将主机指针和数据复制到结构中,然后复制到设备上。为了简单起见(MCVE),我在 struct 中只使用了一个指针:

#include <cuda.h>
#include <stdio.h>

typedef struct test {
    float *ptr;
} test_t;

__global__ void test_kernel(test_t *s) {
    s->ptr[0] = s->ptr[1] = s->ptr[2] = s->ptr[3] = s->ptr[4] = 100;
    s->ptr[5] = s->ptr[6] = s->ptr[7] = s->ptr[8] = s->ptr[9] = 100;
}

int main() {

    float arr[] = {0,1,2,3,4,5,6,7,8,9};

    test_t *h_struct;
    h_struct = (test_t *)malloc(sizeof(test_t));
    h_struct->ptr = arr;

    test_t *d_struct;
    float *d_data;
    cudaMalloc((void **)&d_struct, sizeof(test_t));
    cudaMalloc((void **)&d_data, sizeof(float)*10);

    // Copy the data from host to device
    cudaMemcpy(d_data, h_struct->ptr, sizeof(float)*10,   cudaMemcpyHostToDevice);
    // Point the host struct ptr to device memory
    h_struct->ptr = d_data;
    // copy the host struct to device
    cudaMemcpy(d_struct, h_struct, sizeof(test_t), cudaMemcpyHostToDevice);


    // Kernel Launch
    test_kernel<<<1,1>>>(d_struct);
    // copy the device array to host
    cudaMemcpy(h_struct->ptr, d_data, sizeof(float)*10, cudaMemcpyDeviceToHost);

    cudaFree(d_data);
    cudaFree(d_struct);

    // Verifying if all the values have been set to 100
    int i;
    for(i=0 ; i<10 ; i++)
        printf("%f\t", h_struct->ptr[i]);

    return 0;
}

当我检查d_struct-&gt;ptr 的值时,就在内核启动之前它显示0x0。 (我在调试模式下使用 nsight 检查了这些值)

【问题讨论】:

  • 如果需要,我可以用实际代码更新我的问题,因为内核和内核启动的代码非常庞大。
  • 是的,请务必提供minimal reproducible example,因此请先找到一个能够重现您的问题的最小示例,然后将其发布在此处
  • 您的新示例在内核运行后完全破坏了主机端数据处理。 h_struct-&gt;ptr 不是有效的主机指针,您不能将其用作设备中的目标来托管内存传输或尝试打印其值。如果我修改您的代码,以便将 arr 用作内核之后的目标,并将其打印出来,它会按预期工作并打印出 100。大概您从未真正运行过它,因为如果您这样做了,您将得到一个主机段错误
  • @talonmies 感谢您指出这一点。它就像你指出的那样工作。现在我将把它扩展到多个参数来处理我之前的场景。但是在内核启动之前d_struct-&gt;ptr 仍然是0x0

标签: cuda cuda-gdb


【解决方案1】:

不确定是否是问题所在,但我认为将参数传递给内核的堆栈大小是有限的。您可能需要创建一个存储您的参数的结构,将其复制到设备,并且只将指向它的指针作为参数传递给您的内核。然后,在内核内部,您从结构中检索您的参数...


编辑:添加了已提交代码的更正版本。 这对我有用,并且体现了我所描述的原则。

#include <cuda.h>
#include <stdio.h>

typedef struct test {
    float *ptr;
} test_t;

__global__ void test_kernel(test_t *s) {
    s->ptr[0] = s->ptr[1] = s->ptr[2] = s->ptr[3] = s->ptr[4] = 100;
    s->ptr[5] = s->ptr[6] = s->ptr[7] = s->ptr[8] = s->ptr[9] = 100;
}

int main() {

    float arr[] = {0,1,2,3,4,5,6,7,8,9};

    test_t *h_struct;
    h_struct = (test_t *)malloc(sizeof(test_t));

    test_t *d_struct;
    float *d_data;
    cudaMalloc((void **)&d_struct, sizeof(test_t));
    cudaMalloc((void **)&d_data, sizeof(float)*10);

    // Copy the data from host to device
    cudaMemcpy(d_data, arr, sizeof(float)*10, cudaMemcpyHostToDevice);
    // Point the host struct ptr to device memory
    h_struct->ptr = d_data;
    // copy the host struct to device
    cudaMemcpy(d_struct, h_struct, sizeof(test_t), cudaMemcpyHostToDevice);

    // Kernel Launch
    test_kernel<<<1,1>>>(d_struct);
    // copy the device array to host
    cudaMemcpy(arr, d_data, sizeof(float)*10, cudaMemcpyDeviceToHost);

    cudaFree(d_data);
    cudaFree(d_struct);

    // Verifying if all the values have been set to 100
    int i;
    for(i=0 ; i<10 ; i++)
        printf("%f\t", arr[i]);

    return 0;
}

【讨论】:

  • 查了一下发现这个:devtalk.nvidia.com/default/topic/458705/… 显然限制是256B
  • @Giles 是的!连我都在看这个。让我修改我的代码并检查一下。
  • 顺便说一句,不需要像我指出的线程中描述的那样初始化 kenel,只需定义一个包含所有参数的结构(到包含文件中),在主机端填充它,分配一个指针它在设备端,将相应的数据从主机复制到设备并将指针作为内核的参数传递。这应该只需要添加一个额外的d_arg-&gt; 来从内核内部访问您的参数。
  • 我试过这样做,但问题是,在设备端分配的结构中,当我尝试将此结构内的任何指针设置为指向设备端内存时,它总是得到集合为 NULL。
  • 是的,这行不通。您应该在主机端放入结构中的是设备端的指针,即您的d_data 指针,因为这是您在设备端需要的...然后,您将结构从主机复制到像你一样的设备。这有意义吗?
猜你喜欢
  • 2015-07-12
  • 2014-12-31
  • 2014-02-01
  • 1970-01-01
  • 2014-07-21
  • 1970-01-01
  • 2015-01-16
  • 2014-11-26
  • 2014-01-02
相关资源
最近更新 更多