将 F2Py 与 OpenACC 一起使用会在 Python 中出现导入错误
Using F2Py with OpenACC gives import error in Python
我正在编写一个简单的测试代码,看看如何包装包含 openacc 区域的 Fortran 代码并从 python 调用。这是代码。
module test
use iso_c_binding, only: sp => C_FLOAT, dp => C_DOUBLE, i8 => C_INT
implicit none
contains
subroutine add (a, b, n, c)
integer(kind=i8), intent(in) :: n
real(kind=dp), intent(in) :: a(n)
real(kind=dp), intent(in) :: b(n)
real(kind=dp), intent(out) :: c(n)
integer(kind=i8) :: i
!$acc enter data create(a, b, c)
do i = 1, n
c(i) = a(i) + b(i)
end do
!$acc exit data delete(a, b, c)
end subroutine add
subroutine mult (a, b, c)
real(kind=dp), intent(in) :: a
real(kind=dp), intent(in) :: b
real(kind=dp), intent(out) :: c
c = a * b
end subroutine mult
end module test
现在,如果我不使用 openacc,它工作正常,我可以使用来自 python 的 add 和 mult。但是在我放入 openacc 区域之后,f2py 编译它很好,但是当我尝试导入到 python 时,我得到以下错误
ImportError: /home/vikram/Experiments/Experiments/fortran_python/hello.cpython-35m-x86_64-linux-gnu.so: undefined symbol: GOACC_enter_exit_data
这好像告诉我Python需要知道如何找到GOACC_enter_exit_data,我看到GOACC_enter_exit_data在libgomp.so.1。我如何告诉 python 它的路径。
我决定看看我直接编译link生成的可执行文件是什么。这样做
ldd a.out
给我
linux-vdso.so.1 => (0x00007ffed24a0000)
libcublas.so.7.5 => /usr/local/cuda/lib64/libcublas.so.7.5 (0x00007f04c2d45000)
libcudart.so.7.5 => /usr/local/cuda/lib64/libcudart.so.7.5 (0x00007f04c2ae7000)
libgfortran.so.3 => /home//Experiments/Nvidia/OpenACC/OLCFHack15/gcc6/install/lib64/libgfortran.so.3 (0x00007f04c27c1000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f04c24bb000)
libgomp.so.1 => /home//Experiments/Nvidia/OpenACC/OLCFHack15/gcc6/install/lib64/libgomp.so.1 (0x00007f04c228d000)
libgcc_s.so.1 => /home//Experiments/Nvidia/OpenACC/OLCFHack15/gcc6/install/lib64/libgcc_s.so.1 (0x00007f04c2077000)
libquadmath.so.0 => /home//Experiments/Nvidia/OpenACC/OLCFHack15/gcc6/install/lib64/libquadmath.so.0 (0x00007f04c1e38000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f04c1c1a000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f04c1855000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f04c164d000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f04c1449000)
libstdc++.so.6 => /home//Experiments/Nvidia/OpenACC/OLCFHack15/gcc6/install/lib64/libstdc++.so.6 (0x00007f04c10c9000)
/lib64/ld-linux-x86-64.so.2 (0x00007f04c4624000)
而 f2py 使用
创建的模块
f2py -c -m --f90flags='-fopenacc -foffload=nvptx-none -foffload=-O3 -O3 - fPIC' hello hello.f90
给我
linux-vdso.so.1 => (0x00007ffeeef63000)
libpython3.5m.so.1.0 => not found
libgfortran.so.3 => /home//Experiments/Nvidia/OpenACC/OLCFHack15/gcc6/install/lib64/libgfortran.so.3 (0x00007f841918f000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f8418e89000)
libgcc_s.so.1 => /home//Experiments/Nvidia/OpenACC/OLCFHack15/gcc6/install/lib64/libgcc_s.so.1 (0x00007f8418c73000)
libquadmath.so.0 => /home//Experiments/Nvidia/OpenACC/OLCFHack15/gcc6/install/lib64/libquadmath.so.0 (0x00007f8418a34000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f841866f000)
/lib64/ld-linux-x86-64.so.2 (0x00007f84196be000)
很明显,libgomp 在可执行文件中被 linked,但在 f2py 创建的对象中却没有。所以我将f2py命令修改为
f2py -c -m --f90flags='-fopenacc -foffload=nvptx-none -foffload=-O3 -O3 -fPIC' hello hello.f90 -L/usr/local/cuda/lib64 -lcublas -lcudart -lgomp
现在它可以编译,我可以导入 python 而不会出现该错误。
正如我通过邮件告诉你的那样,我终于设法通过 f2py 正确地调用了 acc_init 和一些内核。
我的代码目前还不完全正确,我仍然需要继续努力,但这是我用来调用 f2py 的 CMakeLists.txt 的一部分(基本上我添加了 -L/data_local/sw/pgi/linuxpower/19.9/ -L/usr/lib64 -L.-laccapi -laccg -laccn -laccg2 -ldl -lcudadevice -lpthread -lpgc -lm 到 f2py 调用按照 中的解释):
set(OPENACC_Fortran_FLAGS -Mnorpath)
list(APPEND OPENACC_Fortran_FLAGS -Minfo)
list(APPEND OPENACC_Fortran_FLAGS -acc)
list(APPEND OPENACC_Fortran_FLAGS -ta=tesla:nordc)
list(APPEND OPENACC_Fortran_FLAGS -ta=tesla:cc60,cc70)
list(APPEND OPENACC_Fortran_FLAGS -Mextend)
list(APPEND OPENACC_Fortran_FLAGS -Mbackslash)
list(APPEND OPENACC_Fortran_FLAGS -Mcuda=cuda10.1)
list(APPEND OPENACC_Fortran_FLAGS -lcuda)
set(EXTRA_Fortran_FLAGS ${OPENACC_Fortran_FLAGS})
## BUILD python wrapper
add_custom_command(OUTPUT ${SOURCE_LIST_WRAP}
COMMAND f90wrap -m my_module ${SOURCE_LIST_TO_WRAP}
DEPENDS ${SOURCE_LIST_TO_WRAP})
add_custom_target(_my_module ALL
DEPENDS ${SOURCE_LIST_WRAP}
COMMAND CC=gcc f2py --fcompiler=pg --f90flags="${EXTRA_Fortran_FLAGS}" -m _my_module -c ${SOURCE_LIST_WRAP} -L. -lmy_kernels_lib -L/data_local/sw/pgi/linuxpower/19.9/ -L/usr/lib64 -L. -laccapi -laccg -laccn -laccg2 -ldl -lcudadevice -lpthread -lpgc -lm )
事实上,我似乎只需要 -laccn:
add_custom_target(_my_module ALL
DEPENDS ${SOURCE_LIST_WRAP}
COMMAND CC=gcc f2py --fcompiler=pg --f90flags="${EXTRA_Fortran_FLAGS}" -m _my_module -c ${SOURCE_LIST_WRAP} -L. -lmy_kernels_lib -laccn )
PS:
这对于 PGI 19.x 和 20.x 是正确的我需要更改标志:
if (CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 20)
set(F2PY_ACC_LIBS -laccapi -laccn)
else()
set(F2PY_ACC_LIBS -lcudafor -lacccuda -lcudafor2 -lcudafor101 -lcudadevice)
endif()
我正在编写一个简单的测试代码,看看如何包装包含 openacc 区域的 Fortran 代码并从 python 调用。这是代码。
module test
use iso_c_binding, only: sp => C_FLOAT, dp => C_DOUBLE, i8 => C_INT
implicit none
contains
subroutine add (a, b, n, c)
integer(kind=i8), intent(in) :: n
real(kind=dp), intent(in) :: a(n)
real(kind=dp), intent(in) :: b(n)
real(kind=dp), intent(out) :: c(n)
integer(kind=i8) :: i
!$acc enter data create(a, b, c)
do i = 1, n
c(i) = a(i) + b(i)
end do
!$acc exit data delete(a, b, c)
end subroutine add
subroutine mult (a, b, c)
real(kind=dp), intent(in) :: a
real(kind=dp), intent(in) :: b
real(kind=dp), intent(out) :: c
c = a * b
end subroutine mult
end module test
现在,如果我不使用 openacc,它工作正常,我可以使用来自 python 的 add 和 mult。但是在我放入 openacc 区域之后,f2py 编译它很好,但是当我尝试导入到 python 时,我得到以下错误
ImportError: /home/vikram/Experiments/Experiments/fortran_python/hello.cpython-35m-x86_64-linux-gnu.so: undefined symbol: GOACC_enter_exit_data
这好像告诉我Python需要知道如何找到GOACC_enter_exit_data,我看到GOACC_enter_exit_data在libgomp.so.1。我如何告诉 python 它的路径。
我决定看看我直接编译link生成的可执行文件是什么。这样做
ldd a.out
给我
linux-vdso.so.1 => (0x00007ffed24a0000)
libcublas.so.7.5 => /usr/local/cuda/lib64/libcublas.so.7.5 (0x00007f04c2d45000)
libcudart.so.7.5 => /usr/local/cuda/lib64/libcudart.so.7.5 (0x00007f04c2ae7000)
libgfortran.so.3 => /home//Experiments/Nvidia/OpenACC/OLCFHack15/gcc6/install/lib64/libgfortran.so.3 (0x00007f04c27c1000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f04c24bb000)
libgomp.so.1 => /home//Experiments/Nvidia/OpenACC/OLCFHack15/gcc6/install/lib64/libgomp.so.1 (0x00007f04c228d000)
libgcc_s.so.1 => /home//Experiments/Nvidia/OpenACC/OLCFHack15/gcc6/install/lib64/libgcc_s.so.1 (0x00007f04c2077000)
libquadmath.so.0 => /home//Experiments/Nvidia/OpenACC/OLCFHack15/gcc6/install/lib64/libquadmath.so.0 (0x00007f04c1e38000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f04c1c1a000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f04c1855000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f04c164d000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f04c1449000)
libstdc++.so.6 => /home//Experiments/Nvidia/OpenACC/OLCFHack15/gcc6/install/lib64/libstdc++.so.6 (0x00007f04c10c9000)
/lib64/ld-linux-x86-64.so.2 (0x00007f04c4624000)
而 f2py 使用
创建的模块f2py -c -m --f90flags='-fopenacc -foffload=nvptx-none -foffload=-O3 -O3 - fPIC' hello hello.f90
给我
linux-vdso.so.1 => (0x00007ffeeef63000)
libpython3.5m.so.1.0 => not found
libgfortran.so.3 => /home//Experiments/Nvidia/OpenACC/OLCFHack15/gcc6/install/lib64/libgfortran.so.3 (0x00007f841918f000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f8418e89000)
libgcc_s.so.1 => /home//Experiments/Nvidia/OpenACC/OLCFHack15/gcc6/install/lib64/libgcc_s.so.1 (0x00007f8418c73000)
libquadmath.so.0 => /home//Experiments/Nvidia/OpenACC/OLCFHack15/gcc6/install/lib64/libquadmath.so.0 (0x00007f8418a34000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f841866f000)
/lib64/ld-linux-x86-64.so.2 (0x00007f84196be000)
很明显,libgomp 在可执行文件中被 linked,但在 f2py 创建的对象中却没有。所以我将f2py命令修改为
f2py -c -m --f90flags='-fopenacc -foffload=nvptx-none -foffload=-O3 -O3 -fPIC' hello hello.f90 -L/usr/local/cuda/lib64 -lcublas -lcudart -lgomp
现在它可以编译,我可以导入 python 而不会出现该错误。
正如我通过邮件告诉你的那样,我终于设法通过 f2py 正确地调用了 acc_init 和一些内核。
我的代码目前还不完全正确,我仍然需要继续努力,但这是我用来调用 f2py 的 CMakeLists.txt 的一部分(基本上我添加了 -L/data_local/sw/pgi/linuxpower/19.9/ -L/usr/lib64 -L.-laccapi -laccg -laccn -laccg2 -ldl -lcudadevice -lpthread -lpgc -lm 到 f2py 调用按照
set(OPENACC_Fortran_FLAGS -Mnorpath)
list(APPEND OPENACC_Fortran_FLAGS -Minfo)
list(APPEND OPENACC_Fortran_FLAGS -acc)
list(APPEND OPENACC_Fortran_FLAGS -ta=tesla:nordc)
list(APPEND OPENACC_Fortran_FLAGS -ta=tesla:cc60,cc70)
list(APPEND OPENACC_Fortran_FLAGS -Mextend)
list(APPEND OPENACC_Fortran_FLAGS -Mbackslash)
list(APPEND OPENACC_Fortran_FLAGS -Mcuda=cuda10.1)
list(APPEND OPENACC_Fortran_FLAGS -lcuda)
set(EXTRA_Fortran_FLAGS ${OPENACC_Fortran_FLAGS})
## BUILD python wrapper
add_custom_command(OUTPUT ${SOURCE_LIST_WRAP}
COMMAND f90wrap -m my_module ${SOURCE_LIST_TO_WRAP}
DEPENDS ${SOURCE_LIST_TO_WRAP})
add_custom_target(_my_module ALL
DEPENDS ${SOURCE_LIST_WRAP}
COMMAND CC=gcc f2py --fcompiler=pg --f90flags="${EXTRA_Fortran_FLAGS}" -m _my_module -c ${SOURCE_LIST_WRAP} -L. -lmy_kernels_lib -L/data_local/sw/pgi/linuxpower/19.9/ -L/usr/lib64 -L. -laccapi -laccg -laccn -laccg2 -ldl -lcudadevice -lpthread -lpgc -lm )
事实上,我似乎只需要 -laccn:
add_custom_target(_my_module ALL
DEPENDS ${SOURCE_LIST_WRAP}
COMMAND CC=gcc f2py --fcompiler=pg --f90flags="${EXTRA_Fortran_FLAGS}" -m _my_module -c ${SOURCE_LIST_WRAP} -L. -lmy_kernels_lib -laccn )
PS: 这对于 PGI 19.x 和 20.x 是正确的我需要更改标志:
if (CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 20)
set(F2PY_ACC_LIBS -laccapi -laccn)
else()
set(F2PY_ACC_LIBS -lcudafor -lacccuda -lcudafor2 -lcudafor101 -lcudadevice)
endif()