Fortran 中的内联函数
Inlining functions in Fortran
在 Fortran 项目中,我们使用二进制搜索来查找所需的值:
integer function binsearch(tab, el)
implicit none
real, intent(in) :: tab(:), el
integer :: a, b, mid
a = 1
b = size(tab)
do while (b - a > 1)
mid = (a + b)/2
if (el >= tab(mid)) then
a = mid
else
b = mid
endif
! if (el < tab(mid + 1)) exit ! BAD OPTIMIZATION !
enddo
binsearch = a
end function binsearch
后面我们就直接用
foo = binsearch(tab, el)
不幸的是,周围例程的使用如此频繁,以至于 BAD OPTIMIZATION
将总执行时间增加了一半。所以我考虑内联函数以减少调用成本。
是否可以将此函数标记为内联?在 C 中有关键字 inline
这是对编译器的建议 - Fortran 2008 中是否有类似的内容?
为了代码清晰,我不想复制粘贴。
在 Fortran 中,没有与 C 中 inline
的直接模拟;内联哪些函数总是由编译器决定。然后最重要的是编译具有高优化级别的代码以打开积极的内联(例如 gfortran 中的 -Ofast
,ifort 中的 -fast
)。此外,您可能想要打开 "link-time optimization"(gfortran 中的 -flto
,ifort 中的 -ipo
),以便编译器可以在 link 时间内联来自不同源文件的函数如有必要。
但是,有一些方法可以重写增加内联机会的代码。一种这样的方法是将函数显式标记为 pure
(即没有副作用的函数),因为这意味着编译器更容易优化对它的调用。换句话说:
pure function binsearch(tab, el) result(r)
real, intent(in) :: tab(:), el
integer :: r, a, b, mid
...
end function
如果您可以将 binsearch
重写为您正在使用它的任何函数中的嵌套函数,编译很可能会替换函数对 tab
的函数调用正文或快速 goto
语句,即使您不更改编译选项。在那种情况下:
subroutine some_other_thing()
...
! Do the search
i = binsearch(tab, el)
...
contains
pure function binsearch(tab, el) result(r)
real, intent(in) :: tab(:), el
integer :: r, a, b, mid
...
end function
end subroutine
这取决于编译器。我可以验证这适用于 Cray 和 Intel Fortran 编译器,但语句略有不同。
Cray 编译器:
!dir$ forceinline :: frob
这将强制编译器内联函数 frob。你会把它放在函数定义的正上方。
英特尔编译器:
!dir$ attributes forceinline :: frob
我没有看到 gcc/gfortran 目前有这些选项。
两种编译器的手册都涵盖了这一点。
在 Fortran 项目中,我们使用二进制搜索来查找所需的值:
integer function binsearch(tab, el)
implicit none
real, intent(in) :: tab(:), el
integer :: a, b, mid
a = 1
b = size(tab)
do while (b - a > 1)
mid = (a + b)/2
if (el >= tab(mid)) then
a = mid
else
b = mid
endif
! if (el < tab(mid + 1)) exit ! BAD OPTIMIZATION !
enddo
binsearch = a
end function binsearch
后面我们就直接用
foo = binsearch(tab, el)
不幸的是,周围例程的使用如此频繁,以至于 BAD OPTIMIZATION
将总执行时间增加了一半。所以我考虑内联函数以减少调用成本。
是否可以将此函数标记为内联?在 C 中有关键字 inline
这是对编译器的建议 - Fortran 2008 中是否有类似的内容?
为了代码清晰,我不想复制粘贴。
在 Fortran 中,没有与 C 中 inline
的直接模拟;内联哪些函数总是由编译器决定。然后最重要的是编译具有高优化级别的代码以打开积极的内联(例如 gfortran 中的 -Ofast
,ifort 中的 -fast
)。此外,您可能想要打开 "link-time optimization"(gfortran 中的 -flto
,ifort 中的 -ipo
),以便编译器可以在 link 时间内联来自不同源文件的函数如有必要。
但是,有一些方法可以重写增加内联机会的代码。一种这样的方法是将函数显式标记为 pure
(即没有副作用的函数),因为这意味着编译器更容易优化对它的调用。换句话说:
pure function binsearch(tab, el) result(r)
real, intent(in) :: tab(:), el
integer :: r, a, b, mid
...
end function
如果您可以将 binsearch
重写为您正在使用它的任何函数中的嵌套函数,编译很可能会替换函数对 tab
的函数调用正文或快速 goto
语句,即使您不更改编译选项。在那种情况下:
subroutine some_other_thing()
...
! Do the search
i = binsearch(tab, el)
...
contains
pure function binsearch(tab, el) result(r)
real, intent(in) :: tab(:), el
integer :: r, a, b, mid
...
end function
end subroutine
这取决于编译器。我可以验证这适用于 Cray 和 Intel Fortran 编译器,但语句略有不同。
Cray 编译器:
!dir$ forceinline :: frob
这将强制编译器内联函数 frob。你会把它放在函数定义的正上方。
英特尔编译器:
!dir$ attributes forceinline :: frob
我没有看到 gcc/gfortran 目前有这些选项。
两种编译器的手册都涵盖了这一点。