【问题标题】:How to access device memory which was allocated using omp_target_alloc()如何访问使用 omp_target_alloc() 分配的设备内存
【发布时间】:2018-03-01 15:50:12
【问题描述】:

我正在试验 OpenMP 和目标指令。我正在使用omp_target_alloc() 直接在设备上分配一个缓冲区,然后我尝试在target 区域内写入这个缓冲区。不幸的是,当我尝试这样做时,我遇到了分段错误。有趣的是,如果我使用指令而不是函数omp_target_alloc(),程序不会崩溃。为了让事情变得更有趣,omp_get_num_devices()omp_get_default_device() 都返回 0。这是我的代码:

#include <iostream>
#include <omp.h>

//#define USE_TARGET // Uncomment this to see the segmentation fault

int main(int argc, char** argv)
{
    const unsigned long int N = 100000;

    std::cout << "Number of devices: " << omp_get_num_devices() << std::endl;
    std::cout << "Default device: " << omp_get_default_device() << std::endl;

    // Allocate
#ifdef USE_TARGET
    float* buffer = (float*)omp_target_alloc(N*sizeof(float), 0);
#else
    float* buffer = (float*)malloc(N*sizeof(float));
#endif

    // Evaluate
#ifdef USE_TARGET
    #pragma omp target is_device_ptr(buffer)
    {
#else
    #pragma omp target data map(tofrom:buffer[0:N])
    {
#endif
        #pragma omp parallel for
        for(unsigned long int i = 0; i < N; ++i)
            buffer[i] = i;
    }

    // Cleanup
#ifdef USE_TARGET
    omp_target_free(buffer, 0);
#else
    free(buffer);
#endif

    return 0;
}

有人可以向我解释为什么上面的代码在我定义USE_TARGET 时会产生分段错误吗?我需要做什么来修复此代码?

我在呼叫omp_target_alloc() 时使用“设备0”。我假设设备 0 是 CPU 本身。对?我知道target 指令和omp_target_alloc() 有点毫无意义,但我的目标是编写一个在加速器和CPU 上运行的代码。

另外,g++ --version 给了我这个:g++ (Debian 7.3.0-5) 7.3.0

【问题讨论】:

  • 我怀疑你可以取消引用设备指针。
  • 编译您的代码时出现一堆错误,例如mkoffload: fatal error: x86_64-linux-gnu-accel-nvptx-none-gcc-7。您必须使用支持 GPU 卸载的 GCC 版本(它不在 Ubuntu 17.10 上的默认 GCC 版本中)。
  • 我用g++ -Wall omp.cpp -fopenmp -foffload=nvptx-none -fno-stack-protector 编译它。它不会对我崩溃。
  • 其实g++ omp.cpp -Wall -fopenmp -fno-stack-protector就足够了。我用 sudo nvprof ./a.out 检查了它是否会进入 GPU。但是Number of devices: 1 所以我还是有点困惑。

标签: c++ openmp


【解决方案1】:

问题在于,根据OpenMP 4.5 specification(参见第 3.5.1 节)omp_target_alloc 要求

device_num,必须大于等于0且小于omp_get_num_devices()的结果

在您的情况下,您的 GCC 安装没有看到任何非主机设备,因为 omp_get_num_devices() 返回零。这会导致omp_target_alloc 返回NULL。这就是它崩溃的原因http://coliru.stacked-crooked.com/a/00054f08e8e1322e

在我的系统上 omp_get_num_devices 返回 1 并且您的代码不会崩溃。


我刚刚了解到我可以使用 -foffload=disable 让您的代码在我的系统上崩溃

g++ -Wall -O3 -fopenmp -foffload=disable -fno-stack-protector foo.cpp

这将禁用卸载并导致omp_target_alloc 返回NULL

您可以使用以下方法修复您的代码

bool offload;
#pragma omp target defaultmap(tofrom:scalar)
offload = !omp_is_initial_device();
int device = offload ? 0: omp_get_initial_device();

如果没有非主机设备,这会将device 设置为主机设备,否则将设备设置为0。我有这个想法here。然后使用device 而不是0 用于设备参数,如下所示:

#include <iostream>
#include <omp.h>

int main(int argc, char** argv)
{
    const unsigned long int N = 100000;

    std::cout << "Number of devices: " << omp_get_num_devices() << std::endl;
    std::cout << "Default device: " << omp_get_default_device() << std::endl;

    bool offload;
    #pragma omp target defaultmap(tofrom:scalar)
    offload = !omp_is_initial_device();
    int device = offload ? 0: omp_get_initial_device();

    if (offload) {
      printf("Able to use offloading!\n");
    }

    // Allocate
    float* buffer = (float*)omp_target_alloc(N*sizeof(float), device);

    // Evaluate
    #pragma omp target is_device_ptr(buffer)
    #pragma omp parallel for
    for(unsigned long int i = 0; i < N; ++i) buffer[i] = i;

    // Cleanup
    omp_target_free(buffer, device);

    return 0;
}

http://coliru.stacked-crooked.com/a/5104446f789e2fc9

【讨论】:

    猜你喜欢
    • 2010-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-14
    • 2012-07-06
    • 2022-10-24
    相关资源
    最近更新 更多