【问题标题】:How is variable in device memory used by external function?外部函数如何使用设备内存中的变量?
【发布时间】:2014-11-18 04:22:53
【问题描述】:

在这段代码中:

#include <iostream>

void intfun(int * variable, int value){
    #pragma acc parallel present(variable[:1]) num_gangs(1) num_workers(1)
    {
        *variable = value;
    }
}

int main(){
    int var, value = 29;

    #pragma acc enter data create(var) copyin(value)
        intfun(&var,value);
    #pragma acc exit data copyout(var) delete(value)

    std::cout << var << std::endl;
}

如何将int value 识别为位于intfun 的设备内存中?如果我在 intfun 杂注中将 present(variable[:1]) 替换为 present(variable[:1],value),我会收到以下运行时错误:

FATAL ERROR: data in PRESENT clause was not found on device 1: name=_43144_33_value
 file:/opt/pgi/linux86-64/14.9/include/CC/iostream intfun__FPii line:5
Present table dump for device[1]: NVIDIA Tesla GPU 1, compute capability 3.5
host:0x7fffc11faa28 device:0x2303f20200 size:4 presentcount:1 line:14 name:_43152_14_value
host:0x7fffc11faa34 device:0x2303f20000 size:4 presentcount:2 line:14 name:_43152_9_var

我不明白为什么指定 valuepresent 会导致上述失败。我用 NVVP 检查了valueenter data 指令中只复制一次,即它不会在intfunparallel 指令中再次复制。 OpenACC 如何发挥它的魔力?

【问题讨论】:

    标签: c++ cuda gpgpu openacc pgi


    【解决方案1】:

    您再次对自己的语法和已经向您指出的内容感到困惑。

    intfun 中的valuemain 中的value 中的copyin(value) 不同。函数调用按值传递value,这意味着它制作了它的副本。因此,将其添加到 present() 子句是没有意义的,因为它在设备上不存在。编译器必须把它拷贝进去。(当你根本不提它时,编译器会自动识别出它是需要的,并为你拷贝进去。)

    设备上存在的项目是main-范围变量valueintfun未使用。为所有变量赋予相同的名称可能无法帮助您理解这一点。

    为了证明这一点,让我们通过value 通过引用而不是通过值

    $ cat main8.cpp
    #include <iostream>
    
    void intfun(int * variable, int &value){
        #pragma acc parallel present(variable[:1],value) num_gangs(1) num_workers(1)
        {
            *variable = value;
        }
    }
    
    int main(){
        int var, value = 29;
    
        #pragma acc enter data create(var) copyin(value)
            intfun(&var,value);
        #pragma acc exit data copyout(var) delete(value)
    
        std::cout << var << std::endl;
    }
    [user2@dc12 misc]$ pgcpp -acc -Minfo main8.cpp
    intfun(int *, int &):
          5, Generating present(variable[:1])
             Generating present(value[:])
             Accelerator kernel generated
             Generating Tesla code
    main:
         14, Generating enter data copyin(value)
             Generating enter data create(var)
         17, Generating exit data delete(value)
             Generating exit data copyout(var)
    $ ./a.out
    29
    $
    

    现在主作用域变量value在设备上,编译器知道了,它会被intfun直接使用,并且把它加到present子句中是合法的和功能性的。

    【讨论】:

    • 那么我不明白为什么在我的原始示例中,如果我在main 的编译指示中省略了copyin(value)delete(value)value 不会被复制到设备中。设备从哪里检索 29 的值?它存储在主机内存中,因此必须在某个时候复制到设备内存中,对吧?
    • 我已经在我的回答中说过,如果您省略任何提及value,编译器会自动识别出内核需要value,它会自动为其生成所需的副本。只有当您指定 present 并覆盖此行为时,事情才会中断。如果您有一个新问题,即您不理解的其他问题,它基于与您的问题中显示的代码不同的代码,您可能会提出一个新问题。 main 中的 copyin(value) 与您的原始代码无关,没有它您的原始代码也可以正常工作。
    • 我已通过 NVVP 验证,在 main 中省略显式的 copyinvalue 会导致主机到设备的数据传输无法传输。因此,我对设备从哪里获得value 的值感到困惑。
    • 可以作为内核参数传递。
    • 感谢您的回答,它帮助我弄清楚了一些东西。我想提一下,当您说“已经向您指出的内容”时,它仅适用于可能从您所写内容中受益的众多人中的一个。
    猜你喜欢
    • 2022-11-27
    • 1970-01-01
    • 2014-03-01
    • 1970-01-01
    • 2016-07-11
    • 1970-01-01
    • 2023-01-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多