0

我使用英特尔 C++ 编译器 17.0.01,我有两个代码块。

第一个代码块在 Xeon Phi 上分配内存,如下所示:

#pragma offload target(mic:1) nocopy(data[0:size]: alloc_if(1) free_if(0))

第二个块评估上述内存并将其复制回主机:

#pragma offload target(mic:1) out(data[0:size]: alloc_if(0) free_if(0))

这段代码运行得很好,但#pragma offload 只是英特尔编译器的一部分(我认为)。所以,我想将其转换为 OpenMP。

这就是我将第一个块转换为 OpenMP 的方式:

#pragma omp target device(1) map(alloc:data[0:size])

这就是我将第二个块转换为 OpenMP 的方式:

#pragma omp target device(1) map(from:data[0:size])

此外,我使用export OFFLOAD_REPORT=2它是为了更好地了解运行时发生的情况。

这是我的问题/问题:

  • 第一个代码块的 OpenMP 版本与 Intel 版本一样快 ( #pragma offload)。这里没有什么奇怪的。
  • 第二个代码块的 OpenMP 版本比 Intel 版本慢 5 倍。但是,MIC_TIME两者相同,但CPU_TIME不同(OpenMP 版本要高得多)。这是为什么?
  • 我的英特尔指令是最优的吗?
  • 我的 Intel -> OpenMP 翻译是否正确且最佳?

这里还有一些其他的,有点不同的问题:

  • 在测试机器上,我有两张 Intel Phi 卡。因为我想使用第二个,所以我这样做:#pragma omp target device(1).... 那是对的吗?
  • 如果我这样做#pragma omp target device(5)...,代码仍然有效!它运行在一张 Phi 卡(而不是 CPU)上,因为性能相似。这是为什么?
  • 我还在没有 Xeon Phi 的机器上尝试了我的软件(OpenMP 版本),它在 CPU 上运行得很好!这是有保证的吗?当您的机器上没有加速器时,target device(1)会被忽略吗?
  • 是否可以在 OpenMP 卸载区域内执行类似操作std::cout << print_phi_card_name_or_uid();(因此我可以确定我的软件在哪张卡上运行)?
4

1 回答 1

1

第二个 OpenMP 代码块再次分配内存。您应该通过将两个块都包含在 中来将数据映射到设备数据环境#pragma omp target data map(from:data[0:size]),或者只是#pragma omp target enter data map(alloc:data[0:size])在第一个块之前添加。

在测试机器上,我有两张 Intel Phi 卡。因为我想使用第二个,所以我这样做:#pragma omp target device(1).... 对吗?

AFAIK,设备(0)表示默认卡,设备(1)表示第一张卡,设备(2)是第二张卡。

如果我执行 #pragma omp target device(5)... 代码仍然有效!它运行在一张 Phi 卡(而不是 CPU)上,因为性能相似。这是为什么?

因为 liboffload是这样做的(liboffload 是 gcc 和 icc 都使用的运行时库)。然而,OpenMP 标准不保证这种行为。

我还在没有 Xeon Phi 的机器上尝试了我的软件(OpenMP 版本),它在 CPU 上运行得很好!这是有保证的吗?当您的机器上没有加速器时,目标设备(1)会被忽略吗?

是的。不确定标准,但是以这种方式实现了 icc 和 gcc 中的卸载。

是否可以做类似 std::cout << print_phi_card_name_or_uid(); 在 OpenMP 卸载区域内(所以我可以确定我的软件在哪张卡上运行)?

OpenMP 4.5 仅提供omp_is_initial_device()区分主机和加速器的功能。也许有一些英特尔特定的接口可以做到这一点。

于 2017-05-24T19:21:02.690 回答