【问题标题】:How does the OpenACC copyin directive work?OpenACC 复制指令如何工作?
【发布时间】:2022-01-20 15:18:43
【问题描述】:

根据 OpenACC 文档:

copyin - 为设备上列出的变量创建空间,通过复制初始化变量 数据到设备的区域开始,并释放设备上的空间时 无需将数据复制回主机即可完成。

我已经创建了一个测试示例程序

int main(int argc, char** argv)
{
    int teste[] = { -15 };


    #pragma acc data copyin(teste[0:1])
    {

        #pragma acc parallel loop
        for (int p = 0; p < 5000; p++) {
            teste[0] = p;
        }
    }
    printf("%d", teste[0]);
    return 0;
}

根据文档,程序应该输出-15,因为数据在设备上被修改并且结果不会被复制回主机。但是一旦我编译并运行这段代码,输出是4999

我的编译器是gcc (tdm64-1) 10.3.0,我在一台具有独立设备和主机内存的计算机上运行程序

我想知道为什么这不起作用,我可以做些什么来防止从设备复制回主机。

这是在 windows 上使用 git bash 运行的程序:

$ cat test.c && echo "" &&gcc -fopenacc test.c && ./a.exe

#include <stdio.h>

int main(int argc, char** argv)
{
    int teste[] = { -15 };


    #pragma acc data copyin(teste[0:1])
    {

        #pragma acc parallel loop
        for (int p = 0; p < 5000; p++) {
            teste[0] = p;
        }
    }
    printf("%d\n", teste[0]);
    return 0;
}
4999

我还可以访问 Linux 机器,即使使用 nvc 也无法获得正确的结果

cat test.c && echo "" && /opt/nvidia/hpc_sdk/Linux_x86_64/2021/compilers/bin/nvc -acc -Minfo=accel test.c && ./a.out
#include <stdio.h>

int main(int argc, char** argv)
{
    int teste[] = { -15 };


    #pragma acc data copyin(teste[0:1])
    {

        #pragma acc parallel loop
        for (int p = 0; p < 5000; p++) {
            teste[0] = p;
        }
    }
    printf("%d\n", teste[0]);
    return 0;
}

main:
    9, Generating copyin(teste[:]) [if not already present]
       Generating NVIDIA GPU code
       12, #pragma acc loop gang, vector(128) /* blockIdx.x threadIdx.x */
4999

【问题讨论】:

    标签: c memory gpu openacc


    【解决方案1】:

    程序应该打印 -15,因为主机上的值没有改变。因此,这要么是 gcc 中的错误,要么您实际上并未启用 OpenACC。你使用什么编译器标志?

    这是针对 NVIDIA A100 使用 nvc 的输出:

    % cat test.c
    #include <stdio.h>
    
    int main(int argc, char** argv)
    {
        int teste[] = { -15 };
    
    
        #pragma acc data copyin(teste[0:1])
        {
    
            #pragma acc parallel loop
            for (int p = 0; p < 5000; p++) {
                teste[0] = p;
            }
        }
        printf("%d\n", teste[0]);
        return 0;
    }
    % nvc test.c -acc -Minfo=accel ; a.out
    main:
         10, Generating copyin(teste[:]) [if not already present]
             Generating NVIDIA GPU code
             13, #pragma acc loop gang, vector(128) /* blockIdx.x threadIdx.x */
    -15
    

    【讨论】:

    • 在 Windows 上运行,您通过 git bash 使用的相同命令(但使用 gcc 而不是 nvc)给了我相同的结果。我编辑了问题以显示输出
    • 奇怪,它实际上并没有在 GPU 上运行(我假设您确实安装了 NVIDIA GPU?)。您可以使用 nvc 构建设置环境变量“NV_ACC_NOTIFY=3”吗?这将使 NV OpenACC 打印内核启动和运行中的数据移动。我们可以看看它是否真的在 GPU 上运行。如果它没有显示任何内容,则它在 CPU 上运行。在这种情况下,请发布运行“nvaccelinfo”或“nvidia-smi”的输出,以便我知道您正在使用什么设备和 CUDA 驱动程序版本。
    • 请注意,在以共享内存作为主机的目标上运行时(即针对多核 CPU 或使用 CUDA 统一内存),数据区域基本上会被忽略,因此会出现 4999 答案。我知道这只是理解结构的一个例子,但总的来说,不要依赖于不完整的记忆。
    • 在我尝试使用 NV_ACC_NOTIFY=3 的 linux 机器上并没有显示任何内容,我尝试同时运行 nvaccelinfonvidia-smi 但没有找到这些命令,系统管理员告诉我这台机器有访问 GPU,但我必须与系统管理员核实这台机器是否真的有 Nvidia GPU,以及运行 linux 的虚拟机是否可以访问它。
    • 同时windows电脑有一个GTX1080,使用GOMP_DEBUG=1(应该和NV_ACC_NOTIFY=3一样)返回:```$GOMP_DEBUG=1; ./a.exe 4999 GOACC_data_start:mapnum = 1,hostaddrs = 0000003baefff898,大小= 00007ff7cc682010,种= 00007ff7cc682018 GOACC_parallel_keyed:mapnum = 1,hostaddrs = 0000003baefff890,大小= 00007ff7cc682020,种= 00007ff7cc682028 GOACC_data_end:恢复映射GOACC_data_end:映射恢复`` `
    猜你喜欢
    • 2017-05-30
    • 2013-08-22
    • 2015-11-04
    • 1970-01-01
    • 2021-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-15
    相关资源
    最近更新 更多