Fortran调用C:如何获得高效的矢量化函数

时间:2016-07-04 13:00:12

标签: c fortran vectorization simd intel-fortran

我必须从Fortran调用C函数,但我想在矢量化循环中执行此操作。我正在使用Linux上的Intel 16.0.3编译器。

所以选项是:我可以尝试将函数内联或者我可以使用SIMD函数(我想使用OpenMP SIMD,我希望它是可移植的,我已经使用了OpenMP)。

如果我从Fortran调用Fortran,它可以双向工作。对于传递参数,我使用线性/ ref子句将引用传递给值向量而不是引用向量,这似乎有效。但在C中,线性/ ref子句无法识别。

我可以得到名义矢量化的功能,但它插入了收集和散射,性能并不比标量好(至少对于我的小测试函数)。

如果我将linear(ref(r,s))放在Fortran接口块中,我会收到消息

  

不得在伪参数上使用UVAL或REF修饰符   VALUE属性。

我可以使用从Fortran传递值并返回值作为函数返回的技巧来获得性能。这会产生一个矢量化函数,性能也很好,但遗憾的是我的实函数需要返回多个值。

如果我尝试内联C函数,它就行不通。 opt报告告诉我,无法内联呼叫站点。即使使用标量函数也是如此。我根本无法将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 callee

#pragma omp declare simd
int simd_c_func(double *r, double *s) {
 (*r)+=(*s);
 return 0;
}

2 个答案:

答案 0 :(得分:2)

LINEAR(REF())很新,所以人们只能希望使用OMP和CONTIGUOUS的LINEAR可以让你高兴。

消息:

  

不得在具有VALUE属性的伪参数上使用UVAL或REF修饰符。"

表示它在堆栈上正在执行值。我以为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被调用者做什么。

答案 1 :(得分:0)

睡了之后,我想知道你是否应该有一个空白,并在你的接口规范上使用子程序?

另一种选择似乎是: INTEGER FUNCTION simd_c_func然后在FORTRAN侧的SIMD中使用REDUCTION。

但是这些都没有解决你得到的实际编译器消息。 而且我看到你已经使用过-IPO了。

您可以尝试替换: LINEAR(REF(R,S)) 同 LINEAR(REF(R),REF(S))