我有一个与多维数组或派生类型的访问时间相关的问题。我写了一个很好的算法。但是,此算法的主要部分使用%
通过不同类型引用某些数据。例如,这是我的代码中最昂贵的循环:
do c_elem = 1 , no_elems
call tmp_element%init_element(no_fl)
tmp_element%Gij(no_fl,1) = e_Gxa(c_elem)
tmp_element%Gij(no_fl,2) = e_Gax(c_elem)
GAX = tmp_element%Gij(no_fl,1)/GAA
GXA = tmp_element%Gij(no_fl,2)/GAA
do k = 1 , no_fl-1
s1 = this%flNew%Iij(k)
i1 = this%nodes(s1)%fl_id
tmp_element%Gij(k,1) = this%elOld(c_elem)%Gij(i1,1) + GAX*this%flNew%Gij(no_fl,k)
tmp_element%Gij(k,2) = this%elOld(c_elem)%Gij(i1,2) + this%flNew%Gij(k,no_fl)*GXA
enddo
call this%elOld(c_elem)%init_element(no_fl)
this%elOld(c_elem)%Gij = tmp_element%Gij
enddo
正如您所看到的那样,我通过%
访问一些变量,并且大多数数组都有“可分配”变量,复数或整数。我读过有时使用派生类型可能会导致计算速度变慢,所以我决定重写我的算法直接在没有类型的数组上工作。现在只使用数组的相同循环看起来像:
do c_elem = 1 , no_elems
nGij1(no_fl,c_elem) = e_Gxa(c_elem)
nGij2(no_fl,c_elem) = e_Gax(c_elem)
GAX = e_Gxa(c_elem)/GAA
GXA = e_Gax(c_elem)/GAA
do k = 1 , no_fl-1
i1 = fl_id(k)
nGij1(k,c_elem) = oGij1(i1,c_elem) + GAX*fl_new_Gij(no_fl,k)
nGij2(k,c_elem) = oGij2(i1,c_elem) + fl_new_Gij(k,no_fl)*GXA
enddo
enddo
我预计上面的代码比我使用派生类型的代码运行得更快。所以我检查了时间。以下是此部分代码的CPU时间:
我在编译和ifort英特尔编译器中只使用-O2
选项。在上面的代码中,no_elems>> no_fl和大多数数组和类型都很复杂。很明显,两种算法的唯一区别是存储器访问时间。
为什么两种情况的执行时间都有很大差异?
编辑#1
我试图做一个简短的例子,但是我无法获得与完整代码类似的结果......两种情况的时间几乎相同 - 数组稍快一些。
我可以向你展示对我来说完全陌生的事情:我有一个类型:
type element
complex*16,allocatable :: Gij(:,:)
integer :: no_sites
complex*16 :: Gp,Gxa,Gax
integer :: i,j
contains
procedure,pass(this) :: free_element
procedure,pass(this) :: init_element
procedure,pass(this) :: copy_element
end type element
然后,在一个大循环的某个点上,我计算这样的值:
! derived type way
this%elOld(c_elem)%Gax = GAX
this%elOld(c_elem)%Gxa = GXA
this%elOld(c_elem)%Gp = this%elOld(c_elem)%Gp + GXA*GAX/GAA
! array way to do it
e_Gax(c_elem) = GAX
e_Gxa(c_elem) = GXA
e_Gp (c_elem) = e_Gp (c_elem) + GXA*GAX/GAA
其中:
complex(16),allocatable :: e_Gax(:),e_Gxa(:),e_Gp(:)
和elOld是另一种类型
定义的元素数组 type(element),allocatable :: elOld(:),elNew(:)
然后我有循环,我已经告诉你了,但如果我这样做的话:
tmp_element%Gij(no_fl,1) = e_Gxa(c_elem)
tmp_element%Gij(no_fl,2) = e_Gax(c_elem)
GAX = e_Gxa(c_elem)/GAA
GXA = e_Gxa(c_elem)/GAA
而不是:
tmp_element%Gij(no_fl,1) = this%elOld(c_elem)%Gxa
tmp_element%Gij(no_fl,2) = this%elOld(c_elem)%Gax
GAX = tmp_element%Gij(no_fl,1)/GAA
GXA = tmp_element%Gij(no_fl,2)/GAA
程序变得明显变慢......(使用type(elemen):: tmp_element),这意味着访问简单数组e_Gxa(:)比访问类型数组中的复杂变量Gxa要慢,即此%elOld( :)%GXA。仅更改代码的几行可能会改变可见的执行时间。 我用gfortran检查了它,结果是一样的。以下是我正在讨论的完整代码的一部分:modskminv_fast.f90。 很抱歉发布完整模块,但是当我将代码拆分成小块时,我无法获得相同的结果。
答案 0 :(得分:0)
错误显然在我身边。偶然我将所有复杂的数组声明为:
complex(16)
而不是
complex*16 or complex(kind=8)
很抱歉打扰你。现在,它就像一个魅力:)