使用CUDA中的统一内存分配函数指针

时间:2017-02-17 11:32:34

标签: cuda

我试图在方便的统一内存模型下实现CUDA功能的动态绑定。这里,我们有一个包含成员的struct Parameters ,一个函数指针void(* p_func)()。

#include <cstdio>

struct Parameters {
    void (*p_func)();
};

结构由统一内存管理,我们将实际函数 func_A 分配给 p_func

__host__ __device__
void func_A() {
    printf("func_A is correctly invoked!\n");
    return;
}

当我们通过以下代码时,出现问题:如果分配1运行,即 para-> p_func = func_A ,则设备和主机功能地址实际上都是由功能地址分配的在主持人。相反,如果赋值2运行,则地址都将成为设备地址。

__global__ void assign_func_pointer(Parameters* para) {
    para->p_func = func_A;
}

__global__ void run_on_device(Parameters* para) {
    printf("run on device with address %p\n", para->p_func);
    para->p_func();
}

void run_on_host(Parameters* para) {
    printf("run on host with address %p\n", para->p_func);
    para->p_func();
}

int main(int argc, char* argv[]) {

    Parameters* para;
    cudaMallocManaged(&para, sizeof(Parameters));

    // assignment 1, if we uncomment this section, p_func points to address at host
    para->p_func = func_A;
    printf("addr@host: %p\n", para->p_func);

    // assignment 2, if we uncomment this section, p_func points to address at device
    assign_func_pointer<<<1,1>>>(para); // 
    cudaDeviceSynchronize();
    printf("addr@device: %p\n", para->p_func);

    run_on_device<<<1,1>>>(para);
    cudaDeviceSynchronize();

    run_on_host(para);

    cudaFree(para);
    return 0;
}

现在的问题是,在统一内存模型下,设备和主机上的函数指针是否可能分别指向正确的函数地址?

2 个答案:

答案 0 :(得分:1)

暂时不考虑统一内存的技术性,你的问题实际上是“一个变量可以同时具有两个不同的值吗?”对此的答案显然不是。

更详细地说:CUDA统一内存从根本上确保了当从主机和设备访问时,给定的托管分配将具有一致的值(在某些约束下)。你要求的是完全相反的,显然不支持。

答案 1 :(得分:1)

struct定义进行一些修改后,可能会出现类似的情况:

$ cat t1288.cu
#include <cstdio>

struct Parameters {
    void (*p_hfunc)();
    void (*p_dfunc)();
    __host__ __device__
    void p_func(){
      #ifdef __CUDA_ARCH__
      (*p_dfunc)();
      #else
      (*p_hfunc)();
      #endif
      }
};

__host__ __device__
void func_A() {
    printf("func_A is correctly invoked!\n");
    return;
}

__global__ void assign_func_pointer(Parameters* para) {
    para->p_dfunc = func_A;
}

__global__ void run_on_device(Parameters* para) {
    printf("run on device\n"); // with address %p\n", para->p_dfunc);
    para->p_func();
}

void run_on_host(Parameters* para) {
    printf("run on host\n"); // with address %p\n", para->p_func);
    para->p_func();
}

int main(int argc, char* argv[]) {

    Parameters* para;
    cudaMallocManaged(&para, sizeof(Parameters));

    // assignment 1, if we uncomment this section, p_func points to address at host
    para->p_hfunc = func_A;
    printf("addr@host: %p\n", para->p_hfunc);

    // assignment 2, if we uncomment this section, p_func points to address at device
    assign_func_pointer<<<1,1>>>(para); //
    cudaDeviceSynchronize();
    printf("addr@device: %p\n", para->p_dfunc);

    run_on_device<<<1,1>>>(para);
    cudaDeviceSynchronize();
    run_on_host(para);

    cudaFree(para);
    return 0;
}
$ nvcc -arch=sm_35 -o t1288 t1288.cu
$ cuda-memcheck ./t1288
========= CUDA-MEMCHECK
addr@host: 0x402add
addr@device: 0x8
run on device
func_A is correctly invoked!
run on host
func_A is correctly invoked!
========= ERROR SUMMARY: 0 errors
$

我同意另一个答案,即使使用托管内存,目前也无法使用单个数字函数指针,该指针在主机代码和设备代码中都能正常工作。