我使用Intel 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版本与英特尔版本(
#pragma offload
)一样快 . 这里没什么奇怪的 . -
第二个代码块的OpenMP版本比英特尔版本慢5倍 . 但是,两者的
MIC_TIME
是相同的,但CPU_TIME
是不同的(OpenMP版本要高得多) . 这是为什么? -
我的英特尔指令是否最佳?
-
我的英特尔 - > 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();
的操作(因此我肯定知道我的软件正在运行哪个卡)?
1 回答
第二个OpenMP代码块再次分配内存 . 您应该将数据映射到设备数据环境,方法是将两个块都包含在
#pragma omp target data map(from:data[0:size])
中,或者只在第一个块之前添加#pragma omp target enter data map(alloc:data[0:size])
.AFAIK,设备(0)表示默认卡,设备(1)表示第一张卡,设备(2)表示第二张卡 .
因为liboffload does this(liboffload是gcc和icc使用的运行时库) . 但是,OpenMP标准并不保证这种行为 .
是 . 不确定标准,但icc和gcc的卸载是通过这种方式实现的 .
OpenMP 4.5仅提供
omp_is_initial_device()
功能来区分主机和加速器 . 也许有一些特定于英特尔的界面可以做到这一点 .