【问题标题】:Improve Fortran computation-time [closed]改善 Fortran 计算时间 [关闭]
【发布时间】:2021-06-12 13:22:27
【问题描述】:

我有这个我最初实现的代码的 sn-p 需要检查。检查后,我现在想知道它是否可以优化。特别是提出的问题是:

“预先初始化该大型计算的所有单个成员而不是直接在其中计算它们会更好吗(即 sqrt() )?”

换句话说,在计算本身执行计算时,内存分配与 CPU 时间之间是否存在权衡?

这里是代码 sn-p(编辑):

                                 do id=1,3
                                    BF(idx1,idx2,idx3)  = BF(idx1,idx2,idx3) +&
                                       ! i-j, i-k
                                       2*bsa_wind_coeff(ilib,4+id,inode)*bsa_wind_coeff(jlib,1+id,jnode)*bsa_wind_coeff(klib,1+id,knode)* &
                                       (nodCorr(id,p1)* sqrt(SU(i1,id,inode)*SU(i1,id,jnode))) * (nodCorr(id,p2)* sqrt(SU(i2,id,inode)*SU(i2,id,knode)) )+&
                                       ! i-j, j-k
                                       2*bsa_wind_coeff(ilib,1+id,inode)*bsa_wind_coeff(jlib,4+id,jnode)*bsa_wind_coeff(klib,1+id,knode)* &
                                       (nodCorr(id,p1)* sqrt(SU12(id,inode)*SU12(id,jnode))) * (nodCorr(id,p3)* sqrt(SU(i2,id,jnode)*SU(i2,id,knode)) )+&
                                       ! i-k, j-k
                                       2*bsa_wind_coeff(ilib,1+id,inode)*bsa_wind_coeff(jlib,1+id,jnode)*bsa_wind_coeff(klib,4+id,knode)* &
                                       (nodCorr(id,p2)* sqrt(SU12(id,inode)*SU12(id,knode))) * (nodCorr(id,p3)* sqrt(SU(i1,id,jnode)*SU(i1,id,knode)) )
                                 enddo

                                 ! dir 1-2
                                 BF(idx1,idx2,idx3)  = BF(idx1,idx2,idx3) +&
                                    ! i-k, i-j
                                    bsa_wind_coeff(ilib,8,inode)*bsa_wind_coeff(jlib,3,jnode)*bsa_wind_coeff(klib,2,knode)* &
                                       (nodCorr(1,p2)* sqrt( SU(i2,1,inode)*SU(i2,1,knode) )) * (nodCorr(2,p1)* sqrt( SU(i1,2,inode)*SU(i1,2,jnode) ) )+&
                                    ! i-j, j-k
                                    bsa_wind_coeff(ilib,2,inode)*bsa_wind_coeff(jlib,8,jnode)*bsa_wind_coeff(klib,3,knode)* &
                                       (nodCorr(1,p2)* sqrt( SU12(1,inode)*SU12(1,jnode) )) * (nodCorr(2,p3)* sqrt( SU(i2,2,jnode)*SU(i2,2,knode) ) )+&
                                    ! j-k, i-k
                                    bsa_wind_coeff(ilib,3,inode)*bsa_wind_coeff(jlib,2,jnode)*bsa_wind_coeff(klib,8,knode)* &
                                       (nodCorr(1,p3)* sqrt( SU(i1,1,jnode)*SU(i1,1,knode) )) * (nodCorr(2,p2)* sqrt( SU12(2,inode)*SU12(2,knode) ) )+&
                                    ! i-j, i-k
                                    bsa_wind_coeff(ilib,8,inode)*bsa_wind_coeff(jlib,2,jnode)*bsa_wind_coeff(klib,3,knode)* &
                                       (nodCorr(1,p1)* sqrt( SU(i1,1,inode)*SU(i1,1,jnode) )) * (nodCorr(2,p2)* sqrt( SU(i2,2,inode)*SU(i2,2,knode) ) )+&
                                    ! j-k, i-j
                                    bsa_wind_coeff(ilib,3,inode)*bsa_wind_coeff(jlib,8,jnode)*bsa_wind_coeff(klib,2,knode)* &
                                       (nodCorr(1,p3)* sqrt( SU(i2,1,jnode)*SU(i2,1,knode) )) * (nodCorr(2,p1)* sqrt( SU12(2,inode)*SU12(2,jnode) ) )+&
                                    ! i-k, j-k
                                    bsa_wind_coeff(ilib,2,inode)*bsa_wind_coeff(jlib,3,jnode)*bsa_wind_coeff(klib,8,knode)* &
                                       (nodCorr(1,p2)* sqrt( SU12(1,inode)*SU12(1,knode) )) * (nodCorr(2,p3)* sqrt( SU(i1,2,jnode)*SU(i1,2,knode) ) )

                                 
                                 ! dir 1-3
                                 BF(idx1,idx2,idx3)  = BF(idx1,idx2,idx3) +&
                                    ! i-k, i-j
                                    bsa_wind_coeff(ilib,9,inode)*bsa_wind_coeff(jlib,4,jnode)*bsa_wind_coeff(klib,2,knode)* &
                                       (nodCorr(1,p2)* sqrt( SU(i2,1,inode)*SU(i2,1,knode) )) * (nodCorr(3,p1)* sqrt( SU(i1,3,inode)*SU(i1,3,jnode) ) )+&
                                    ! i-j, j-k
                                    bsa_wind_coeff(ilib,2,inode)*bsa_wind_coeff(jlib,9,jnode)*bsa_wind_coeff(klib,4,knode)* &
                                       (nodCorr(1,p2)* sqrt( SU12(1,inode)*SU12(1,jnode) )) * (nodCorr(3,p3)* sqrt( SU(i2,3,jnode)*SU(i2,3,knode) ) )+&
                                    ! j-k, i-k
                                    bsa_wind_coeff(ilib,4,inode)*bsa_wind_coeff(jlib,2,jnode)*bsa_wind_coeff(klib,9,knode)* &
                                       (nodCorr(1,p3)* sqrt( SU(i1,1,jnode)*SU(i1,1,knode) )) * (nodCorr(3,p2)* sqrt( SU12(3,inode)*SU12(3,knode) ) )+&
                                    ! i-j, i-k
                                    bsa_wind_coeff(ilib,9,inode)*bsa_wind_coeff(jlib,2,jnode)*bsa_wind_coeff(klib,4,knode)* &
                                       (nodCorr(1,p1)* sqrt( SU(i1,1,inode)*SU(i1,1,jnode) )) * (nodCorr(3,p2)* sqrt( SU(i2,3,inode)*SU(i2,3,knode) ) )+&
                                    ! j-k, i-j
                                    bsa_wind_coeff(ilib,4,inode)*bsa_wind_coeff(jlib,9,jnode)*bsa_wind_coeff(klib,2,knode)* &
                                       (nodCorr(1,p3)* sqrt( SU(i2,1,jnode)*SU(i2,1,knode) )) * (nodCorr(3,p1)* sqrt( SU12(3,inode)*SU12(3,jnode) ) )+&
                                    ! i-k, j-k
                                    bsa_wind_coeff(ilib,2,inode)*bsa_wind_coeff(jlib,4,jnode)*bsa_wind_coeff(klib,9,knode)* &
                                       (nodCorr(1,p2)* sqrt( SU12(1,inode)*SU12(1,knode) )) * (nodCorr(3,p3)* sqrt( SU(i1,3,jnode)*SU(i1,3,knode) ) )


                                 ! dir 2-3
                                 BF(idx1,idx2,idx3)  = BF(idx1,idx2,idx3) +&
                                    bsa_wind_coeff(ilib,10,inode)*bsa_wind_coeff(jlib,4,jnode)*bsa_wind_coeff(klib,3,knode)* &
                                       (nodCorr(2,p2)* sqrt( SU(i2,2,inode)*SU(i2,2,knode) )) * (nodCorr(3,p1)* sqrt( SU(i1,3,inode)*SU(i1,3,jnode) ) )+&
                                    bsa_wind_coeff(ilib,3,inode)*bsa_wind_coeff(jlib,10,jnode)*bsa_wind_coeff(klib,4,knode)* &
                                       (nodCorr(2,p2)* sqrt( SU12(2,inode)*SU12(2,jnode) )) * (nodCorr(3,p3)* sqrt( SU(i2,3,jnode)*SU(i2,3,knode) ) )+&
                                    bsa_wind_coeff(ilib,4,inode)*bsa_wind_coeff(jlib,3,jnode)*bsa_wind_coeff(klib,10,knode)* &
                                       (nodCorr(2,p3)* sqrt( SU(i1,2,jnode)*SU(i1,2,knode) )) * (nodCorr(3,p2)* sqrt( SU12(3,inode)*SU12(3,knode) ) )+&
                                    bsa_wind_coeff(ilib,10,inode)*bsa_wind_coeff(jlib,3,jnode)*bsa_wind_coeff(klib,4,knode)* &
                                       (nodCorr(2,p1)* sqrt( SU(i1,2,inode)*SU(i1,2,jnode) )) * (nodCorr(3,p2)* sqrt( SU(i2,3,inode)*SU(i2,3,knode) ) )+&
                                    bsa_wind_coeff(ilib,4,inode)*bsa_wind_coeff(jlib,10,jnode)*bsa_wind_coeff(klib,3,knode)* &
                                       (nodCorr(2,p3)* sqrt( SU(i2,2,jnode)*SU(i2,2,knode) )) * (nodCorr(3,p1)* sqrt( SU12(3,inode)*SU12(3,jnode) ) )+&
                                    bsa_wind_coeff(ilib,3,inode)*bsa_wind_coeff(jlib,4,jnode)*bsa_wind_coeff(klib,10,knode)* &
                                       (nodCorr(2,p2)* sqrt( SU12(2,inode)*SU12(2,knode) )) * (nodCorr(3,p3)* sqrt( SU(i1,3,jnode)*SU(i1,3,knode) ) )

一些注意事项:

bsa_wind_coeffs 是一个公共变量(在模块中声明),而代码 sn-p 中存在的所有其他变量都是直接传递的(即我假设在本地创建一个副本)。在过程本身内,索引 ilib、jlib、klib、inode、jnode、knode 是循环的。在外部过程中多次调用此计算。

编辑: 这里的所有变量都是static,因为它们被计算一次(在调用此过程之前),然后只是根据一些索引值进行遍历,如您所见。也就是说,在每次调用时,都会传递相同的数组。

【问题讨论】:

  • 如果没有最小的完整示例,很难说清楚,重要的是循环(引导索引)以及有关变量大小、数据类型等的一些信息。
  • @albert,循环(当然在可能的情况下)已经优化为按列进行。数据类型(在操作本身中)始终为 real(8 个字节)。大小可能会有所不同,但我会说这并不能解决问题。我的问题想要更“conceptual”,也就是说,如果存在一个阈值,在这个阈值之前这个实现可能是首选的 w.r.t。相反(预先初始化 tmp vars 中的所有成员)。
  • sqrt 计算非常昂贵,因此将结果存储在临时数组中可能很有用,但这完全取决于使用相同输入数组的调用次数,其中 sqrt 被采用,所需额外内存的大小,将部分保存在内部缓存中的可能性....
  • 基本上我同意 Albert 的观点——没有一个最小但完整的例子,除了看起来像模板应用外,很难说很多,所以我会尽量减少网格上每个点的工作尽可能在内循环之外进行计算,尤其是 sqrts。但是哎呀,这段代码伤害了我的眼睛!我要做的第一件事就是把它分解成一些更简单的陈述,而不是一个巨大的、单一的、令人困惑的东西。
  • @veryreverie 我不是浮点计算方面的专家,但是当假设 sqrt 的项很小时,可能会发生 a*b 小于适合浮点的项number 并且给出 0 是 NaN 或 .. 所以 sqrt 也给出了一个数字。首先计算 sqrt(a)*sqrt(b) 并将给出“合理”的数字,以及 sqrt 的乘积。另请注意,最好使用(也可能在原始版本中)绝对值,或者保证 a 和 b 为正。所有这些可能都超出了这里的范围。

标签: performance optimization memory-management fortran


【解决方案1】:

在 cmets 中,您说您想要一个“概念”的答案,即预计算何时比不预计算更快。

不幸的是,出于几个原因,对两种方法中的哪一种更好进行静态分析通常很困难。首先,优化编译器非常聪明,并且在幕后做了很多相当不可预测的事情。其次,外部变量很多,编译器、cpu、内存等细节都会改变结果。

“这两种算法中哪一种更快”这个问题的答案通常是“都试试看”。您至少应该为您的代码计时,但使用分析工具是理想的。分析工具不仅会告诉您不同方法需要多长时间,它还将有助于缩小两种方法中花费最多时间的部分。这让您知道应该优化代码的哪些部分以获得最佳结果。

【讨论】:

  • 不仅编译器复杂而聪明,而且现代CPU具有乱序执行来隐藏缓存未命中和计算的延迟。并且具有硬件预取的多级 CPU 缓存也很复杂。因此,理想情况下,您应该在几种不同类型的 CPU 上进行测试,尤其是在结果接近的情况下。
猜你喜欢
  • 1970-01-01
  • 2015-05-27
  • 2012-11-29
  • 1970-01-01
  • 2010-12-16
  • 2023-03-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多