微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

连续调用fortran中的同一子例程,性能明显降低

如何解决连续调用fortran中的同一子例程,性能明显降低

TL; DR

我的程序两次调用一个子例程。该子例程两次都执行基本相同的操作,但是第二次运行需要更长的时间。这两个调用间的唯一区别是,第一个调用生成的数据被用作第二个调用中的输入。该数据存储在第一次调用子例程之前在模块中声明的可分配数组中。

全文

以下显示了我的代码中有关该问题的相关部分:

program Economy

!! Declarations !!

    use Modern_mod,only: Modern

    use Globals,only: Na,Ny,Ne,Vimp,Xmp,Pmp,FCp,Vimu,& ! Globals is a module containing vbles.
                     & Xmu,Pmu,FCu

    implicit none

    real(kind=nag_wp) :: param(4)

!! Execution !!

 ! First call to modern !

    param = (/1.0d0,2.0d0,3.0d0,4.0d0/)

    allocate(Vimp(Na,Ne),FCp(4,Na*Ne),Pmp(Ny,Xmp(Ny,Ne))

    call Modern(param,Xmp)

 ! Second call to modern !

    param = (/5.0d0,6.0d0,7.0d0,8.0d0/)

    allocate(Vimu(Na,FCu(4,Pmu(Ny,Xmu(Ny,FCu,Xmu)

end program Economy

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

module Modern_mod

    implicit none

    contains

    subroutine Modern(param,Vim,FCm,Pm,Xm)

    !! Declarations !!

     ! Modules !

        use Globals,Ny

        use FindVmp_mod,only: FindVmp

        use FindVmu_mod,only: FindVmu

        implicit none

     ! Declaring other variables !

        real(kind=nag_wp),intent(in) :: param(4)                               ! param-Parameters specific to one of the modern sectors;

        real(kind=nag_wp),intent(out),allocatable :: FCm(:,:),Xm(:,&      ! FCm-Firm choices; Xm-Policy fun;
                                                     & Pm(:,Vim(:,:)        ! Pm-Price of a share; Vim-Start of period value function;

        real(kind=nag_wp),allocatable :: Vm1(:,Vim1(:,Pm1(:,&       ! Vm1-Vm next guess; Pm1-Next share price guess;
                                        & Vm(:,:)                               ! Vm-End of period value function; Vim1-Next Vim guess;

    !! Execution !!

     ! Allocating and initializing functions !

        allocate(Vim(Na,FCm(4,Vm(Ny,Pm(Ny,Xm(Ny,Ne))
        allocate(Vim1(Na,Vm1(Ny,Pm1(Ny,Ne))

     ! Inizializing arrays !

        Vm  = ...
        Vim = ...

        ...

     ! Doing calculations !

        if(param(1) .eq. 1.0d0) then
            call FindVmp(FCm,Vm1,Pm1,Xm)         ! New value funciton guess for productive guys
        else
            call FindVmu(FCm,Xm)         ! New value funciton guess for unproductive guys
        end if

    end subroutine Modern

end module Modern_mod

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

module FindVmp_mod

    implicit none

    contains

        subroutine  FindVmp(FCm,Vim0,P0,Vm,P,x)

        !! Declarations !!

            use Vmfp_mod,only: Calculations               ! Contains the operations computing the final values of the outputs to FindVmp

            implicit none

            real(kind=nag_wp),allocatable,intent(out) :: Vm(:,x(:,P(:,:)  ! Vm-New value function; x-Policy function; P-Share price;

            real(kind=nag_wp),intent(in) :: P0(:,Vim0(:,FCm(:,:)           ! P0-Initial share price guess; Vim-Initial guess for beginning of period value function;
                                                                                                            ! FCm-Firm choices;

        !! Execution !!

         ! Allocate matrices !

            allocate(Vm(Ny,x(Ny,P(Ny,Ne))

         ! Compute results !

            call Calculations(FCm,x)

        end subroutine FindVmp

end module FindVmp_mod

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

module FindVmu_mod

    implicit none

    contains

        subroutine  FindVmu(FCm,x) 

        !! Declarations !!

            use Globals,only: Vmp,Pmp

            use VmFu_mod,only: Calculations       ! Contains the operations computing the final values of the outputs to FindVmu

            implicit none

            real(kind=nag_wp),x,Vmp,Pmp)   ! Using the values of Vmp and Pmp computes in the first call to Modern

        end subroutine FindVmu

end module FindVmu_mod

每次运行时,Modern被馈入在模块*p中声明的相同大小和类型(分别为*uGlobals)的不同数组。 Modern类似地调用两个非常相似的子例程FindVm?中的一个,为它们提供相应的数组。 FindVmpFindVmu计算几乎相同的操作,只是后者使用Vimp,Pmp的值(在FindVmp中计算)作为输入。

我一直在试图弄清为什么第二个对Modern调用与第一个相比要花费更长的时间来完成。

我的第一个猜测是,也许通过在程序开始时分配VimpPmp,然后再分配一堆其他数组,每个对前一个数组的引用可能会很昂贵,因为它们的内存地址与FindVmu中当前正在计算的数组(供参考,Na = 101,Ny = 91,Ne = 9)相距很远。但是后来我读到allocated数组存储在堆中,并且堆中的数据没有被 stacked (没有双关语),因此这不一定是我的问题的根源。实际上,我尝试在Modern中以不同的点和顺序将所有矩阵分配给我,但是执行时间大致相同。

本着同样的精神,我试图改变在不同子例程中声明某些数组的方式(例如,使某些数组自动而不是可分配,并使用编译器(ifort18)选项将其强制放在堆栈上),尽管我确实会在整个代码中产生整体性能差异,两次调用Modern的相对性能不会改变。

最后,我读到in this thread,说您在内存中拥有的数组越多,代码通常就变得越慢。尽管这种解释对我来说确实有意义,但这是我第一次在整个fortran程序中遇到如此重大的性能损失。如果这确实是我面临的问题,那么我可能会在之前的许多项目中都遇到过这个问题。尽管如此,这是否可能是这里发生的事情的原因?

我基本上没有主意...

奖励问题

我们正在研究它,但发现Economy中的以下几行(对我而言)令人惊讶地不会导致段错误

allocate(Vimp(Na,Ne))

allocate(Vimu(Na,Ne))

换句话说:如果我不手动分配在Globals中声明的数组,那么当我将它们传递给Modern时,程序似乎就自动执行了。是这种标准行为,还是当我最初自己不分配它们时很幸运?

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。