将 OpenMP 与 clang 一起使用
Posted
技术标签:
【中文标题】将 OpenMP 与 clang 一起使用【英文标题】:Using OpenMP with clang 【发布时间】:2016-01-26 05:14:16 【问题描述】:我在使用 clang(3.6 和 3.8 ToT)编译 OpenMP 代码时遇到问题。
我关注了这篇博文http://blog.llvm.org/2015/05/openmp-support_22.html,但问题是编译后的程序只在一个线程上执行。 我使用的是 ubuntu 15.04 x64,我同时安装了 libgomp 和 libiopmp,并使用以下命令编译我的代码:
clang test.c -o test -fopenmp -L/usr/lib/gcc/x86_64-linux-gnu/5.1.1
当我改用 gcc 时,一切正常:gcc test.c -o test -fopenmp
我也尝试运行export LD_LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/5.1.1:$LD_LIBRARY_PATH
,但没有帮助。
`
有什么建议吗?
【问题讨论】:
【参考方案1】:一些额外的 cmets:
1) 您需要使用 -fopenmp=libomp 在 clang 中启用 OpenMP。 -fopenmp 仅链接 libgomp 但忽略所有编译指示。很奇怪,我知道——很快就会在后备箱里换掉。
2) 3.7 是第一个支持 OpenMP 的版本。 3.6 没有。
3) clang 只能与 libomp 一起工作。不要以 libomp 的方式放置 libgomp(头文件或库)! clang 使用 Intel API,libgomp 不支持。 -fopenmp=libomp 应该链接正确的库。
【讨论】:
你能澄清一下,在当前的 OSX 版本下,使用 OpenMP 编译 C++-11 兼容程序的正确方法是什么,称为demo.cpp
?我的意思是完整的命令行吗?
@Andrey Bokhanko 我正在尝试使用 clang 4.0 和 CMake 3.7 以及 SET(CMAKE_CXX_FLAGS "$CMAKE_CXX_FLAGS -Wall -std=c++11 -fopenmp=libomp") find_package(OpenMP REQUIRED)
,但仍然得到“找不到 OpenMP”
clang 3.8 也有同样的问题。有人找到解决方案了吗?
使用 CMake 3.9 并查看 docs。如果您使用 OpenMP::OpenMP_CXX
目标,它应该与 Clang 一起正常工作。但是,从 High Sierra / Xcode 9.0 开始,您不能使用 Apple Clang。您必须使用 brew install llvm
并为该编译器设置环境。
Windows 和clang-cl
怎么样?【参考方案2】:
我让它在 Linux Mint 17.2 上运行。 (基本上是 Ubuntu 14.04)与:
包:libiomp-dev clang-3.8
编译标志:-fopenmp
链接器标志:-fopenmp=libiomp5
现在它编译并使用多个线程。
这里是修改后的FindOpenMP.cmake
【讨论】:
在 Mint 18.1 上,我确认它适用于 clang 3.8 和libiomp-dev
。我没有使用任何标志。
使用 clang++ 6.0 版、libomp-dev 5.0.1 版和链接器标志-fopenmp
,我的程序运行得很好。但是,当将-fopenmp
添加为 compiler 标志时,它惨遭失败。(!)【参考方案3】:
更新
构建最新的 LLVM/Clang (clang-3.8) 主干,安装 libiomp5,并指定 gomp omp 头文件的位置。请注意,libiomp5 的 Ubuntu 软件包并不完全正确,因此您需要在 /usr/lib 中添加一个从 /usr/lib/libiomp5.so 到 /usr/lib/libiomp5.so.5 的符号链接。
./clang++ -I/usr/lib/gcc/x86_64-linux-gnu/4.9/include -fopenmp=libiomp5 -o test test.cpp
我在 Linux Mint 17.2(基本上 Ubuntu 可信赖)上使用 g++-5.1 和 clang++-3.6,我看到以下代码的结果相同。
#include <iostream>
#include <omp.h>
int main()
#pragma omp parallel num_threads(4)
#pragma omp critical
std::cout << "tid = " << omp_get_thread_num() << std::endl;
在 ltrace 下运行会发现问题:
g++
$ g++ -fopenmp -o test test.cpp
$ ./test
tid = 0
tid = 3
tid = 2
tid = 1
$ ltrace ./test
__libc_start_main(0x400af6, 1, 0x7ffc937b8198, 0x400bc0 <unfinished ...>
_ZNSt8ios_base4InitC1Ev(0x6021b1, 0xffff, 0x7ffc937b81a8, 5) = 0
__cxa_atexit(0x4009f0, 0x6021b1, 0x602090, 0x7ffc937b7f70) = 0
GOMP_parallel(0x400b6d, 0, 4, 0 <unfinished ...>
GOMP_critical_start(0, 128, 0, 0) = 0
tid = 3
tid = 2
omp_get_thread_num(0x7f9fe13894a8, 1, 0, 0x493e0) = 0
_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc(0x6020a0, 0x400c44, 0, 0x493e0) = 0x6020a0
_ZNSolsEi(0x6020a0, 0, 0x7f9fe1a03988, 0x203d2064) = 0x6020a0
_ZNSolsEPFRSoS_E(0x6020a0, 0x400920, 0x7f9fe1a03988, 0 <unfinished ...>
_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_(0x6020a0, 0x400920, 0x7f9fe1a03988, 0) = 0x6020a0
<... _ZNSolsEPFRSoS_E resumed> ) = 0x6020a0
GOMP_critical_end(0x7f9fe0d2d400, 0x7f9fe0d2e9e0, 0, -1) = 0
tid = 1
tid = 0
<... GOMP_parallel resumed> ) = 0
_ZNSt8ios_base4InitD1Ev(0x6021b1, 0, 224, 0x7f9fe0d2df50) = 0x7f9fe1a08940
+++ exited (status 0) +++
叮当
$ clang++ -fopenmp -o test test.cpp
$ ./test
tid = 0
$ ltrace ./test
__libc_start_main(0x4009a0, 1, 0x7ffde4782538, 0x400a00 <unfinished ...>
_ZNSt8ios_base4InitC1Ev(0x6013f4, 0x7ffde4782538, 0x7ffde4782548, 5) = 0
__cxa_atexit(0x400830, 0x6013f4, 0x6012c8, 0x7ffde4782310) = 0
_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc(0x6012e0, 0x400a84, 0x7ffde4782548, 6) = 0x6012e0
omp_get_thread_num(0x7f3e4698c006, 0x7f3e4698c000, 0x7f3e46764988, 1024) = 0
_ZNSolsEi(0x6012e0, 0, 0x7f3e46764988, 1024) = 0x6012e0
_ZNSolsEPFRSoS_E(0x6012e0, 0x4007a0, 0x7f3e46764988, 0 <unfinished ...>
_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_(0x6012e0, 0x4007a0, 0x7f3e46764988, 0) = 0x6012e0
tid = 0
<... _ZNSolsEPFRSoS_E resumed> ) = 0x6012e0
_ZNSt8ios_base4InitD1Ev(0x6013f4, 0, 224, 0x7f3e45886f50) = 0x7f3e46769940
+++ exited (status 0) +++
您可以立即看到问题:clang++ 从不调用 GOMP_parallel,因此您总是得到一个线程。这是clang的疯狂行为。您是否尝试过构建和使用 clang 的“特殊”OpenMP version?
【讨论】:
Clang-omp 似乎已停产 - 最后一次更改是一年多前的。 谢谢,您对使用 ToT clang 并指定与 libgomp 不同的 omp 库是正确的。事实上,我也可以在我的树莓派 2 上使用它,使用自建 libomp:openmp.llvm.org。 “请注意,libiomp5 的 Ubuntu 软件包并不完全正确”似乎是错误的。如果您希望标头和链接库的能力,您应该安装libiomp-dev
包【参考方案4】:
OMP_NUM_THREADS 环境变量可能是您想要的。您也可以通过编程方式进行设置。
https://gcc.gnu.org/onlinedocs/libgomp/Environment-Variables.html
clang 也是一样。
【讨论】:
实用地设置它不起作用 - 我的程序不会以任何方式崩溃并继续在一个线程上执行。 这不起作用,因为 clang 不会为 omp pragma 发出任何代码。以上是关于将 OpenMP 与 clang 一起使用的主要内容,如果未能解决你的问题,请参考以下文章
将 OpenMP 与 Fortran 一起使用时出现内存错误,运行 FFTW
使用 clang-cl 在 Visual Studio 2019 中使用 Openmp 4/5
Mac 运行 OpenMP,“clang:错误:不支持的选项 '-fopenmp'”
启用 openmp 时出错 - “ld: library not found for -lgomp”和 Clang 错误