Fortran 调用 C:如何获得有效的矢量化函数
Posted
技术标签:
【中文标题】Fortran 调用 C:如何获得有效的矢量化函数【英文标题】:Fortran calling C: How do I get an efficient vectorised function 【发布时间】:2016-07-04 13:00:12 【问题描述】:我必须从 Fortran 调用 C 函数,但我想在向量化循环中执行此操作。我正在 Linux 上使用 Intel 16.0.3 编译器。
所以选项是:我可以尝试将函数内联,或者我可以使用 SIMD 函数(我想为此使用 OpenMP SIMD,我希望它是可移植的,并且我已经在使用 OpenMP)。
如果我从 Fortran 调用 Fortran,它可以双向工作。对于传递参数,我使用 linear/ref 子句来传递对值向量而不是引用向量的引用,这似乎有效。但在 C 中,linear/ref 子句不被识别。
我可以让函数名义上矢量化,但它正在插入聚集和分散,性能并不比标量好(至少对于我的小测试函数而言)。
如果我将 linear(ref(r,s))
放在 Fortran 接口块中,我会收到消息
UVAL 或 REF 修饰符不得用于带有 VALUE 属性。
我可以使用从 Fortran 传递值并返回一个值作为函数返回的技巧来获得性能。这会产生一个向量化的函数,并且性能很好,但不幸的是我的真实函数需要返回多个值。
如果我尝试内联 C 函数,它将无法正常工作。 opt-report 只是告诉我调用站点不能内联。即使使用标量函数也是如此。我根本无法让 C 函数内联到 Fortran。我正在使用 ipo 来尝试这样做。我想知道内联问题是否可能是 Fortran 将指针传递给指针?但是随着代码给出了正确的答案,它似乎在某种程度上可以接受。
测试代码(传递指针)本质上是……
Fortran 调用者
Use, intrinsic :: ISO_C_BINDING
….
real*8, allocatable :: r(:),s(:) .
….
interface
integer simd_c_func(r,s) bind(c, name="simd_c_func")
!$OMP DECLARE SIMD(simd_c_func)
import :: C_DOUBLE
real(kind=C_DOUBLE), intent(inout):: r,s
end interface
allocate....
!$OMP SIMD
do i=1,N
ierror=simd_c_func(r(i),s(i))
enddo
C被调用者
#pragma omp declare simd
int simd_c_func(double *r, double *s)
(*r)+=(*s);
return 0;
【问题讨论】:
你能做一个可以编译的测试程序吗? 这些东西很新,支持不完整,而且因编译器版本而异。包含实际的编译器输出并尝试制作一个 MCVE ***.com/help/mcve 好的,我会尽快粘贴一个工作示例。我在带有相关编译器包的独立机器上拥有代码。正在等待转移。 【参考方案1】:LINEAR(REF())
很新,所以只能希望一些使用 OMP 和 CONTIGUOUS 的 LINEAR 可以让你开心。
消息:
UVAL 或 REF 修饰符不得用于具有 VALUE 属性的虚拟参数。"
表示它正在做值并在堆栈上。我以为 C 数组在 heap
中?但也许你需要一个-heap
开关?
C 端:
我建议你加linear
给你#pragma
#pragma omp declare simd linear(r,s)
您是否考虑过使用#pragma vector aligned
?还有#pragma ivdep
?
我假设 (*r) 是一个引用(在堆中)
F90 侧
我建议你更换:
real(8), allocatable :: r(:), s(:)
与
!$DIR ATTRIBUTES ALIGN:64 :: R, S
REAL(KIND=8), DIMENSION(:), ALLOCATABLE, CONTIGUOUS :: R, S
这里唯一真正的变化是 64 位对齐和连续。 也可以使用 switch -align array64byte
如果ierror
不是一个数组,那么你想要一个吗?或者您是否可能需要在ierror
上使用第一个/最后一个私有或缩减子句?我可能会使用归约。
!$OMP SIMD
然后转到:
!$OMP DO SIMD REDUCTION(ierror)
但正如您提到的,您需要多个值,那么您可能需要分配ierror
?
我对接口如何知道它的返回值为零感兴趣。好像你必须在界面的某个地方有 INTEGER FUNCTION。
链接编译端:
如果 C 生成了 F90-
MODULE,则 USE 将允许它深入了解 C 代码以内联或以其他方式提供帮助。所以你可能需要编译器/链接上的-IPO
来让 F90 了解它可以对 C 调用者做什么。
【讨论】:
【参考方案2】:睡一觉后,我想知道你是否应该只是有一个 void,并在你的接口规范上使用子程序?
另一个选项似乎是: INTEGER FUNCTION simd_c_func 然后在 FORTRAN 端的 SIMD 中使用 REDUCTION。
但是这些都没有解决您收到的实际编译器消息。 我看到你已经使用了-IPO。
您可以尝试替换: 线性(REF(R,S)) 和 线性(REF(R), REF(S))
【讨论】:
这可能是对您之前答案的修改。水平标尺 (---
) 可以很好地分隔各个部分,并且可以使用大字体的标题。所以我建议进行编辑,然后删除第二个答案。欢迎来到 ***,顺便说一句。我不知道编译器可以在语言之间进行链接时间优化。这很酷。 (不过我不知道 fortran;因为 SIMD 标签,我看到了这个问题,所以我自己不能在这个问题上添加任何东西。)。
另外,如果this is you as well,您应该将您的帐户合并为一个
Peter 如何合并它们?我似乎找不到它。
IDK,我从来没有创建过第二个帐户。我认为这应该是可能的;尝试搜索 meta.***.com 或 meta.stackexchange.com以上是关于Fortran 调用 C:如何获得有效的矢量化函数的主要内容,如果未能解决你的问题,请参考以下文章