【问题标题】:Why does Fortran spend so much time on 'for_allocate' or 'for_deallocate'?为什么 Fortran 在“for_allocate”或“for_deallocate”上花费这么多时间?
【发布时间】:2017-11-12 17:25:22
【问题描述】:

我正在尝试优化我继承的一些 Fortran 代码。这是一个非常重复的代码,需要几天才能运行,我正在努力减少运行时间。在减少了一些函数和子程序的运行时间之后,根据 VTune Amplifier,最新的瓶颈是 for_deallocation 和 for_allocation,具体从一个子程序调用。我有点不确定“for_”在分配和释放之前的含义,尤其是在例程中没有进行分配的情况下。代码总结如下:

module global_variables
    double precision, allocatable :: input_values(:)
    double precision, allocatable :: input_values2(:,:)
    double precision, allocatable :: indices_array(:)
    double precision, allocatable :: value_array(:)
    double precision, allocatable :: final_result(:)
end module

subroutine func1()
    allocate( ...global values...)
    do I=1,n
        call func2(I)
    end do

end subroutine func1

subroutine func2(I)
    double precision, intent(in) :: I
    double precision :: value, x
    double precision, dimension(3) :: output_array

    call find_Indices(x)
    value_array = input_values(indices_array)
    call calculations(value)

    do j = 1,3
        value_array = input_values2(indices_array,j)
        call calculations(output_array(j))
    end do

    final_result = output_array * value

end subroutine func2

subroutine find_Indices(position)
    indices_array = some calculation on position
end subroutine find_Indices

subroutine calculations(output)
    double precision :: output
    output = some calculation on value_array
end subroutine calculations

由于其性质,我不得不总结而不是粘贴实际代码。分配/释放时间过长的子程序是func2。子例程中没有分配语句,也没有重新分配全局值。使用我可用的文档,我无法确定分配/解除分配前面的“for_”是什么意思,或者为什么在 func2 中花了这么多时间。由于我指定将所有数组放在堆上的代码的大小,这将解释分配,但是允许数组回到堆栈上并没有减少时间。

有没有人能帮助我理解 for_allocate/for_deallocate 的本质?或者为什么这个函数会花这么多时间调用它?

解决方案:

在谷歌搜索数组属性时,对于我遇到的另一个问题,我遇到了这篇文章: Fortran: dynamic arrays vs. automatic array Avoiding Memory Allocation

这表明修改可分配的全局数组有很大的开销。将 value_array 从可分配数组更改为指针数组(双精度,指针 :: value_array(:))消除了 for_allocate 和 for_deallocate 的大部分开销,并将运行时间减少到原来的 1/5。这向我表明,当可分配数组的值被修改时,原始数组被释放并分配一个新数组。这在 Fortran 社区中可能是众所周知的,但作为一个新用户,没有遇到任何形式的这种行为的文档,这对我来说并不明显。

【问题讨论】:

  • 我们需要一些上下文。至少是一个可编译的子程序(最好是一个小程序),以及您正在使用的编译器。
  • 在没有更好的信息的情况下,人们可能会猜测您需要内联或此类优化来跨对 func2 的多次调用保留动态数组,以及可能尝试堆栈与堆。 output_array 似乎最有可能以昂贵的分配转移到堆中。 for_ 只是指 Fortran 运行时库。
  • 我使用的是英特尔 17.0 编译器。我会看看我能做些什么来创建一个可编译的例子。我应该意识到“for_”代表 Fortran,我只是觉得英特尔使用“fort”作为 Fortran 的缩写。
  • 请准备一个完全可编译的示例 (minimal reproducible example),而不仅仅是代码摘要。
  • 好的,下次我发问题时我会记住的。

标签: optimization fortran intel-fortran


【解决方案1】:

https://software.intel.com/en-us/articles/fortran-array-data-and-arguments-and-vectorization查看“6. 间接数组访问”中的示例

重复分配(很可能)是因为在使用索引数组时,编译器会分配一个临时数组(上面链接中的示例 7.1)来存储结果数组。另一种方法是显式循环索引(示例 7.2)。

上面的链接适用于 MIC 架构,但原理在普通 CPU 上可能相同。此处https://software.intel.com/en-us/forums/intel-fortran-compiler-for-linux-and-mac-os-x/topic/685221 的线程还提示为数组索引创建临时数组。

为了确定发生了什么,可以检查程序集输出或显式测试“显式索引”场景。

【讨论】:

    猜你喜欢
    • 2017-11-15
    • 1970-01-01
    • 2016-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-01
    相关资源
    最近更新 更多